1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include "excimp8.hxx"
24 #include <boost/bind.hpp>
26 #include <scitems.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <unotools/fltrcfg.hxx>
30 #include <vcl/wmf.hxx>
32 #include <editeng/eeitem.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <sfx2/objsh.hxx>
36 #include <sfx2/request.hxx>
37 #include <sfx2/app.hxx>
38 #include <sfx2/docinf.hxx>
39 #include <sfx2/frame.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/editdata.hxx>
43 #include <editeng/editeng.hxx>
44 #include <editeng/editobj.hxx>
45 #include <editeng/editstat.hxx>
46 #include <editeng/colritem.hxx>
47 #include <editeng/udlnitem.hxx>
48 #include <editeng/wghtitem.hxx>
49 #include <editeng/postitem.hxx>
50 #include <editeng/crossedoutitem.hxx>
51 #include <editeng/flditem.hxx>
52 #include <svx/xflclit.hxx>
54 #include <vcl/graph.hxx>
55 #include <vcl/bmpacc.hxx>
56 #include <sot/exchange.hxx>
58 #include <svl/stritem.hxx>
59 #include <svl/sharedstringpool.hxx>
61 #include <rtl/math.hxx>
62 #include <rtl/ustring.hxx>
63 #include <unotools/localedatawrapper.hxx>
64 #include <unotools/charclass.hxx>
65 #include <drwlayer.hxx>
67 #include <boost/scoped_array.hpp>
69 #include "formulacell.hxx"
70 #include "document.hxx"
71 #include "patattr.hxx"
72 #include "docpool.hxx"
74 #include "conditio.hxx"
76 #include "globalnames.hxx"
77 #include "editutil.hxx"
78 #include "markdata.hxx"
79 #include "rangenam.hxx"
80 #include "docoptio.hxx"
81 #include "globstr.hrc"
82 #include "fprogressbar.hxx"
83 #include "xltracer.hxx"
84 #include "xihelper.hxx"
86 #include "xicontent.hxx"
88 #include "xiescher.hxx"
89 #include "xipivot.hxx"
91 #include "excform.hxx"
92 #include "scextopt.hxx"
93 #include "stlpool.hxx"
94 #include "stlsheet.hxx"
95 #include "detfunc.hxx"
96 #include "macromgr.hxx"
97 #include "queryentry.hxx"
99 #include <com/sun/star/document/XDocumentProperties.hpp>
100 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
101 #include <com/sun/star/script/ModuleInfo.hpp>
102 #include <com/sun/star/container/XIndexContainer.hpp>
103 #include <cppuhelper/component_context.hxx>
104 #include "xltoolbar.hxx"
105 #include <oox/ole/vbaproject.hxx>
106 #include <oox/ole/olestorage.hxx>
107 #include <unotools/streamwrap.hxx>
109 using namespace com::sun::star
;
110 using namespace ::comphelper
;
112 //OleNameOverrideContainer
114 typedef ::cppu::WeakImplHelper1
< container::XNameContainer
> OleNameOverrideContainer_BASE
;
116 class OleNameOverrideContainer
: public OleNameOverrideContainer_BASE
119 typedef std::unordered_map
< OUString
, uno::Reference
< container::XIndexContainer
>, OUStringHash
,
120 std::equal_to
< OUString
> > NamedIndexToOleName
;
121 NamedIndexToOleName IdToOleNameHash
;
122 ::osl::Mutex m_aMutex
;
125 virtual uno::Type SAL_CALL
getElementType( ) throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
{ return cppu::UnoType
<container::XIndexContainer
>::get(); }
126 virtual sal_Bool SAL_CALL
hasElements( ) throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
128 ::osl::MutexGuard
aGuard( m_aMutex
);
129 return ( !IdToOleNameHash
.empty() );
132 virtual uno::Any SAL_CALL
getByName( const OUString
& aName
) throw (container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
) SAL_OVERRIDE
134 ::osl::MutexGuard
aGuard( m_aMutex
);
135 if ( !hasByName(aName
) )
136 throw container::NoSuchElementException();
137 return uno::makeAny( IdToOleNameHash
[ aName
] );
139 virtual uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
141 ::osl::MutexGuard
aGuard( m_aMutex
);
142 uno::Sequence
< OUString
> aResult( IdToOleNameHash
.size() );
143 NamedIndexToOleName::iterator it
= IdToOleNameHash
.begin();
144 NamedIndexToOleName::iterator it_end
= IdToOleNameHash
.end();
145 OUString
* pName
= aResult
.getArray();
146 for (; it
!= it_end
; ++it
, ++pName
)
150 virtual sal_Bool SAL_CALL
hasByName( const OUString
& aName
) throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
152 ::osl::MutexGuard
aGuard( m_aMutex
);
153 return ( IdToOleNameHash
.find( aName
) != IdToOleNameHash
.end() );
157 virtual void SAL_CALL
insertByName( const OUString
& aName
, const uno::Any
& aElement
) throw(lang::IllegalArgumentException
, container::ElementExistException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
) SAL_OVERRIDE
159 ::osl::MutexGuard
aGuard( m_aMutex
);
160 if ( hasByName( aName
) )
161 throw container::ElementExistException();
162 uno::Reference
< container::XIndexContainer
> xElement
;
163 if ( ! ( aElement
>>= xElement
) )
164 throw lang::IllegalArgumentException();
165 IdToOleNameHash
[ aName
] = xElement
;
167 virtual void SAL_CALL
removeByName( const OUString
& aName
) throw(container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
) SAL_OVERRIDE
169 ::osl::MutexGuard
aGuard( m_aMutex
);
170 if ( !hasByName( aName
) )
171 throw container::NoSuchElementException();
172 IdToOleNameHash
.erase( IdToOleNameHash
.find( aName
) );
174 virtual void SAL_CALL
replaceByName( const OUString
& aName
, const uno::Any
& aElement
) throw(lang::IllegalArgumentException
, container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
) SAL_OVERRIDE
176 ::osl::MutexGuard
aGuard( m_aMutex
);
177 if ( !hasByName( aName
) )
178 throw container::NoSuchElementException();
179 uno::Reference
< container::XIndexContainer
> xElement
;
180 if ( ! ( aElement
>>= xElement
) )
181 throw lang::IllegalArgumentException();
182 IdToOleNameHash
[ aName
] = xElement
;
188 /** Future Record Type header.
189 @return whether read rt matches nRecordID
191 bool readFrtHeader( XclImpStream
& rStrm
, sal_uInt16 nRecordID
)
193 sal_uInt16 nRt
= rStrm
.ReaduInt16();
194 rStrm
.Ignore(10); // grbitFrt (2 bytes) and reserved (8 bytes)
195 return nRt
== nRecordID
;
200 ImportExcel8::ImportExcel8( XclImpRootData
& rImpData
, SvStream
& rStrm
) :
201 ImportExcel( rImpData
, rStrm
)
203 // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
205 pFormConv
= pExcRoot
->pFmlaConverter
= new ExcelToSc8( GetRoot() );
208 ImportExcel8::~ImportExcel8()
212 void ImportExcel8::Calccount()
214 ScDocOptions aOpt
= pD
->GetDocOptions();
215 aOpt
.SetIterCount( aIn
.ReaduInt16() );
216 pD
->SetDocOptions( aOpt
);
219 void ImportExcel8::Precision()
221 ScDocOptions aOpt
= pD
->GetDocOptions();
222 aOpt
.SetCalcAsShown( aIn
.ReaduInt16() == 0 );
223 pD
->SetDocOptions( aOpt
);
226 void ImportExcel8::Delta()
228 ScDocOptions aOpt
= pD
->GetDocOptions();
229 aOpt
.SetIterEps( aIn
.ReadDouble() );
230 pD
->SetDocOptions( aOpt
);
233 void ImportExcel8::Iteration()
235 ScDocOptions aOpt
= pD
->GetDocOptions();
236 aOpt
.SetIter( aIn
.ReaduInt16() == 1 );
237 pD
->SetDocOptions( aOpt
);
240 void ImportExcel8::Boundsheet()
245 aIn
.DisableDecryption();
246 maSheetOffsets
.push_back( aIn
.ReaduInt32() );
247 aIn
.EnableDecryption();
248 nGrbit
= aIn
.ReaduInt16();
249 nLen
= aIn
.ReaduInt8();
251 OUString
aName( aIn
.ReadUniString( nLen
) );
252 GetTabInfo().AppendXclTabName( aName
, nBdshtTab
);
254 SCTAB nScTab
= static_cast< SCTAB
>( nBdshtTab
);
257 OSL_ENSURE( !pD
->HasTable( nScTab
), "ImportExcel8::Boundsheet - sheet exists already" );
258 pD
->MakeTable( nScTab
);
261 if( ( nGrbit
& 0x0001 ) || ( nGrbit
& 0x0002 ) )
262 pD
->SetVisible( nScTab
, false );
264 if( !pD
->RenameTab( nScTab
, aName
) )
266 pD
->CreateValidTabName( aName
);
267 pD
->RenameTab( nScTab
, aName
);
273 void ImportExcel8::Scenman()
275 sal_uInt16 nLastDispl
;
278 nLastDispl
= aIn
.ReaduInt16();
280 maScenList
.nLastScenario
= nLastDispl
;
283 void ImportExcel8::Scenario()
285 maScenList
.aEntries
.push_back( new ExcScenario( aIn
, *pExcRoot
) );
288 void ImportExcel8::Labelsst()
295 nXF
= aIn
.ReaduInt16();
296 nSst
= aIn
.ReaduInt32( );
298 ScAddress
aScPos( ScAddress::UNINITIALIZED
);
299 if( GetAddressConverter().ConvertAddress( aScPos
, aXclPos
, GetCurrScTab(), true ) )
301 GetXFRangeBuffer().SetXF( aScPos
, nXF
);
302 const XclImpString
* pXclStr
= GetSst().GetString(nSst
);
304 XclImpStringHelper::SetToDocument(GetDocImport(), aScPos
, *this, *pXclStr
, nXF
);
308 void ImportExcel8::FeatHdr()
310 if (!readFrtHeader( aIn
, 0x0867))
313 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
315 sal_uInt16 nFeatureType
= aIn
.ReaduInt16();
316 if (nFeatureType
!= EXC_ISFPROTECTION
)
317 // We currently only support import of enhanced protection data.
320 aIn
.Ignore(1); // always 1
322 GetSheetProtectBuffer().ReadOptions( aIn
, GetCurrScTab() );
325 void ImportExcel8::Feat()
327 if (!readFrtHeader( aIn
, 0x0868))
330 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
332 sal_uInt16 nFeatureType
= aIn
.ReaduInt16();
333 if (nFeatureType
!= EXC_ISFPROTECTION
)
334 // We currently only support import of enhanced protection data.
337 aIn
.Ignore(5); // reserved1 (1 byte) and reserved2 (4 bytes)
339 sal_uInt16 nCref
= aIn
.ReaduInt16(); // number of ref elements
340 aIn
.Ignore(4); // size if EXC_ISFFEC2, else 0 and to be ignored
341 aIn
.Ignore(2); // reserved3 (2 bytes)
343 ScEnhancedProtection aProt
;
347 aRefs
.Read( aIn
, true, nCref
);
350 aProt
.maRangeList
= new ScRangeList
;
351 GetAddressConverter().ConvertRangeList( *aProt
.maRangeList
, aRefs
, GetCurrScTab(), false);
355 // FeatProtection structure follows in record.
357 aProt
.mnAreserved
= aIn
.ReaduInt32();
358 aProt
.mnPasswordVerifier
= aIn
.ReaduInt32();
359 aProt
.maTitle
= aIn
.ReadUniString();
360 if ((aProt
.mnAreserved
& 0x00000001) == 0x00000001)
362 sal_uInt32 nCbSD
= aIn
.ReaduInt32();
363 // TODO: could here be some sanity check applied to not allocate 4GB?
364 aProt
.maSecurityDescriptor
.resize( nCbSD
);
365 sal_Size nRead
= aIn
.Read( &aProt
.maSecurityDescriptor
.front(), nCbSD
);
367 aProt
.maSecurityDescriptor
.resize( nRead
);
370 GetSheetProtectBuffer().AppendEnhancedProtection( aProt
, GetCurrScTab() );
373 void ImportExcel8::ReadBasic()
375 SfxObjectShell
* pShell
= GetDocShell();
376 tools::SvRef
<SotStorage
> xRootStrg
= GetRootStorage();
377 const SvtFilterOptions
& rFilterOpt
= SvtFilterOptions::Get();
378 if( pShell
&& xRootStrg
.Is() ) try
380 // #FIXME need to get rid of this, we can also do this from within oox
381 // via the "ooo.vba.VBAGlobals" service
382 if( ( rFilterOpt
.IsLoadExcelBasicCode() ||
383 rFilterOpt
.IsLoadExcelBasicStorage() ) &&
384 rFilterOpt
.IsLoadExcelBasicExecutable() )
386 // see if we have the XCB stream
387 tools::SvRef
<SotStorageStream
> xXCB
= xRootStrg
->OpenSotStream( OUString("XCB"), STREAM_STD_READ
| StreamMode::NOCREATE
);
388 if ( xXCB
.Is()|| SVSTREAM_OK
== xXCB
->GetError() )
390 ScCTBWrapper wrapper
;
391 if ( wrapper
.Read( *xXCB
) )
393 #if OSL_DEBUG_LEVEL > 1
394 wrapper
.Print( stderr
);
396 wrapper
.ImportCustomToolBar( *pShell
);
402 uno::Reference
< uno::XComponentContext
> aCtx( ::comphelper::getProcessComponentContext() );
403 SfxMedium
& rMedium
= GetMedium();
404 uno::Reference
< io::XInputStream
> xIn
= rMedium
.GetInputStream();
405 oox::ole::OleStorage
root( aCtx
, xIn
, false );
406 oox::StorageRef vbaStg
= root
.openSubStorage( "_VBA_PROJECT_CUR", false );
409 oox::ole::VbaProject
aVbaPrj( aCtx
, pShell
->GetModel(), "Calc" );
410 // collect names of embedded form controls, as specified in the VBA project
411 uno::Reference
< container::XNameContainer
> xOleNameOverrideSink( new OleNameOverrideContainer
);
412 aVbaPrj
.setOleOverridesSink( xOleNameOverrideSink
);
413 aVbaPrj
.importVbaProject( *vbaStg
);
414 GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink
);
417 catch( uno::Exception
& )
421 catch( uno::Exception
& )
426 void ImportExcel8::EndSheet()
428 ImportExcel::EndSheet();
429 GetCondFormatManager().Apply();
430 GetValidationManager().Apply();
433 void ImportExcel8::PostDocLoad()
435 #if HAVE_FEATURE_SCRIPTING
436 // reading basic has been delayed until sheet objects (codenames etc.) are read
440 // #i11776# filtered ranges before outlines and hidden rows
441 if( pExcRoot
->pAutoFilterBuffer
)
442 pExcRoot
->pAutoFilterBuffer
->Apply();
444 GetWebQueryBuffer().Apply(); //TODO: test if extant
445 GetSheetProtectBuffer().Apply();
446 GetDocProtectBuffer().Apply();
448 ImportExcel::PostDocLoad();
450 // check scenarios; Attention: This increases the table count of the document!!
451 if( !pD
->IsClipboard() && maScenList
.aEntries
.size() )
453 pD
->UpdateChartListenerCollection(); // references in charts must be updated
455 maScenList
.Apply( GetRoot() );
458 // read doc info (no docshell while pasting from clipboard)
459 LoadDocumentProperties();
461 // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
462 // when formula cells are calculated, for the GETPIVOTDATA function.
465 void ImportExcel8::LoadDocumentProperties()
467 // no docshell while pasting from clipboard
468 if( SfxObjectShell
* pShell
= GetDocShell() )
470 // BIFF5+ without storage is possible
471 tools::SvRef
<SotStorage
> xRootStrg
= GetRootStorage();
472 if( xRootStrg
.Is() ) try
474 uno::Reference
< document::XDocumentPropertiesSupplier
> xDPS( pShell
->GetModel(), uno::UNO_QUERY_THROW
);
475 uno::Reference
< document::XDocumentProperties
> xDocProps( xDPS
->getDocumentProperties(), uno::UNO_SET_THROW
);
476 sfx2::LoadOlePropertySet( xDocProps
, xRootStrg
);
478 catch( uno::Exception
& )
486 void ImportExcel8::FilterMode()
488 // The FilterMode record exists: if either the AutoFilter
489 // record exists or an Advanced Filter is saved and stored
490 // in the sheet. Thus if the FilterMode records only exists
491 // then the latter is true..
492 if( !pExcRoot
->pAutoFilterBuffer
) return;
494 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
496 pData
->SetAutoOrAdvanced();
499 void ImportExcel8::AutoFilterInfo()
501 if( !pExcRoot
->pAutoFilterBuffer
) return;
503 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
506 pData
->SetAdvancedRange( NULL
);
511 void ImportExcel8::AutoFilter()
513 if( !pExcRoot
->pAutoFilterBuffer
) return;
515 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
517 pData
->ReadAutoFilter(aIn
, GetDoc().GetSharedStringPool());
520 XclImpAutoFilterData::XclImpAutoFilterData( RootData
* pRoot
, const ScRange
& rRange
) :
525 bAutoOrAdvanced(false)
527 aParam
.nCol1
= rRange
.aStart
.Col();
528 aParam
.nRow1
= rRange
.aStart
.Row();
529 aParam
.nTab
= rRange
.aStart
.Tab();
530 aParam
.nCol2
= rRange
.aEnd
.Col();
531 aParam
.nRow2
= rRange
.aEnd
.Row();
533 aParam
.bInplace
= true;
539 OUString
CreateFromDouble( double fVal
)
541 return rtl::math::doubleToUString(fVal
,
542 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
543 ScGlobal::pLocaleData
->getNumDecimalSep()[0], true);
548 void XclImpAutoFilterData::SetCellAttribs()
550 ScDocument
& rDoc
= pExcRoot
->pIR
->GetDoc();
551 for ( SCCOL nCol
= StartCol(); nCol
<= EndCol(); nCol
++ )
553 sal_Int16 nFlag
= static_cast<const ScMergeFlagAttr
*>( rDoc
.GetAttr( nCol
, StartRow(), Tab(), ATTR_MERGE_FLAG
))->GetValue();
554 rDoc
.ApplyAttr( nCol
, StartRow(), Tab(), ScMergeFlagAttr( nFlag
| SC_MF_AUTO
) );
558 void XclImpAutoFilterData::InsertQueryParam()
563 bool bHasAdv
= pCurrDBData
->GetAdvancedQuerySource( aAdvRange
);
565 pExcRoot
->pIR
->GetDoc().CreateQueryParam( aAdvRange
.aStart
.Col(),
566 aAdvRange
.aStart
.Row(), aAdvRange
.aEnd
.Col(), aAdvRange
.aEnd
.Row(),
567 aAdvRange
.aStart
.Tab(), aParam
);
569 pCurrDBData
->SetQueryParam( aParam
);
571 pCurrDBData
->SetAdvancedQuerySource( &aAdvRange
);
574 pCurrDBData
->SetAutoFilter( true );
580 static void ExcelQueryToOooQuery( OUString
& aStr
, ScQueryEntry
& rEntry
)
582 if (rEntry
.eOp
!= SC_EQUAL
&& rEntry
.eOp
!= SC_NOT_EQUAL
)
585 sal_Int32 nLen
= aStr
.getLength();
586 sal_Unicode nStart
= aStr
[0];
587 sal_Unicode nEnd
= aStr
[ nLen
-1 ];
588 if( nLen
> 2 && nStart
== '*' && nEnd
== '*' )
590 aStr
= aStr
.copy( 1, nLen
-2 );
591 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_CONTAINS
: SC_DOES_NOT_CONTAIN
;
593 else if( nLen
> 1 && nStart
== '*' && nEnd
!= '*' )
595 aStr
= aStr
.copy( 1 );
596 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_ENDS_WITH
: SC_DOES_NOT_END_WITH
;
598 else if( nLen
> 1 && nStart
!= '*' && nEnd
== '*' )
600 aStr
= aStr
.copy( 0, nLen
-1 );
601 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_BEGINS_WITH
: SC_DOES_NOT_BEGIN_WITH
;
603 else if( nLen
== 2 && nStart
== '*' && nEnd
== '*' )
605 aStr
= aStr
.copy( 1 );
609 void XclImpAutoFilterData::ReadAutoFilter(
610 XclImpStream
& rStrm
, svl::SharedStringPool
& rPool
)
612 sal_uInt16 nCol
, nFlags
;
613 nCol
= rStrm
.ReaduInt16();
614 nFlags
= rStrm
.ReaduInt16();
616 ScQueryConnect eConn
= ::get_flagvalue( nFlags
, EXC_AFFLAG_ANDORMASK
, SC_OR
, SC_AND
);
617 bool bSimple1
= ::get_flag(nFlags
, EXC_AFFLAG_SIMPLE1
);
618 bool bSimple2
= ::get_flag(nFlags
, EXC_AFFLAG_SIMPLE2
);
619 bool bTop10
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10
);
620 bool bTopOfTop10
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10TOP
);
621 bool bPercent
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10PERC
);
622 sal_uInt16 nCntOfTop10
= nFlags
>> 7;
626 ScQueryEntry
& aEntry
= aParam
.AppendEntry();
627 ScQueryEntry::Item
& rItem
= aEntry
.GetQueryItem();
628 aEntry
.bDoQuery
= true;
629 aEntry
.nField
= static_cast<SCCOLROW
>(StartCol() + static_cast<SCCOL
>(nCol
));
630 aEntry
.eOp
= bTopOfTop10
?
631 (bPercent
? SC_TOPPERC
: SC_TOPVAL
) : (bPercent
? SC_BOTPERC
: SC_BOTVAL
);
632 aEntry
.eConnect
= SC_AND
;
634 rItem
.meType
= ScQueryEntry::ByString
;
635 rItem
.maString
= rPool
.intern(OUString::number(nCntOfTop10
));
641 sal_uInt8 nType
, nOper
, nBoolErr
, nVal
;
646 sal_uInt8 nStrLen
[2] = { 0, 0 };
647 ScQueryEntry aEntries
[2];
649 for (size_t nE
= 0; nE
< 2; ++nE
)
651 ScQueryEntry
& rEntry
= aEntries
[nE
];
652 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
655 nType
= rStrm
.ReaduInt8();
656 nOper
= rStrm
.ReaduInt8();
659 case EXC_AFOPER_LESS
:
660 rEntry
.eOp
= SC_LESS
;
662 case EXC_AFOPER_EQUAL
:
663 rEntry
.eOp
= SC_EQUAL
;
665 case EXC_AFOPER_LESSEQUAL
:
666 rEntry
.eOp
= SC_LESS_EQUAL
;
668 case EXC_AFOPER_GREATER
:
669 rEntry
.eOp
= SC_GREATER
;
671 case EXC_AFOPER_NOTEQUAL
:
672 rEntry
.eOp
= SC_NOT_EQUAL
;
674 case EXC_AFOPER_GREATEREQUAL
:
675 rEntry
.eOp
= SC_GREATER_EQUAL
;
678 rEntry
.eOp
= SC_EQUAL
;
684 nRK
= rStrm
.ReadInt32();
686 rItem
.maString
= rPool
.intern(
687 CreateFromDouble(XclTools::GetDoubleFromRK(nRK
)));
689 case EXC_AFTYPE_DOUBLE
:
690 fVal
= rStrm
.ReadDouble();
691 rItem
.maString
= rPool
.intern(CreateFromDouble(fVal
));
693 case EXC_AFTYPE_STRING
:
695 nStrLen
[ nE
] = rStrm
.ReaduInt8();
697 rItem
.maString
= svl::SharedString();
699 case EXC_AFTYPE_BOOLERR
:
700 nBoolErr
= rStrm
.ReaduInt8();
701 nVal
= rStrm
.ReaduInt8();
703 rItem
.maString
= rPool
.intern(OUString::number(nVal
));
704 bIgnore
= (nBoolErr
!= 0);
706 case EXC_AFTYPE_EMPTY
:
707 rEntry
.SetQueryByEmpty();
709 case EXC_AFTYPE_NOTEMPTY
:
710 rEntry
.SetQueryByNonEmpty();
719 rEntry
.bDoQuery
= true;
720 rItem
.meType
= ScQueryEntry::ByString
;
721 rEntry
.nField
= static_cast<SCCOLROW
>(StartCol() + static_cast<SCCOL
>(nCol
));
722 rEntry
.eConnect
= nE
? eConn
: SC_AND
;
728 for (size_t nE
= 0; nE
< 2; ++nE
)
730 if (nStrLen
[nE
] && aEntries
[nE
].bDoQuery
)
732 OUString aStr
= rStrm
.ReadUniString(nStrLen
[nE
]);
733 ExcelQueryToOooQuery(aStr
, aEntries
[nE
]);
734 aEntries
[nE
].GetQueryItem().maString
= rPool
.intern(aStr
);
735 aParam
.AppendEntry() = aEntries
[nE
];
741 OSL_ASSERT(eConn
== SC_OR
);
742 // Import only when both conditions are for simple equality, else
743 // import only the 1st condition due to conflict with the ordering of
744 // conditions. #i39464#.
746 // Example: Let A1 be a condition of column A, and B1 and B2
747 // conditions of column B, connected with OR. Excel performs 'A1 AND
748 // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
751 if (bSimple1
&& bSimple2
&& nStrLen
[0] && nStrLen
[1])
753 // Two simple OR'ed equal conditions. We can import this correctly.
754 ScQueryEntry
& rEntry
= aParam
.AppendEntry();
755 rEntry
.bDoQuery
= true;
756 rEntry
.eOp
= SC_EQUAL
;
757 rEntry
.eConnect
= SC_AND
;
758 ScQueryEntry::QueryItemsType aItems
;
760 ScQueryEntry::Item aItem1
, aItem2
;
761 aItem1
.maString
= rPool
.intern(rStrm
.ReadUniString(nStrLen
[0]));
762 aItem1
.meType
= ScQueryEntry::ByString
;
763 aItem2
.maString
= rPool
.intern(rStrm
.ReadUniString(nStrLen
[1]));
764 aItem2
.meType
= ScQueryEntry::ByString
;
765 aItems
.push_back(aItem1
);
766 aItems
.push_back(aItem2
);
767 rEntry
.GetQueryItems().swap(aItems
);
769 else if (nStrLen
[0] && aEntries
[0].bDoQuery
)
771 // Due to conflict, we can import only the first condition.
772 OUString aStr
= rStrm
.ReadUniString(nStrLen
[0]);
773 ExcelQueryToOooQuery(aStr
, aEntries
[0]);
774 aEntries
[0].GetQueryItem().maString
= rPool
.intern(aStr
);
775 aParam
.AppendEntry() = aEntries
[0];
780 void XclImpAutoFilterData::SetAdvancedRange( const ScRange
* pRange
)
784 aCriteriaRange
= *pRange
;
791 void XclImpAutoFilterData::SetExtractPos( const ScAddress
& rAddr
)
793 aParam
.nDestCol
= rAddr
.Col();
794 aParam
.nDestRow
= rAddr
.Row();
795 aParam
.nDestTab
= rAddr
.Tab();
796 aParam
.bInplace
= false;
797 aParam
.bDestPers
= true;
800 void XclImpAutoFilterData::Apply()
810 void XclImpAutoFilterData::CreateScDBData()
813 // Create the ScDBData() object if the AutoFilter is activated
814 // or if we need to create the Advanced Filter.
815 if( bActive
|| bCriteria
)
817 ScDocument
* pDoc
= pExcRoot
->pIR
->GetDocPtr();
818 OUString
aNewName(STR_DB_LOCAL_NONAME
);
819 pCurrDBData
= new ScDBData(aNewName
, Tab(),
820 StartCol(),StartRow(), EndCol(),EndRow() );
823 EnableRemoveFilter();
825 pCurrDBData
->SetQueryParam( aParam
);
826 pCurrDBData
->SetAdvancedQuerySource(&aCriteriaRange
);
829 pCurrDBData
->SetAdvancedQuerySource(NULL
);
830 pDoc
->SetAnonymousDBData(Tab(), pCurrDBData
);
835 void XclImpAutoFilterData::EnableRemoveFilter()
837 // only if this is a saved Advanced filter
838 if( !bActive
&& bAutoOrAdvanced
)
840 ScQueryEntry
& aEntry
= aParam
.AppendEntry();
841 aEntry
.bDoQuery
= true;
844 // TBD: force the automatic activation of the
845 // "Remove Filter" by setting a virtual mouse click
846 // inside the advanced range
849 void XclImpAutoFilterBuffer::Insert( RootData
* pRoot
, const ScRange
& rRange
)
851 if( !GetByTab( rRange
.aStart
.Tab() ) )
852 maFilters
.push_back( new XclImpAutoFilterData( pRoot
, rRange
) );
855 void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange
& rRange
)
857 XclImpAutoFilterData
* pData
= GetByTab( rRange
.aStart
.Tab() );
859 pData
->SetAdvancedRange( &rRange
);
862 void XclImpAutoFilterBuffer::AddExtractPos( const ScRange
& rRange
)
864 XclImpAutoFilterData
* pData
= GetByTab( rRange
.aStart
.Tab() );
866 pData
->SetExtractPos( rRange
.aStart
);
869 void XclImpAutoFilterBuffer::Apply()
871 std::for_each(maFilters
.begin(),maFilters
.end(),
872 boost::bind(&XclImpAutoFilterData::Apply
,_1
));
875 XclImpAutoFilterData
* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab
)
877 boost::ptr_vector
<XclImpAutoFilterData
>::iterator it
;
878 for( it
= maFilters
.begin(); it
!= maFilters
.end(); ++it
)
880 if( it
->Tab() == nTab
)
881 return const_cast<XclImpAutoFilterData
*>(&(*it
));
886 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */