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 <scitems.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/sequence.hxx>
27 #include <officecfg/Office/Calc.hxx>
29 #include <sfx2/docfile.hxx>
30 #include <sfx2/objsh.hxx>
31 #include <sfx2/docinf.hxx>
32 #include <sot/storage.hxx>
33 #include <svl/sharedstringpool.hxx>
35 #include <rtl/math.hxx>
36 #include <rtl/ustring.hxx>
37 #include <unotools/localedatawrapper.hxx>
39 #include <document.hxx>
43 #include <globalnames.hxx>
44 #include <docoptio.hxx>
45 #include <xihelper.hxx>
46 #include <xicontent.hxx>
48 #include <xiescher.hxx>
49 #include <xistyle.hxx>
50 #include <excdefs.hxx>
52 #include <excform.hxx>
53 #include <queryentry.hxx>
55 #include <com/sun/star/document/XDocumentProperties.hpp>
56 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
57 #include <com/sun/star/container/XIndexContainer.hpp>
58 #include <com/sun/star/container/XNameContainer.hpp>
59 #include <com/sun/star/frame/XModel.hpp>
60 #include <cppuhelper/implbase.hxx>
61 #include "xltoolbar.hxx"
62 #include <oox/ole/vbaproject.hxx>
63 #include <oox/ole/olestorage.hxx>
65 using namespace com::sun::star
;
66 using namespace ::comphelper
;
68 //OleNameOverrideContainer
72 class OleNameOverrideContainer
: public ::cppu::WeakImplHelper
< container::XNameContainer
>
75 typedef std::unordered_map
< OUString
, uno::Reference
< container::XIndexContainer
> > NamedIndexToOleName
;
76 NamedIndexToOleName IdToOleNameHash
;
80 virtual uno::Type SAL_CALL
getElementType( ) override
{ return cppu::UnoType
<container::XIndexContainer
>::get(); }
81 virtual sal_Bool SAL_CALL
hasElements( ) override
83 std::unique_lock
aGuard( m_aMutex
);
84 return ( !IdToOleNameHash
.empty() );
87 virtual uno::Any SAL_CALL
getByName( const OUString
& aName
) override
89 std::unique_lock
aGuard( m_aMutex
);
90 auto it
= IdToOleNameHash
.find( aName
);
91 if ( it
== IdToOleNameHash
.end() )
92 throw container::NoSuchElementException();
93 return uno::Any( it
->second
);
95 virtual uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) override
97 std::unique_lock
aGuard( m_aMutex
);
98 return comphelper::mapKeysToSequence( IdToOleNameHash
);
100 virtual sal_Bool SAL_CALL
hasByName( const OUString
& aName
) override
102 std::unique_lock
aGuard( m_aMutex
);
103 return ( IdToOleNameHash
.find( aName
) != IdToOleNameHash
.end() );
107 virtual void SAL_CALL
insertByName( const OUString
& aName
, const uno::Any
& aElement
) override
109 std::unique_lock
aGuard( m_aMutex
);
110 auto it
= IdToOleNameHash
.find( aName
);
111 if ( it
!= IdToOleNameHash
.end() )
112 throw container::ElementExistException();
113 uno::Reference
< container::XIndexContainer
> xElement
;
114 if ( ! ( aElement
>>= xElement
) )
115 throw lang::IllegalArgumentException();
116 IdToOleNameHash
[ aName
] = std::move(xElement
);
118 virtual void SAL_CALL
removeByName( const OUString
& aName
) override
120 std::unique_lock
aGuard( m_aMutex
);
121 if ( IdToOleNameHash
.erase( aName
) == 0 )
122 throw container::NoSuchElementException();
124 virtual void SAL_CALL
replaceByName( const OUString
& aName
, const uno::Any
& aElement
) override
126 std::unique_lock
aGuard( m_aMutex
);
127 auto it
= IdToOleNameHash
.find( aName
);
128 if ( it
== IdToOleNameHash
.end() )
129 throw container::NoSuchElementException();
130 uno::Reference
< container::XIndexContainer
> xElement
;
131 if ( ! ( aElement
>>= xElement
) )
132 throw lang::IllegalArgumentException();
133 it
->second
= std::move(xElement
);
137 /** Future Record Type header.
138 @return whether read rt matches nRecordID
140 bool readFrtHeader( XclImpStream
& rStrm
, sal_uInt16 nRecordID
)
142 sal_uInt16 nRt
= rStrm
.ReaduInt16();
143 rStrm
.Ignore(10); // grbitFrt (2 bytes) and reserved (8 bytes)
144 return nRt
== nRecordID
;
149 ImportExcel8::ImportExcel8( XclImpRootData
& rImpData
, SvStream
& rStrm
) :
150 ImportExcel( rImpData
, rStrm
)
152 // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
153 pFormConv
.reset(new ExcelToSc8( GetRoot() ));
154 pExcRoot
->pFmlaConverter
= pFormConv
.get();
157 ImportExcel8::~ImportExcel8()
161 void ImportExcel8::Calccount()
163 ScDocOptions aOpt
= rD
.GetDocOptions();
164 aOpt
.SetIterCount( aIn
.ReaduInt16() );
165 rD
.SetDocOptions( aOpt
);
168 void ImportExcel8::Precision()
170 ScDocOptions aOpt
= rD
.GetDocOptions();
171 aOpt
.SetCalcAsShown( aIn
.ReaduInt16() == 0 );
172 rD
.SetDocOptions( aOpt
);
175 void ImportExcel8::Delta()
177 ScDocOptions aOpt
= rD
.GetDocOptions();
178 aOpt
.SetIterEps( aIn
.ReadDouble() );
179 rD
.SetDocOptions( aOpt
);
182 void ImportExcel8::Iteration()
184 ScDocOptions aOpt
= rD
.GetDocOptions();
185 aOpt
.SetIter( aIn
.ReaduInt16() == 1 );
186 rD
.SetDocOptions( aOpt
);
189 void ImportExcel8::Boundsheet()
194 aIn
.DisableDecryption();
195 maSheetOffsets
.push_back( aIn
.ReaduInt32() );
196 aIn
.EnableDecryption();
197 nGrbit
= aIn
.ReaduInt16();
198 nLen
= aIn
.ReaduInt8();
200 OUString
aName( aIn
.ReadUniString( nLen
) );
201 GetTabInfo().AppendXclTabName( aName
, nBdshtTab
);
203 SCTAB nScTab
= nBdshtTab
;
206 OSL_ENSURE( !rD
.HasTable( nScTab
), "ImportExcel8::Boundsheet - sheet exists already" );
207 rD
.MakeTable( nScTab
);
210 if( ( nGrbit
& 0x0001 ) || ( nGrbit
& 0x0002 ) )
211 rD
.SetVisible( nScTab
, false );
213 if( !rD
.RenameTab( nScTab
, aName
) )
215 rD
.CreateValidTabName( aName
);
216 rD
.RenameTab( nScTab
, aName
);
222 void ImportExcel8::Scenman()
224 sal_uInt16 nLastDispl
;
227 nLastDispl
= aIn
.ReaduInt16();
229 maScenList
.nLastScenario
= nLastDispl
;
232 void ImportExcel8::Scenario()
234 maScenList
.aEntries
.push_back( std::make_unique
<ExcScenario
>( aIn
, *pExcRoot
) );
237 void ImportExcel8::Labelsst()
244 nXF
= aIn
.ReaduInt16();
245 nSst
= aIn
.ReaduInt32( );
247 ScAddress
aScPos( ScAddress::UNINITIALIZED
);
248 if( GetAddressConverter().ConvertAddress( aScPos
, aXclPos
, GetCurrScTab(), true ) )
250 GetXFRangeBuffer().SetXF( aScPos
, nXF
);
251 const XclImpString
* pXclStr
= GetSst().GetString(nSst
);
253 XclImpStringHelper::SetToDocument(GetDocImport(), aScPos
, *this, *pXclStr
, nXF
);
257 void ImportExcel8::FeatHdr()
259 if (!readFrtHeader( aIn
, 0x0867))
262 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
264 sal_uInt16 nFeatureType
= aIn
.ReaduInt16();
265 if (nFeatureType
!= EXC_ISFPROTECTION
)
266 // We currently only support import of enhanced protection data.
269 aIn
.Ignore(1); // always 1
271 GetSheetProtectBuffer().ReadOptions( aIn
, GetCurrScTab() );
274 void ImportExcel8::Feat()
276 if (!readFrtHeader( aIn
, 0x0868))
279 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
281 sal_uInt16 nFeatureType
= aIn
.ReaduInt16();
282 if (nFeatureType
!= EXC_ISFPROTECTION
)
283 // We currently only support import of enhanced protection data.
286 aIn
.Ignore(5); // reserved1 (1 byte) and reserved2 (4 bytes)
288 sal_uInt16 nCref
= aIn
.ReaduInt16(); // number of ref elements
289 aIn
.Ignore(4); // size if EXC_ISFFEC2, else 0 and to be ignored
290 aIn
.Ignore(2); // reserved3 (2 bytes)
292 ScEnhancedProtection aProt
;
296 aRefs
.Read( aIn
, true, nCref
);
299 aProt
.maRangeList
= new ScRangeList
;
300 GetAddressConverter().ConvertRangeList( *aProt
.maRangeList
, aRefs
, GetCurrScTab(), false);
304 // FeatProtection structure follows in record.
306 aProt
.mnAreserved
= aIn
.ReaduInt32();
307 aProt
.mnPasswordVerifier
= aIn
.ReaduInt32();
308 aProt
.maTitle
= aIn
.ReadUniString();
309 if ((aProt
.mnAreserved
& 0x00000001) == 0x00000001)
311 sal_uInt32 nCbSD
= aIn
.ReaduInt32();
312 // TODO: could here be some sanity check applied to not allocate 4GB?
313 aProt
.maSecurityDescriptor
.resize( nCbSD
);
314 std::size_t nRead
= aIn
.Read(aProt
.maSecurityDescriptor
.data(), nCbSD
);
316 aProt
.maSecurityDescriptor
.resize( nRead
);
319 GetSheetProtectBuffer().AppendEnhancedProtection( aProt
, GetCurrScTab() );
322 void ImportExcel8::ReadBasic()
324 ScDocShell
* pShell
= GetDocShell();
325 rtl::Reference
<SotStorage
> xRootStrg
= GetRootStorage();
326 if( !pShell
|| !xRootStrg
.is() )
331 // #FIXME need to get rid of this, we can also do this from within oox
332 // via the "ooo.vba.VBAGlobals" service
333 if( ( officecfg::Office::Calc::Filter::Import::VBA::Load::get() ||
334 officecfg::Office::Calc::Filter::Import::VBA::Save::get() ) &&
335 officecfg::Office::Calc::Filter::Import::VBA::Executable::get() )
337 // see if we have the XCB stream
338 rtl::Reference
<SotStorageStream
> xXCB
= xRootStrg
->OpenSotStream( u
"XCB"_ustr
, StreamMode::STD_READ
);
339 if ( xXCB
.is()|| ERRCODE_NONE
== xXCB
->GetError() )
341 ScCTBWrapper wrapper
;
342 if ( wrapper
.Read( *xXCB
) )
344 #ifdef DEBUG_SC_EXCEL
345 wrapper
.Print( stderr
);
347 wrapper
.ImportCustomToolBar( *pShell
);
353 const uno::Reference
< uno::XComponentContext
>& aCtx( ::comphelper::getProcessComponentContext() );
354 SfxMedium
& rMedium
= GetMedium();
355 uno::Reference
< io::XInputStream
> xIn
= rMedium
.GetInputStream();
356 oox::ole::OleStorage
root( aCtx
, xIn
, false );
357 oox::StorageRef vbaStg
= root
.openSubStorage( u
"_VBA_PROJECT_CUR"_ustr
, false );
360 oox::ole::VbaProject
aVbaPrj( aCtx
, pShell
->GetModel(), u
"Calc" );
361 // collect names of embedded form controls, as specified in the VBA project
362 uno::Reference
< container::XNameContainer
> xOleNameOverrideSink( new OleNameOverrideContainer
);
363 aVbaPrj
.setOleOverridesSink( xOleNameOverrideSink
);
364 aVbaPrj
.importVbaProject( *vbaStg
);
365 GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink
);
368 catch( uno::Exception
& )
372 catch( uno::Exception
& )
377 void ImportExcel8::EndSheet()
379 ImportExcel::EndSheet();
380 GetCondFormatManager().Apply();
381 GetValidationManager().Apply();
384 void ImportExcel8::PostDocLoad()
386 #if HAVE_FEATURE_SCRIPTING
387 // reading basic has been delayed until sheet objects (codenames etc.) are read
391 // #i11776# filtered ranges before outlines and hidden rows
392 if( pExcRoot
->pAutoFilterBuffer
)
393 pExcRoot
->pAutoFilterBuffer
->Apply();
395 GetWebQueryBuffer().Apply(); //TODO: test if extant
396 GetSheetProtectBuffer().Apply();
397 GetDocProtectBuffer().Apply();
399 ImportExcel::PostDocLoad();
401 // check scenarios; Attention: This increases the table count of the document!!
402 if( !rD
.IsClipboard() && !maScenList
.aEntries
.empty() )
404 rD
.UpdateChartListenerCollection(); // references in charts must be updated
406 maScenList
.Apply( GetRoot() );
409 // read doc info (no docshell while pasting from clipboard)
410 ScDocShell
* pShell
= GetDocShell();
414 // BIFF5+ without storage is possible
415 rtl::Reference
<SotStorage
> xRootStrg
= GetRootStorage();
416 if( xRootStrg
.is() ) try
418 uno::Reference
< document::XDocumentPropertiesSupplier
> xDPS( static_cast<cppu::OWeakObject
*>(pShell
->GetModel()), uno::UNO_QUERY_THROW
);
419 uno::Reference
< document::XDocumentProperties
> xDocProps( xDPS
->getDocumentProperties(), uno::UNO_SET_THROW
);
420 sfx2::LoadOlePropertySet( xDocProps
, xRootStrg
.get() );
422 catch( uno::Exception
& )
426 // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
427 // when formula cells are calculated, for the GETPIVOTDATA function.
432 void ImportExcel8::FilterMode()
434 // The FilterMode record exists: if either the AutoFilter
435 // record exists or an Advanced Filter is saved and stored
436 // in the sheet. Thus if the FilterMode records only exists
437 // then the latter is true...
438 if( !pExcRoot
->pAutoFilterBuffer
) return;
440 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
442 pData
->SetAutoOrAdvanced();
445 void ImportExcel8::AutoFilterInfo()
447 if( !pExcRoot
->pAutoFilterBuffer
) return;
449 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
452 pData
->SetAdvancedRange( nullptr );
457 void ImportExcel8::AutoFilter()
459 if( !pExcRoot
->pAutoFilterBuffer
) return;
461 XclImpAutoFilterData
* pData
= pExcRoot
->pAutoFilterBuffer
->GetByTab( GetCurrScTab() );
463 pData
->ReadAutoFilter(aIn
, GetDoc().GetSharedStringPool());
466 XclImpAutoFilterData::XclImpAutoFilterData( RootData
* pRoot
, const ScRange
& rRange
) :
468 pCurrDBData(nullptr),
471 bAutoOrAdvanced(false)
473 aParam
.nCol1
= rRange
.aStart
.Col();
474 aParam
.nRow1
= rRange
.aStart
.Row();
475 aParam
.nTab
= rRange
.aStart
.Tab();
476 aParam
.nCol2
= rRange
.aEnd
.Col();
477 aParam
.nRow2
= rRange
.aEnd
.Row();
479 aParam
.bInplace
= true;
485 OUString
CreateFromDouble( double fVal
)
487 return rtl::math::doubleToUString(fVal
,
488 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
489 ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
494 void XclImpAutoFilterData::SetCellAttribs()
496 ScDocument
& rDoc
= pExcRoot
->pIR
->GetDoc();
497 for ( SCCOL nCol
= StartCol(); nCol
<= EndCol(); nCol
++ )
499 ScMF nFlag
= rDoc
.GetAttr( nCol
, StartRow(), Tab(), ATTR_MERGE_FLAG
)->GetValue();
500 rDoc
.ApplyAttr( nCol
, StartRow(), Tab(), ScMergeFlagAttr( nFlag
| ScMF::Auto
) );
504 void XclImpAutoFilterData::InsertQueryParam()
510 bool bHasAdv
= pCurrDBData
->GetAdvancedQuerySource( aAdvRange
);
512 pExcRoot
->pIR
->GetDoc().CreateQueryParam(aAdvRange
, aParam
);
514 pCurrDBData
->SetQueryParam( aParam
);
516 pCurrDBData
->SetAdvancedQuerySource( &aAdvRange
);
519 pCurrDBData
->SetAutoFilter( true );
524 static void ExcelQueryToOooQuery( OUString
& aStr
, ScQueryEntry
& rEntry
)
526 if (rEntry
.eOp
!= SC_EQUAL
&& rEntry
.eOp
!= SC_NOT_EQUAL
)
529 sal_Int32 nLen
= aStr
.getLength();
530 sal_Unicode nStart
= aStr
[0];
531 sal_Unicode nEnd
= aStr
[ nLen
-1 ];
532 if( nLen
> 2 && nStart
== '*' && nEnd
== '*' )
534 aStr
= aStr
.copy( 1, nLen
-2 );
535 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_CONTAINS
: SC_DOES_NOT_CONTAIN
;
537 else if( nLen
> 1 && nStart
== '*' && nEnd
!= '*' )
539 aStr
= aStr
.copy( 1 );
540 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_ENDS_WITH
: SC_DOES_NOT_END_WITH
;
542 else if( nLen
> 1 && nStart
!= '*' && nEnd
== '*' )
544 aStr
= aStr
.copy( 0, nLen
-1 );
545 rEntry
.eOp
= ( rEntry
.eOp
== SC_EQUAL
) ? SC_BEGINS_WITH
: SC_DOES_NOT_BEGIN_WITH
;
547 else if( nLen
== 2 && nStart
== '*' && nEnd
== '*' )
549 aStr
= aStr
.copy( 1 );
553 void XclImpAutoFilterData::ReadAutoFilter(
554 XclImpStream
& rStrm
, svl::SharedStringPool
& rPool
)
556 sal_uInt16 nCol
, nFlags
;
557 nCol
= rStrm
.ReaduInt16();
558 nFlags
= rStrm
.ReaduInt16();
560 ScQueryConnect eConn
= ::get_flagvalue( nFlags
, EXC_AFFLAG_ANDORMASK
, SC_OR
, SC_AND
);
561 bool bSimple1
= ::get_flag(nFlags
, EXC_AFFLAG_SIMPLE1
);
562 bool bSimple2
= ::get_flag(nFlags
, EXC_AFFLAG_SIMPLE2
);
563 bool bTop10
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10
);
564 bool bTopOfTop10
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10TOP
);
565 bool bPercent
= ::get_flag(nFlags
, EXC_AFFLAG_TOP10PERC
);
566 sal_uInt16 nCntOfTop10
= nFlags
>> 7;
570 ScQueryEntry
& aEntry
= aParam
.AppendEntry();
571 ScQueryEntry::Item
& rItem
= aEntry
.GetQueryItem();
572 aEntry
.bDoQuery
= true;
573 aEntry
.nField
= static_cast<SCCOLROW
>(StartCol() + static_cast<SCCOL
>(nCol
));
574 aEntry
.eOp
= bTopOfTop10
?
575 (bPercent
? SC_TOPPERC
: SC_TOPVAL
) : (bPercent
? SC_BOTPERC
: SC_BOTVAL
);
576 aEntry
.eConnect
= SC_AND
;
578 rItem
.meType
= ScQueryEntry::ByString
;
579 rItem
.maString
= rPool
.intern(OUString::number(nCntOfTop10
));
585 sal_uInt8 nType
, nOper
, nBoolErr
, nVal
;
589 sal_uInt8 nStrLen
[2] = { 0, 0 };
590 ScQueryEntry aEntries
[2];
592 for (size_t nE
= 0; nE
< 2; ++nE
)
594 ScQueryEntry
& rEntry
= aEntries
[nE
];
595 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
596 bool bIgnore
= false;
598 nType
= rStrm
.ReaduInt8();
599 nOper
= rStrm
.ReaduInt8();
602 case EXC_AFOPER_LESS
:
603 rEntry
.eOp
= SC_LESS
;
605 case EXC_AFOPER_EQUAL
:
606 rEntry
.eOp
= SC_EQUAL
;
608 case EXC_AFOPER_LESSEQUAL
:
609 rEntry
.eOp
= SC_LESS_EQUAL
;
611 case EXC_AFOPER_GREATER
:
612 rEntry
.eOp
= SC_GREATER
;
614 case EXC_AFOPER_NOTEQUAL
:
615 rEntry
.eOp
= SC_NOT_EQUAL
;
617 case EXC_AFOPER_GREATEREQUAL
:
618 rEntry
.eOp
= SC_GREATER_EQUAL
;
621 rEntry
.eOp
= SC_EQUAL
;
627 nRK
= rStrm
.ReadInt32();
629 rItem
.maString
= rPool
.intern(
630 CreateFromDouble(XclTools::GetDoubleFromRK(nRK
)));
632 case EXC_AFTYPE_DOUBLE
:
633 fVal
= rStrm
.ReadDouble();
634 rItem
.maString
= rPool
.intern(CreateFromDouble(fVal
));
636 case EXC_AFTYPE_STRING
:
638 nStrLen
[ nE
] = rStrm
.ReaduInt8();
640 rItem
.maString
= svl::SharedString();
642 case EXC_AFTYPE_BOOLERR
:
643 nBoolErr
= rStrm
.ReaduInt8();
644 nVal
= rStrm
.ReaduInt8();
646 rItem
.maString
= rPool
.intern(OUString::number(nVal
));
647 bIgnore
= (nBoolErr
!= 0);
649 case EXC_AFTYPE_EMPTY
:
650 rEntry
.SetQueryByEmpty();
652 case EXC_AFTYPE_NOTEMPTY
:
653 rEntry
.SetQueryByNonEmpty();
662 rEntry
.bDoQuery
= true;
663 rItem
.meType
= ScQueryEntry::ByString
;
664 rEntry
.nField
= static_cast<SCCOLROW
>(StartCol() + static_cast<SCCOL
>(nCol
));
665 rEntry
.eConnect
= nE
? eConn
: SC_AND
;
671 for (size_t nE
= 0; nE
< 2; ++nE
)
673 if (nStrLen
[nE
] && aEntries
[nE
].bDoQuery
)
675 OUString aStr
= rStrm
.ReadUniString(nStrLen
[nE
]);
676 ExcelQueryToOooQuery(aStr
, aEntries
[nE
]);
677 aEntries
[nE
].GetQueryItem().maString
= rPool
.intern(aStr
);
678 aParam
.AppendEntry() = aEntries
[nE
];
684 assert( eConn
== SC_OR
&& "eConn should be SC_AND or SC_OR");
685 // Import only when both conditions are for simple equality, else
686 // import only the 1st condition due to conflict with the ordering of
687 // conditions. #i39464#.
689 // Example: Let A1 be a condition of column A, and B1 and B2
690 // conditions of column B, connected with OR. Excel performs 'A1 AND
691 // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
694 if (bSimple1
&& bSimple2
&& nStrLen
[0] && nStrLen
[1])
696 // Two simple OR'ed equal conditions. We can import this correctly.
697 ScQueryEntry
& rEntry
= aParam
.AppendEntry();
698 rEntry
.bDoQuery
= true;
699 rEntry
.eOp
= SC_EQUAL
;
700 rEntry
.eConnect
= SC_AND
;
701 ScQueryEntry::QueryItemsType aItems
;
703 ScQueryEntry::Item aItem1
, aItem2
;
704 aItem1
.maString
= rPool
.intern(rStrm
.ReadUniString(nStrLen
[0]));
705 aItem1
.meType
= ScQueryEntry::ByString
;
706 aItem2
.maString
= rPool
.intern(rStrm
.ReadUniString(nStrLen
[1]));
707 aItem2
.meType
= ScQueryEntry::ByString
;
708 aItems
.push_back(aItem1
);
709 aItems
.push_back(aItem2
);
710 rEntry
.GetQueryItems().swap(aItems
);
712 else if (nStrLen
[0] && aEntries
[0].bDoQuery
)
714 // Due to conflict, we can import only the first condition.
715 OUString aStr
= rStrm
.ReadUniString(nStrLen
[0]);
716 ExcelQueryToOooQuery(aStr
, aEntries
[0]);
717 aEntries
[0].GetQueryItem().maString
= rPool
.intern(aStr
);
718 aParam
.AppendEntry() = aEntries
[0];
723 void XclImpAutoFilterData::SetAdvancedRange( const ScRange
* pRange
)
727 aCriteriaRange
= *pRange
;
734 void XclImpAutoFilterData::SetExtractPos( const ScAddress
& rAddr
)
736 aParam
.nDestCol
= rAddr
.Col();
737 aParam
.nDestRow
= rAddr
.Row();
738 aParam
.nDestTab
= rAddr
.Tab();
739 aParam
.bInplace
= false;
740 aParam
.bDestPers
= true;
743 void XclImpAutoFilterData::Apply()
745 // Create the ScDBData() object if the AutoFilter is activated
746 // or if we need to create the Advanced Filter.
747 if( bActive
|| bCriteria
)
749 ScDocument
& rDoc
= pExcRoot
->pIR
->GetDoc();
750 pCurrDBData
= new ScDBData(STR_DB_LOCAL_NONAME
, Tab(),
751 StartCol(),StartRow(), EndCol(),EndRow() );
754 EnableRemoveFilter();
756 pCurrDBData
->SetQueryParam( aParam
);
757 pCurrDBData
->SetAdvancedQuerySource(&aCriteriaRange
);
760 pCurrDBData
->SetAdvancedQuerySource(nullptr);
761 rDoc
.SetAnonymousDBData(Tab(), std::unique_ptr
<ScDBData
>(pCurrDBData
));
770 void XclImpAutoFilterData::EnableRemoveFilter()
772 // only if this is a saved Advanced filter
773 if( !bActive
&& bAutoOrAdvanced
)
775 ScQueryEntry
& aEntry
= aParam
.AppendEntry();
776 aEntry
.bDoQuery
= true;
779 // TBD: force the automatic activation of the
780 // "Remove Filter" by setting a virtual mouse click
781 // inside the advanced range
784 void XclImpAutoFilterBuffer::Insert( RootData
* pRoot
, const ScRange
& rRange
)
786 if( !GetByTab( rRange
.aStart
.Tab() ) )
787 maFilters
.push_back( std::make_shared
<XclImpAutoFilterData
>( pRoot
, rRange
));
790 void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange
& rRange
)
792 XclImpAutoFilterData
* pData
= GetByTab( rRange
.aStart
.Tab() );
794 pData
->SetAdvancedRange( &rRange
);
797 void XclImpAutoFilterBuffer::AddExtractPos( const ScRange
& rRange
)
799 XclImpAutoFilterData
* pData
= GetByTab( rRange
.aStart
.Tab() );
801 pData
->SetExtractPos( rRange
.aStart
);
804 void XclImpAutoFilterBuffer::Apply()
806 for( const auto& rFilterPtr
: maFilters
)
810 XclImpAutoFilterData
* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab
)
812 for( const auto& rFilterPtr
: maFilters
)
814 if( rFilterPtr
->Tab() == nTab
)
815 return rFilterPtr
.get();
820 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */