use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / excimp8.cxx
blob248e4589971ee4ebd5892f6716d9c7f96f28c719
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
40 #include <docsh.hxx>
41 #include <attrib.hxx>
42 #include <dbdata.hxx>
43 #include <globalnames.hxx>
44 #include <docoptio.hxx>
45 #include <xihelper.hxx>
46 #include <xicontent.hxx>
47 #include <xilink.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
70 namespace {
72 class OleNameOverrideContainer : public ::cppu::WeakImplHelper< container::XNameContainer >
74 private:
75 typedef std::unordered_map< OUString, uno::Reference< container::XIndexContainer > > NamedIndexToOleName;
76 NamedIndexToOleName IdToOleNameHash;
77 std::mutex m_aMutex;
78 public:
79 // XElementAccess
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() );
86 // XNameAccess
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() );
106 // XNameContainer
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()
191 sal_uInt8 nLen;
192 sal_uInt16 nGrbit;
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;
204 if( nScTab > 0 )
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 );
219 nBdshtTab++;
222 void ImportExcel8::Scenman()
224 sal_uInt16 nLastDispl;
226 aIn.Ignore( 4 );
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()
239 XclAddress aXclPos;
240 sal_uInt16 nXF;
241 sal_uInt32 nSst;
243 aIn >> aXclPos;
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);
252 if (pXclStr)
253 XclImpStringHelper::SetToDocument(GetDocImport(), aScPos, *this, *pXclStr, nXF);
257 void ImportExcel8::FeatHdr()
259 if (!readFrtHeader( aIn, 0x0867))
260 return;
262 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
263 // EXC_ISFFACTOID.
264 sal_uInt16 nFeatureType = aIn.ReaduInt16();
265 if (nFeatureType != EXC_ISFPROTECTION)
266 // We currently only support import of enhanced protection data.
267 return;
269 aIn.Ignore(1); // always 1
271 GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
274 void ImportExcel8::Feat()
276 if (!readFrtHeader( aIn, 0x0868))
277 return;
279 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
280 // EXC_ISFFACTOID.
281 sal_uInt16 nFeatureType = aIn.ReaduInt16();
282 if (nFeatureType != EXC_ISFPROTECTION)
283 // We currently only support import of enhanced protection data.
284 return;
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;
293 if (nCref)
295 XclRangeList aRefs;
296 aRefs.Read( aIn, true, nCref);
297 if (!aRefs.empty())
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);
315 if (nRead < 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() )
327 return;
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 );
346 #endif
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 );
358 if ( vbaStg )
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
388 if( HasBasic() )
389 ReadBasic();
390 #endif
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();
411 if(!pShell)
412 return;
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.
430 // autofilter
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() );
441 if( pData )
442 pData->SetAutoOrAdvanced();
445 void ImportExcel8::AutoFilterInfo()
447 if( !pExcRoot->pAutoFilterBuffer ) return;
449 XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
450 if( pData )
452 pData->SetAdvancedRange( nullptr );
453 pData->Activate();
457 void ImportExcel8::AutoFilter()
459 if( !pExcRoot->pAutoFilterBuffer ) return;
461 XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
462 if( pData )
463 pData->ReadAutoFilter(aIn, GetDoc().GetSharedStringPool());
466 XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
467 ExcRoot( pRoot ),
468 pCurrDBData(nullptr),
469 bActive( false ),
470 bCriteria( false ),
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;
483 namespace {
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()
506 if (!pCurrDBData)
507 return;
509 ScRange aAdvRange;
510 bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
511 if( bHasAdv )
512 pExcRoot->pIR->GetDoc().CreateQueryParam(aAdvRange, aParam);
514 pCurrDBData->SetQueryParam( aParam );
515 if( bHasAdv )
516 pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
517 else
519 pCurrDBData->SetAutoFilter( true );
520 SetCellAttribs();
524 static void ExcelQueryToOooQuery( OUString& aStr, ScQueryEntry& rEntry )
526 if (rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL)
527 return;
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;
568 if( bTop10 )
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));
581 rStrm.Ignore(20);
582 return;
585 sal_uInt8 nType, nOper, nBoolErr, nVal;
586 sal_Int32 nRK;
587 double fVal;
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();
600 switch( nOper )
602 case EXC_AFOPER_LESS:
603 rEntry.eOp = SC_LESS;
604 break;
605 case EXC_AFOPER_EQUAL:
606 rEntry.eOp = SC_EQUAL;
607 break;
608 case EXC_AFOPER_LESSEQUAL:
609 rEntry.eOp = SC_LESS_EQUAL;
610 break;
611 case EXC_AFOPER_GREATER:
612 rEntry.eOp = SC_GREATER;
613 break;
614 case EXC_AFOPER_NOTEQUAL:
615 rEntry.eOp = SC_NOT_EQUAL;
616 break;
617 case EXC_AFOPER_GREATEREQUAL:
618 rEntry.eOp = SC_GREATER_EQUAL;
619 break;
620 default:
621 rEntry.eOp = SC_EQUAL;
624 switch( nType )
626 case EXC_AFTYPE_RK:
627 nRK = rStrm.ReadInt32();
628 rStrm.Ignore( 4 );
629 rItem.maString = rPool.intern(
630 CreateFromDouble(XclTools::GetDoubleFromRK(nRK)));
631 break;
632 case EXC_AFTYPE_DOUBLE:
633 fVal = rStrm.ReadDouble();
634 rItem.maString = rPool.intern(CreateFromDouble(fVal));
635 break;
636 case EXC_AFTYPE_STRING:
637 rStrm.Ignore( 4 );
638 nStrLen[ nE ] = rStrm.ReaduInt8();
639 rStrm.Ignore( 3 );
640 rItem.maString = svl::SharedString();
641 break;
642 case EXC_AFTYPE_BOOLERR:
643 nBoolErr = rStrm.ReaduInt8();
644 nVal = rStrm.ReaduInt8();
645 rStrm.Ignore( 6 );
646 rItem.maString = rPool.intern(OUString::number(nVal));
647 bIgnore = (nBoolErr != 0);
648 break;
649 case EXC_AFTYPE_EMPTY:
650 rEntry.SetQueryByEmpty();
651 break;
652 case EXC_AFTYPE_NOTEMPTY:
653 rEntry.SetQueryByNonEmpty();
654 break;
655 default:
656 rStrm.Ignore( 8 );
657 bIgnore = true;
660 if (!bIgnore)
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;
669 if (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];
682 else
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'
692 // instead.
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;
702 aItems.reserve(2);
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 )
725 if (pRange)
727 aCriteriaRange = *pRange;
728 bCriteria = true;
730 else
731 bCriteria = false;
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() );
752 if(bCriteria)
754 EnableRemoveFilter();
756 pCurrDBData->SetQueryParam( aParam );
757 pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
759 else
760 pCurrDBData->SetAdvancedQuerySource(nullptr);
761 rDoc.SetAnonymousDBData(Tab(), std::unique_ptr<ScDBData>(pCurrDBData));
764 if( bActive )
766 InsertQueryParam();
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() );
793 if( pData )
794 pData->SetAdvancedRange( &rRange );
797 void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
799 XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
800 if( pData )
801 pData->SetExtractPos( rRange.aStart );
804 void XclImpAutoFilterBuffer::Apply()
806 for( const auto& rFilterPtr : maFilters )
807 rFilterPtr->Apply();
810 XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
812 for( const auto& rFilterPtr : maFilters )
814 if( rFilterPtr->Tab() == nTab )
815 return rFilterPtr.get();
817 return nullptr;
820 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */