LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / excel / excimp8.cxx
blob930057c7f78970c2c2218781c1e6e7d383916195
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 <unotools/fltrcfg.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 <attrib.hxx>
41 #include <dbdata.hxx>
42 #include <globalnames.hxx>
43 #include <docoptio.hxx>
44 #include <xihelper.hxx>
45 #include <xicontent.hxx>
46 #include <xilink.hxx>
47 #include <xiescher.hxx>
48 #include <xistyle.hxx>
49 #include <excdefs.hxx>
51 #include <excform.hxx>
52 #include <queryentry.hxx>
54 #include <com/sun/star/document/XDocumentProperties.hpp>
55 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
56 #include <com/sun/star/container/XIndexContainer.hpp>
57 #include <com/sun/star/container/XNameContainer.hpp>
58 #include <com/sun/star/frame/XModel.hpp>
59 #include <cppuhelper/implbase.hxx>
60 #include "xltoolbar.hxx"
61 #include <oox/ole/vbaproject.hxx>
62 #include <oox/ole/olestorage.hxx>
64 using namespace com::sun::star;
65 using namespace ::comphelper;
67 //OleNameOverrideContainer
69 namespace {
71 class OleNameOverrideContainer : public ::cppu::WeakImplHelper< container::XNameContainer >
73 private:
74 typedef std::unordered_map< OUString, uno::Reference< container::XIndexContainer > > NamedIndexToOleName;
75 NamedIndexToOleName IdToOleNameHash;
76 ::osl::Mutex m_aMutex;
77 public:
78 // XElementAccess
79 virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<container::XIndexContainer>::get(); }
80 virtual sal_Bool SAL_CALL hasElements( ) override
82 ::osl::MutexGuard aGuard( m_aMutex );
83 return ( !IdToOleNameHash.empty() );
85 // XNameAccess
86 virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
88 ::osl::MutexGuard aGuard( m_aMutex );
89 if ( !hasByName(aName) )
90 throw container::NoSuchElementException();
91 return uno::makeAny( IdToOleNameHash[ aName ] );
93 virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
95 ::osl::MutexGuard aGuard( m_aMutex );
96 return comphelper::mapKeysToSequence( IdToOleNameHash);
98 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
100 ::osl::MutexGuard aGuard( m_aMutex );
101 return ( IdToOleNameHash.find( aName ) != IdToOleNameHash.end() );
104 // XNameContainer
105 virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override
107 ::osl::MutexGuard aGuard( m_aMutex );
108 if ( hasByName( aName ) )
109 throw container::ElementExistException();
110 uno::Reference< container::XIndexContainer > xElement;
111 if ( ! ( aElement >>= xElement ) )
112 throw lang::IllegalArgumentException();
113 IdToOleNameHash[ aName ] = xElement;
115 virtual void SAL_CALL removeByName( const OUString& aName ) override
117 ::osl::MutexGuard aGuard( m_aMutex );
118 if ( IdToOleNameHash.erase( aName ) == 0 )
119 throw container::NoSuchElementException();
121 virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override
123 ::osl::MutexGuard aGuard( m_aMutex );
124 if ( !hasByName( aName ) )
125 throw container::NoSuchElementException();
126 uno::Reference< container::XIndexContainer > xElement;
127 if ( ! ( aElement >>= xElement ) )
128 throw lang::IllegalArgumentException();
129 IdToOleNameHash[ aName ] = xElement;
133 /** Future Record Type header.
134 @return whether read rt matches nRecordID
136 bool readFrtHeader( XclImpStream& rStrm, sal_uInt16 nRecordID )
138 sal_uInt16 nRt = rStrm.ReaduInt16();
139 rStrm.Ignore(10); // grbitFrt (2 bytes) and reserved (8 bytes)
140 return nRt == nRecordID;
145 ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) :
146 ImportExcel( rImpData, rStrm )
148 // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
149 pFormConv.reset(new ExcelToSc8( GetRoot() ));
150 pExcRoot->pFmlaConverter = pFormConv.get();
153 ImportExcel8::~ImportExcel8()
157 void ImportExcel8::Calccount()
159 ScDocOptions aOpt = rD.GetDocOptions();
160 aOpt.SetIterCount( aIn.ReaduInt16() );
161 rD.SetDocOptions( aOpt );
164 void ImportExcel8::Precision()
166 ScDocOptions aOpt = rD.GetDocOptions();
167 aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 );
168 rD.SetDocOptions( aOpt );
171 void ImportExcel8::Delta()
173 ScDocOptions aOpt = rD.GetDocOptions();
174 aOpt.SetIterEps( aIn.ReadDouble() );
175 rD.SetDocOptions( aOpt );
178 void ImportExcel8::Iteration()
180 ScDocOptions aOpt = rD.GetDocOptions();
181 aOpt.SetIter( aIn.ReaduInt16() == 1 );
182 rD.SetDocOptions( aOpt );
185 void ImportExcel8::Boundsheet()
187 sal_uInt8 nLen;
188 sal_uInt16 nGrbit;
190 aIn.DisableDecryption();
191 maSheetOffsets.push_back( aIn.ReaduInt32() );
192 aIn.EnableDecryption();
193 nGrbit = aIn.ReaduInt16();
194 nLen = aIn.ReaduInt8();
196 OUString aName( aIn.ReadUniString( nLen ) );
197 GetTabInfo().AppendXclTabName( aName, nBdshtTab );
199 SCTAB nScTab = nBdshtTab;
200 if( nScTab > 0 )
202 OSL_ENSURE( !rD.HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" );
203 rD.MakeTable( nScTab );
206 if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
207 rD.SetVisible( nScTab, false );
209 if( !rD.RenameTab( nScTab, aName ) )
211 rD.CreateValidTabName( aName );
212 rD.RenameTab( nScTab, aName );
215 nBdshtTab++;
218 void ImportExcel8::Scenman()
220 sal_uInt16 nLastDispl;
222 aIn.Ignore( 4 );
223 nLastDispl = aIn.ReaduInt16();
225 maScenList.nLastScenario = nLastDispl;
228 void ImportExcel8::Scenario()
230 maScenList.aEntries.push_back( std::make_unique<ExcScenario>( aIn, *pExcRoot ) );
233 void ImportExcel8::Labelsst()
235 XclAddress aXclPos;
236 sal_uInt16 nXF;
237 sal_uInt32 nSst;
239 aIn >> aXclPos;
240 nXF = aIn.ReaduInt16();
241 nSst = aIn.ReaduInt32( );
243 ScAddress aScPos( ScAddress::UNINITIALIZED );
244 if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
246 GetXFRangeBuffer().SetXF( aScPos, nXF );
247 const XclImpString* pXclStr = GetSst().GetString(nSst);
248 if (pXclStr)
249 XclImpStringHelper::SetToDocument(GetDocImport(), aScPos, *this, *pXclStr, nXF);
253 void ImportExcel8::FeatHdr()
255 if (!readFrtHeader( aIn, 0x0867))
256 return;
258 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
259 // EXC_ISFFACTOID.
260 sal_uInt16 nFeatureType = aIn.ReaduInt16();
261 if (nFeatureType != EXC_ISFPROTECTION)
262 // We currently only support import of enhanced protection data.
263 return;
265 aIn.Ignore(1); // always 1
267 GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
270 void ImportExcel8::Feat()
272 if (!readFrtHeader( aIn, 0x0868))
273 return;
275 // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
276 // EXC_ISFFACTOID.
277 sal_uInt16 nFeatureType = aIn.ReaduInt16();
278 if (nFeatureType != EXC_ISFPROTECTION)
279 // We currently only support import of enhanced protection data.
280 return;
282 aIn.Ignore(5); // reserved1 (1 byte) and reserved2 (4 bytes)
284 sal_uInt16 nCref = aIn.ReaduInt16(); // number of ref elements
285 aIn.Ignore(4); // size if EXC_ISFFEC2, else 0 and to be ignored
286 aIn.Ignore(2); // reserved3 (2 bytes)
288 ScEnhancedProtection aProt;
289 if (nCref)
291 XclRangeList aRefs;
292 aRefs.Read( aIn, true, nCref);
293 if (!aRefs.empty())
295 aProt.maRangeList = new ScRangeList;
296 GetAddressConverter().ConvertRangeList( *aProt.maRangeList, aRefs, GetCurrScTab(), false);
300 // FeatProtection structure follows in record.
302 aProt.mnAreserved = aIn.ReaduInt32();
303 aProt.mnPasswordVerifier = aIn.ReaduInt32();
304 aProt.maTitle = aIn.ReadUniString();
305 if ((aProt.mnAreserved & 0x00000001) == 0x00000001)
307 sal_uInt32 nCbSD = aIn.ReaduInt32();
308 // TODO: could here be some sanity check applied to not allocate 4GB?
309 aProt.maSecurityDescriptor.resize( nCbSD);
310 std::size_t nRead = aIn.Read(aProt.maSecurityDescriptor.data(), nCbSD);
311 if (nRead < nCbSD)
312 aProt.maSecurityDescriptor.resize( nRead);
315 GetSheetProtectBuffer().AppendEnhancedProtection( aProt, GetCurrScTab() );
318 void ImportExcel8::ReadBasic()
320 SfxObjectShell* pShell = GetDocShell();
321 tools::SvRef<SotStorage> xRootStrg = GetRootStorage();
322 const SvtFilterOptions& rFilterOpt = SvtFilterOptions::Get();
323 if( !pShell || !xRootStrg.is() )
324 return;
328 // #FIXME need to get rid of this, we can also do this from within oox
329 // via the "ooo.vba.VBAGlobals" service
330 if( ( rFilterOpt.IsLoadExcelBasicCode() ||
331 rFilterOpt.IsLoadExcelBasicStorage() ) &&
332 rFilterOpt.IsLoadExcelBasicExecutable() )
334 // see if we have the XCB stream
335 tools::SvRef<SotStorageStream> xXCB = xRootStrg->OpenSotStream( "XCB", StreamMode::STD_READ );
336 if ( xXCB.is()|| ERRCODE_NONE == xXCB->GetError() )
338 ScCTBWrapper wrapper;
339 if ( wrapper.Read( *xXCB ) )
341 #ifdef DEBUG_SC_EXCEL
342 wrapper.Print( stderr );
343 #endif
344 wrapper.ImportCustomToolBar( *pShell );
350 uno::Reference< uno::XComponentContext > aCtx( ::comphelper::getProcessComponentContext() );
351 SfxMedium& rMedium = GetMedium();
352 uno::Reference< io::XInputStream > xIn = rMedium.GetInputStream();
353 oox::ole::OleStorage root( aCtx, xIn, false );
354 oox::StorageRef vbaStg = root.openSubStorage( "_VBA_PROJECT_CUR", false );
355 if ( vbaStg )
357 oox::ole::VbaProject aVbaPrj( aCtx, pShell->GetModel(), u"Calc" );
358 // collect names of embedded form controls, as specified in the VBA project
359 uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer );
360 aVbaPrj.setOleOverridesSink( xOleNameOverrideSink );
361 aVbaPrj.importVbaProject( *vbaStg );
362 GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink );
365 catch( uno::Exception& )
369 catch( uno::Exception& )
374 void ImportExcel8::EndSheet()
376 ImportExcel::EndSheet();
377 GetCondFormatManager().Apply();
378 GetValidationManager().Apply();
381 void ImportExcel8::PostDocLoad()
383 #if HAVE_FEATURE_SCRIPTING
384 // reading basic has been delayed until sheet objects (codenames etc.) are read
385 if( HasBasic() )
386 ReadBasic();
387 #endif
388 // #i11776# filtered ranges before outlines and hidden rows
389 if( pExcRoot->pAutoFilterBuffer )
390 pExcRoot->pAutoFilterBuffer->Apply();
392 GetWebQueryBuffer().Apply(); //TODO: test if extant
393 GetSheetProtectBuffer().Apply();
394 GetDocProtectBuffer().Apply();
396 ImportExcel::PostDocLoad();
398 // check scenarios; Attention: This increases the table count of the document!!
399 if( !rD.IsClipboard() && !maScenList.aEntries.empty() )
401 rD.UpdateChartListenerCollection(); // references in charts must be updated
403 maScenList.Apply( GetRoot() );
406 // read doc info (no docshell while pasting from clipboard)
407 SfxObjectShell* pShell = GetDocShell();
408 if(!pShell)
409 return;
411 // BIFF5+ without storage is possible
412 tools::SvRef<SotStorage> xRootStrg = GetRootStorage();
413 if( xRootStrg.is() ) try
415 uno::Reference< document::XDocumentPropertiesSupplier > xDPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
416 uno::Reference< document::XDocumentProperties > xDocProps( xDPS->getDocumentProperties(), uno::UNO_SET_THROW );
417 sfx2::LoadOlePropertySet( xDocProps, xRootStrg.get() );
419 catch( uno::Exception& )
423 // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
424 // when formula cells are calculated, for the GETPIVOTDATA function.
427 // autofilter
429 void ImportExcel8::FilterMode()
431 // The FilterMode record exists: if either the AutoFilter
432 // record exists or an Advanced Filter is saved and stored
433 // in the sheet. Thus if the FilterMode records only exists
434 // then the latter is true...
435 if( !pExcRoot->pAutoFilterBuffer ) return;
437 XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
438 if( pData )
439 pData->SetAutoOrAdvanced();
442 void ImportExcel8::AutoFilterInfo()
444 if( !pExcRoot->pAutoFilterBuffer ) return;
446 XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
447 if( pData )
449 pData->SetAdvancedRange( nullptr );
450 pData->Activate();
454 void ImportExcel8::AutoFilter()
456 if( !pExcRoot->pAutoFilterBuffer ) return;
458 XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
459 if( pData )
460 pData->ReadAutoFilter(aIn, GetDoc().GetSharedStringPool());
463 XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
464 ExcRoot( pRoot ),
465 pCurrDBData(nullptr),
466 bActive( false ),
467 bCriteria( false ),
468 bAutoOrAdvanced(false)
470 aParam.nCol1 = rRange.aStart.Col();
471 aParam.nRow1 = rRange.aStart.Row();
472 aParam.nTab = rRange.aStart.Tab();
473 aParam.nCol2 = rRange.aEnd.Col();
474 aParam.nRow2 = rRange.aEnd.Row();
476 aParam.bInplace = true;
480 namespace {
482 OUString CreateFromDouble( double fVal )
484 return rtl::math::doubleToUString(fVal,
485 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
486 ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
491 void XclImpAutoFilterData::SetCellAttribs()
493 ScDocument& rDoc = pExcRoot->pIR->GetDoc();
494 for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ )
496 ScMF nFlag = rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG )->GetValue();
497 rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | ScMF::Auto) );
501 void XclImpAutoFilterData::InsertQueryParam()
503 if (!pCurrDBData)
504 return;
506 ScRange aAdvRange;
507 bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
508 if( bHasAdv )
509 pExcRoot->pIR->GetDoc().CreateQueryParam(aAdvRange, aParam);
511 pCurrDBData->SetQueryParam( aParam );
512 if( bHasAdv )
513 pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
514 else
516 pCurrDBData->SetAutoFilter( true );
517 SetCellAttribs();
521 static void ExcelQueryToOooQuery( OUString& aStr, ScQueryEntry& rEntry )
523 if (rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL)
524 return;
526 sal_Int32 nLen = aStr.getLength();
527 sal_Unicode nStart = aStr[0];
528 sal_Unicode nEnd = aStr[ nLen-1 ];
529 if( nLen > 2 && nStart == '*' && nEnd == '*' )
531 aStr = aStr.copy( 1, nLen-2 );
532 rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN;
534 else if( nLen > 1 && nStart == '*' && nEnd != '*' )
536 aStr = aStr.copy( 1 );
537 rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH;
539 else if( nLen > 1 && nStart != '*' && nEnd == '*' )
541 aStr = aStr.copy( 0, nLen-1 );
542 rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH;
544 else if( nLen == 2 && nStart == '*' && nEnd == '*' )
546 aStr = aStr.copy( 1 );
550 void XclImpAutoFilterData::ReadAutoFilter(
551 XclImpStream& rStrm, svl::SharedStringPool& rPool )
553 sal_uInt16 nCol, nFlags;
554 nCol = rStrm.ReaduInt16();
555 nFlags = rStrm.ReaduInt16();
557 ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND );
558 bool bSimple1 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE1);
559 bool bSimple2 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE2);
560 bool bTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10);
561 bool bTopOfTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10TOP);
562 bool bPercent = ::get_flag(nFlags, EXC_AFFLAG_TOP10PERC);
563 sal_uInt16 nCntOfTop10 = nFlags >> 7;
565 if( bTop10 )
567 ScQueryEntry& aEntry = aParam.AppendEntry();
568 ScQueryEntry::Item& rItem = aEntry.GetQueryItem();
569 aEntry.bDoQuery = true;
570 aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
571 aEntry.eOp = bTopOfTop10 ?
572 (bPercent ? SC_TOPPERC : SC_TOPVAL) : (bPercent ? SC_BOTPERC : SC_BOTVAL);
573 aEntry.eConnect = SC_AND;
575 rItem.meType = ScQueryEntry::ByString;
576 rItem.maString = rPool.intern(OUString::number(nCntOfTop10));
578 rStrm.Ignore(20);
579 return;
582 sal_uInt8 nType, nOper, nBoolErr, nVal;
583 sal_Int32 nRK;
584 double fVal;
586 sal_uInt8 nStrLen[2] = { 0, 0 };
587 ScQueryEntry aEntries[2];
589 for (size_t nE = 0; nE < 2; ++nE)
591 ScQueryEntry& rEntry = aEntries[nE];
592 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
593 bool bIgnore = false;
595 nType = rStrm.ReaduInt8();
596 nOper = rStrm.ReaduInt8();
597 switch( nOper )
599 case EXC_AFOPER_LESS:
600 rEntry.eOp = SC_LESS;
601 break;
602 case EXC_AFOPER_EQUAL:
603 rEntry.eOp = SC_EQUAL;
604 break;
605 case EXC_AFOPER_LESSEQUAL:
606 rEntry.eOp = SC_LESS_EQUAL;
607 break;
608 case EXC_AFOPER_GREATER:
609 rEntry.eOp = SC_GREATER;
610 break;
611 case EXC_AFOPER_NOTEQUAL:
612 rEntry.eOp = SC_NOT_EQUAL;
613 break;
614 case EXC_AFOPER_GREATEREQUAL:
615 rEntry.eOp = SC_GREATER_EQUAL;
616 break;
617 default:
618 rEntry.eOp = SC_EQUAL;
621 switch( nType )
623 case EXC_AFTYPE_RK:
624 nRK = rStrm.ReadInt32();
625 rStrm.Ignore( 4 );
626 rItem.maString = rPool.intern(
627 CreateFromDouble(XclTools::GetDoubleFromRK(nRK)));
628 break;
629 case EXC_AFTYPE_DOUBLE:
630 fVal = rStrm.ReadDouble();
631 rItem.maString = rPool.intern(CreateFromDouble(fVal));
632 break;
633 case EXC_AFTYPE_STRING:
634 rStrm.Ignore( 4 );
635 nStrLen[ nE ] = rStrm.ReaduInt8();
636 rStrm.Ignore( 3 );
637 rItem.maString = svl::SharedString();
638 break;
639 case EXC_AFTYPE_BOOLERR:
640 nBoolErr = rStrm.ReaduInt8();
641 nVal = rStrm.ReaduInt8();
642 rStrm.Ignore( 6 );
643 rItem.maString = rPool.intern(OUString::number(nVal));
644 bIgnore = (nBoolErr != 0);
645 break;
646 case EXC_AFTYPE_EMPTY:
647 rEntry.SetQueryByEmpty();
648 break;
649 case EXC_AFTYPE_NOTEMPTY:
650 rEntry.SetQueryByNonEmpty();
651 break;
652 default:
653 rStrm.Ignore( 8 );
654 bIgnore = true;
657 if (!bIgnore)
659 rEntry.bDoQuery = true;
660 rItem.meType = ScQueryEntry::ByString;
661 rEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
662 rEntry.eConnect = nE ? eConn : SC_AND;
666 if (eConn == SC_AND)
668 for (size_t nE = 0; nE < 2; ++nE)
670 if (nStrLen[nE] && aEntries[nE].bDoQuery)
672 OUString aStr = rStrm.ReadUniString(nStrLen[nE]);
673 ExcelQueryToOooQuery(aStr, aEntries[nE]);
674 aEntries[nE].GetQueryItem().maString = rPool.intern(aStr);
675 aParam.AppendEntry() = aEntries[nE];
679 else
681 assert( eConn == SC_OR && "eConn should be SC_AND or SC_OR");
682 // Import only when both conditions are for simple equality, else
683 // import only the 1st condition due to conflict with the ordering of
684 // conditions. #i39464#.
686 // Example: Let A1 be a condition of column A, and B1 and B2
687 // conditions of column B, connected with OR. Excel performs 'A1 AND
688 // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
689 // instead.
691 if (bSimple1 && bSimple2 && nStrLen[0] && nStrLen[1])
693 // Two simple OR'ed equal conditions. We can import this correctly.
694 ScQueryEntry& rEntry = aParam.AppendEntry();
695 rEntry.bDoQuery = true;
696 rEntry.eOp = SC_EQUAL;
697 rEntry.eConnect = SC_AND;
698 ScQueryEntry::QueryItemsType aItems;
699 aItems.reserve(2);
700 ScQueryEntry::Item aItem1, aItem2;
701 aItem1.maString = rPool.intern(rStrm.ReadUniString(nStrLen[0]));
702 aItem1.meType = ScQueryEntry::ByString;
703 aItem2.maString = rPool.intern(rStrm.ReadUniString(nStrLen[1]));
704 aItem2.meType = ScQueryEntry::ByString;
705 aItems.push_back(aItem1);
706 aItems.push_back(aItem2);
707 rEntry.GetQueryItems().swap(aItems);
709 else if (nStrLen[0] && aEntries[0].bDoQuery)
711 // Due to conflict, we can import only the first condition.
712 OUString aStr = rStrm.ReadUniString(nStrLen[0]);
713 ExcelQueryToOooQuery(aStr, aEntries[0]);
714 aEntries[0].GetQueryItem().maString = rPool.intern(aStr);
715 aParam.AppendEntry() = aEntries[0];
720 void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange )
722 if (pRange)
724 aCriteriaRange = *pRange;
725 bCriteria = true;
727 else
728 bCriteria = false;
731 void XclImpAutoFilterData::SetExtractPos( const ScAddress& rAddr )
733 aParam.nDestCol = rAddr.Col();
734 aParam.nDestRow = rAddr.Row();
735 aParam.nDestTab = rAddr.Tab();
736 aParam.bInplace = false;
737 aParam.bDestPers = true;
740 void XclImpAutoFilterData::Apply()
742 // Create the ScDBData() object if the AutoFilter is activated
743 // or if we need to create the Advanced Filter.
744 if( bActive || bCriteria)
746 ScDocument& rDoc = pExcRoot->pIR->GetDoc();
747 pCurrDBData = new ScDBData(STR_DB_LOCAL_NONAME, Tab(),
748 StartCol(),StartRow(), EndCol(),EndRow() );
749 if(bCriteria)
751 EnableRemoveFilter();
753 pCurrDBData->SetQueryParam( aParam );
754 pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
756 else
757 pCurrDBData->SetAdvancedQuerySource(nullptr);
758 rDoc.SetAnonymousDBData(Tab(), std::unique_ptr<ScDBData>(pCurrDBData));
761 if( bActive )
763 InsertQueryParam();
767 void XclImpAutoFilterData::EnableRemoveFilter()
769 // only if this is a saved Advanced filter
770 if( !bActive && bAutoOrAdvanced )
772 ScQueryEntry& aEntry = aParam.AppendEntry();
773 aEntry.bDoQuery = true;
776 // TBD: force the automatic activation of the
777 // "Remove Filter" by setting a virtual mouse click
778 // inside the advanced range
781 void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange)
783 if( !GetByTab( rRange.aStart.Tab() ) )
784 maFilters.push_back( std::make_shared<XclImpAutoFilterData>( pRoot, rRange ));
787 void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange& rRange )
789 XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
790 if( pData )
791 pData->SetAdvancedRange( &rRange );
794 void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
796 XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
797 if( pData )
798 pData->SetExtractPos( rRange.aStart );
801 void XclImpAutoFilterBuffer::Apply()
803 for( const auto& rFilterPtr : maFilters )
804 rFilterPtr->Apply();
807 XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
809 for( const auto& rFilterPtr : maFilters )
811 if( rFilterPtr->Tab() == nTab )
812 return rFilterPtr.get();
814 return nullptr;
817 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */