summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/excel/excimp8.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel/excimp8.cxx')
-rw-r--r--sc/source/filter/excel/excimp8.cxx817
1 files changed, 817 insertions, 0 deletions
diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx
new file mode 100644
index 000000000..d5db209a1
--- /dev/null
+++ b/sc/source/filter/excel/excimp8.cxx
@@ -0,0 +1,817 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <excimp8.hxx>
+
+#include <scitems.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <unotools/fltrcfg.hxx>
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docinf.hxx>
+#include <sot/storage.hxx>
+#include <svl/sharedstringpool.hxx>
+
+#include <rtl/math.hxx>
+#include <rtl/ustring.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+#include <document.hxx>
+#include <attrib.hxx>
+#include <dbdata.hxx>
+#include <globalnames.hxx>
+#include <docoptio.hxx>
+#include <xihelper.hxx>
+#include <xicontent.hxx>
+#include <xilink.hxx>
+#include <xiescher.hxx>
+#include <xistyle.hxx>
+#include <excdefs.hxx>
+
+#include <excform.hxx>
+#include <queryentry.hxx>
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <cppuhelper/implbase.hxx>
+#include "xltoolbar.hxx"
+#include <oox/ole/vbaproject.hxx>
+#include <oox/ole/olestorage.hxx>
+
+using namespace com::sun::star;
+using namespace ::comphelper;
+
+//OleNameOverrideContainer
+
+namespace {
+
+class OleNameOverrideContainer : public ::cppu::WeakImplHelper< container::XNameContainer >
+{
+private:
+ typedef std::unordered_map< OUString, uno::Reference< container::XIndexContainer > > NamedIndexToOleName;
+ NamedIndexToOleName IdToOleNameHash;
+ ::osl::Mutex m_aMutex;
+public:
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<container::XIndexContainer>::get(); }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return ( !IdToOleNameHash.empty() );
+ }
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !hasByName(aName) )
+ throw container::NoSuchElementException();
+ return uno::Any( IdToOleNameHash[ aName ] );
+ }
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return comphelper::mapKeysToSequence( IdToOleNameHash);
+ }
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return ( IdToOleNameHash.find( aName ) != IdToOleNameHash.end() );
+ }
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( hasByName( aName ) )
+ throw container::ElementExistException();
+ uno::Reference< container::XIndexContainer > xElement;
+ if ( ! ( aElement >>= xElement ) )
+ throw lang::IllegalArgumentException();
+ IdToOleNameHash[ aName ] = xElement;
+ }
+ virtual void SAL_CALL removeByName( const OUString& aName ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( IdToOleNameHash.erase( aName ) == 0 )
+ throw container::NoSuchElementException();
+ }
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+ uno::Reference< container::XIndexContainer > xElement;
+ if ( ! ( aElement >>= xElement ) )
+ throw lang::IllegalArgumentException();
+ IdToOleNameHash[ aName ] = xElement;
+ }
+};
+
+/** Future Record Type header.
+ @return whether read rt matches nRecordID
+ */
+bool readFrtHeader( XclImpStream& rStrm, sal_uInt16 nRecordID )
+{
+ sal_uInt16 nRt = rStrm.ReaduInt16();
+ rStrm.Ignore(10); // grbitFrt (2 bytes) and reserved (8 bytes)
+ return nRt == nRecordID;
+}
+
+}
+
+ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) :
+ ImportExcel( rImpData, rStrm )
+{
+ // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
+ pFormConv.reset(new ExcelToSc8( GetRoot() ));
+ pExcRoot->pFmlaConverter = pFormConv.get();
+}
+
+ImportExcel8::~ImportExcel8()
+{
+}
+
+void ImportExcel8::Calccount()
+{
+ ScDocOptions aOpt = rD.GetDocOptions();
+ aOpt.SetIterCount( aIn.ReaduInt16() );
+ rD.SetDocOptions( aOpt );
+}
+
+void ImportExcel8::Precision()
+{
+ ScDocOptions aOpt = rD.GetDocOptions();
+ aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 );
+ rD.SetDocOptions( aOpt );
+}
+
+void ImportExcel8::Delta()
+{
+ ScDocOptions aOpt = rD.GetDocOptions();
+ aOpt.SetIterEps( aIn.ReadDouble() );
+ rD.SetDocOptions( aOpt );
+}
+
+void ImportExcel8::Iteration()
+{
+ ScDocOptions aOpt = rD.GetDocOptions();
+ aOpt.SetIter( aIn.ReaduInt16() == 1 );
+ rD.SetDocOptions( aOpt );
+}
+
+void ImportExcel8::Boundsheet()
+{
+ sal_uInt8 nLen;
+ sal_uInt16 nGrbit;
+
+ aIn.DisableDecryption();
+ maSheetOffsets.push_back( aIn.ReaduInt32() );
+ aIn.EnableDecryption();
+ nGrbit = aIn.ReaduInt16();
+ nLen = aIn.ReaduInt8();
+
+ OUString aName( aIn.ReadUniString( nLen ) );
+ GetTabInfo().AppendXclTabName( aName, nBdshtTab );
+
+ SCTAB nScTab = nBdshtTab;
+ if( nScTab > 0 )
+ {
+ OSL_ENSURE( !rD.HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" );
+ rD.MakeTable( nScTab );
+ }
+
+ if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
+ rD.SetVisible( nScTab, false );
+
+ if( !rD.RenameTab( nScTab, aName ) )
+ {
+ rD.CreateValidTabName( aName );
+ rD.RenameTab( nScTab, aName );
+ }
+
+ nBdshtTab++;
+}
+
+void ImportExcel8::Scenman()
+{
+ sal_uInt16 nLastDispl;
+
+ aIn.Ignore( 4 );
+ nLastDispl = aIn.ReaduInt16();
+
+ maScenList.nLastScenario = nLastDispl;
+}
+
+void ImportExcel8::Scenario()
+{
+ maScenList.aEntries.push_back( std::make_unique<ExcScenario>( aIn, *pExcRoot ) );
+}
+
+void ImportExcel8::Labelsst()
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF;
+ sal_uInt32 nSst;
+
+ aIn >> aXclPos;
+ nXF = aIn.ReaduInt16();
+ nSst = aIn.ReaduInt32( );
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ GetXFRangeBuffer().SetXF( aScPos, nXF );
+ const XclImpString* pXclStr = GetSst().GetString(nSst);
+ if (pXclStr)
+ XclImpStringHelper::SetToDocument(GetDocImport(), aScPos, *this, *pXclStr, nXF);
+ }
+}
+
+void ImportExcel8::FeatHdr()
+{
+ if (!readFrtHeader( aIn, 0x0867))
+ return;
+
+ // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
+ // EXC_ISFFACTOID.
+ sal_uInt16 nFeatureType = aIn.ReaduInt16();
+ if (nFeatureType != EXC_ISFPROTECTION)
+ // We currently only support import of enhanced protection data.
+ return;
+
+ aIn.Ignore(1); // always 1
+
+ GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
+}
+
+void ImportExcel8::Feat()
+{
+ if (!readFrtHeader( aIn, 0x0868))
+ return;
+
+ // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
+ // EXC_ISFFACTOID.
+ sal_uInt16 nFeatureType = aIn.ReaduInt16();
+ if (nFeatureType != EXC_ISFPROTECTION)
+ // We currently only support import of enhanced protection data.
+ return;
+
+ aIn.Ignore(5); // reserved1 (1 byte) and reserved2 (4 bytes)
+
+ sal_uInt16 nCref = aIn.ReaduInt16(); // number of ref elements
+ aIn.Ignore(4); // size if EXC_ISFFEC2, else 0 and to be ignored
+ aIn.Ignore(2); // reserved3 (2 bytes)
+
+ ScEnhancedProtection aProt;
+ if (nCref)
+ {
+ XclRangeList aRefs;
+ aRefs.Read( aIn, true, nCref);
+ if (!aRefs.empty())
+ {
+ aProt.maRangeList = new ScRangeList;
+ GetAddressConverter().ConvertRangeList( *aProt.maRangeList, aRefs, GetCurrScTab(), false);
+ }
+ }
+
+ // FeatProtection structure follows in record.
+
+ aProt.mnAreserved = aIn.ReaduInt32();
+ aProt.mnPasswordVerifier = aIn.ReaduInt32();
+ aProt.maTitle = aIn.ReadUniString();
+ if ((aProt.mnAreserved & 0x00000001) == 0x00000001)
+ {
+ sal_uInt32 nCbSD = aIn.ReaduInt32();
+ // TODO: could here be some sanity check applied to not allocate 4GB?
+ aProt.maSecurityDescriptor.resize( nCbSD);
+ std::size_t nRead = aIn.Read(aProt.maSecurityDescriptor.data(), nCbSD);
+ if (nRead < nCbSD)
+ aProt.maSecurityDescriptor.resize( nRead);
+ }
+
+ GetSheetProtectBuffer().AppendEnhancedProtection( aProt, GetCurrScTab() );
+}
+
+void ImportExcel8::ReadBasic()
+{
+ SfxObjectShell* pShell = GetDocShell();
+ tools::SvRef<SotStorage> xRootStrg = GetRootStorage();
+ const SvtFilterOptions& rFilterOpt = SvtFilterOptions::Get();
+ if( !pShell || !xRootStrg.is() )
+ return;
+
+ try
+ {
+ // #FIXME need to get rid of this, we can also do this from within oox
+ // via the "ooo.vba.VBAGlobals" service
+ if( ( rFilterOpt.IsLoadExcelBasicCode() ||
+ rFilterOpt.IsLoadExcelBasicStorage() ) &&
+ rFilterOpt.IsLoadExcelBasicExecutable() )
+ {
+ // see if we have the XCB stream
+ tools::SvRef<SotStorageStream> xXCB = xRootStrg->OpenSotStream( "XCB", StreamMode::STD_READ );
+ if ( xXCB.is()|| ERRCODE_NONE == xXCB->GetError() )
+ {
+ ScCTBWrapper wrapper;
+ if ( wrapper.Read( *xXCB ) )
+ {
+#ifdef DEBUG_SC_EXCEL
+ wrapper.Print( stderr );
+#endif
+ wrapper.ImportCustomToolBar( *pShell );
+ }
+ }
+ }
+ try
+ {
+ uno::Reference< uno::XComponentContext > aCtx( ::comphelper::getProcessComponentContext() );
+ SfxMedium& rMedium = GetMedium();
+ uno::Reference< io::XInputStream > xIn = rMedium.GetInputStream();
+ oox::ole::OleStorage root( aCtx, xIn, false );
+ oox::StorageRef vbaStg = root.openSubStorage( "_VBA_PROJECT_CUR", false );
+ if ( vbaStg )
+ {
+ oox::ole::VbaProject aVbaPrj( aCtx, pShell->GetModel(), u"Calc" );
+ // collect names of embedded form controls, as specified in the VBA project
+ uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer );
+ aVbaPrj.setOleOverridesSink( xOleNameOverrideSink );
+ aVbaPrj.importVbaProject( *vbaStg );
+ GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink );
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void ImportExcel8::EndSheet()
+{
+ ImportExcel::EndSheet();
+ GetCondFormatManager().Apply();
+ GetValidationManager().Apply();
+}
+
+void ImportExcel8::PostDocLoad()
+{
+#if HAVE_FEATURE_SCRIPTING
+ // reading basic has been delayed until sheet objects (codenames etc.) are read
+ if( HasBasic() )
+ ReadBasic();
+#endif
+ // #i11776# filtered ranges before outlines and hidden rows
+ if( pExcRoot->pAutoFilterBuffer )
+ pExcRoot->pAutoFilterBuffer->Apply();
+
+ GetWebQueryBuffer().Apply(); //TODO: test if extant
+ GetSheetProtectBuffer().Apply();
+ GetDocProtectBuffer().Apply();
+
+ ImportExcel::PostDocLoad();
+
+ // check scenarios; Attention: This increases the table count of the document!!
+ if( !rD.IsClipboard() && !maScenList.aEntries.empty() )
+ {
+ rD.UpdateChartListenerCollection(); // references in charts must be updated
+
+ maScenList.Apply( GetRoot() );
+ }
+
+ // read doc info (no docshell while pasting from clipboard)
+ SfxObjectShell* pShell = GetDocShell();
+ if(!pShell)
+ return;
+
+ // BIFF5+ without storage is possible
+ tools::SvRef<SotStorage> xRootStrg = GetRootStorage();
+ if( xRootStrg.is() ) try
+ {
+ uno::Reference< document::XDocumentPropertiesSupplier > xDPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< document::XDocumentProperties > xDocProps( xDPS->getDocumentProperties(), uno::UNO_SET_THROW );
+ sfx2::LoadOlePropertySet( xDocProps, xRootStrg.get() );
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
+ // when formula cells are calculated, for the GETPIVOTDATA function.
+}
+
+// autofilter
+
+void ImportExcel8::FilterMode()
+{
+ // The FilterMode record exists: if either the AutoFilter
+ // record exists or an Advanced Filter is saved and stored
+ // in the sheet. Thus if the FilterMode records only exists
+ // then the latter is true...
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ pData->SetAutoOrAdvanced();
+}
+
+void ImportExcel8::AutoFilterInfo()
+{
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ {
+ pData->SetAdvancedRange( nullptr );
+ pData->Activate();
+ }
+}
+
+void ImportExcel8::AutoFilter()
+{
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ pData->ReadAutoFilter(aIn, GetDoc().GetSharedStringPool());
+}
+
+XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
+ ExcRoot( pRoot ),
+ pCurrDBData(nullptr),
+ bActive( false ),
+ bCriteria( false ),
+ bAutoOrAdvanced(false)
+{
+ aParam.nCol1 = rRange.aStart.Col();
+ aParam.nRow1 = rRange.aStart.Row();
+ aParam.nTab = rRange.aStart.Tab();
+ aParam.nCol2 = rRange.aEnd.Col();
+ aParam.nRow2 = rRange.aEnd.Row();
+
+ aParam.bInplace = true;
+
+}
+
+namespace {
+
+OUString CreateFromDouble( double fVal )
+{
+ return rtl::math::doubleToUString(fVal,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
+}
+
+}
+
+void XclImpAutoFilterData::SetCellAttribs()
+{
+ ScDocument& rDoc = pExcRoot->pIR->GetDoc();
+ for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ )
+ {
+ ScMF nFlag = rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | ScMF::Auto) );
+ }
+}
+
+void XclImpAutoFilterData::InsertQueryParam()
+{
+ if (!pCurrDBData)
+ return;
+
+ ScRange aAdvRange;
+ bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
+ if( bHasAdv )
+ pExcRoot->pIR->GetDoc().CreateQueryParam(aAdvRange, aParam);
+
+ pCurrDBData->SetQueryParam( aParam );
+ if( bHasAdv )
+ pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
+ else
+ {
+ pCurrDBData->SetAutoFilter( true );
+ SetCellAttribs();
+ }
+}
+
+static void ExcelQueryToOooQuery( OUString& aStr, ScQueryEntry& rEntry )
+{
+ if (rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL)
+ return;
+
+ sal_Int32 nLen = aStr.getLength();
+ sal_Unicode nStart = aStr[0];
+ sal_Unicode nEnd = aStr[ nLen-1 ];
+ if( nLen > 2 && nStart == '*' && nEnd == '*' )
+ {
+ aStr = aStr.copy( 1, nLen-2 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN;
+ }
+ else if( nLen > 1 && nStart == '*' && nEnd != '*' )
+ {
+ aStr = aStr.copy( 1 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH;
+ }
+ else if( nLen > 1 && nStart != '*' && nEnd == '*' )
+ {
+ aStr = aStr.copy( 0, nLen-1 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH;
+ }
+ else if( nLen == 2 && nStart == '*' && nEnd == '*' )
+ {
+ aStr = aStr.copy( 1 );
+ }
+}
+
+void XclImpAutoFilterData::ReadAutoFilter(
+ XclImpStream& rStrm, svl::SharedStringPool& rPool )
+{
+ sal_uInt16 nCol, nFlags;
+ nCol = rStrm.ReaduInt16();
+ nFlags = rStrm.ReaduInt16();
+
+ ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND );
+ bool bSimple1 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE1);
+ bool bSimple2 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE2);
+ bool bTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10);
+ bool bTopOfTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10TOP);
+ bool bPercent = ::get_flag(nFlags, EXC_AFFLAG_TOP10PERC);
+ sal_uInt16 nCntOfTop10 = nFlags >> 7;
+
+ if( bTop10 )
+ {
+ ScQueryEntry& aEntry = aParam.AppendEntry();
+ ScQueryEntry::Item& rItem = aEntry.GetQueryItem();
+ aEntry.bDoQuery = true;
+ aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
+ aEntry.eOp = bTopOfTop10 ?
+ (bPercent ? SC_TOPPERC : SC_TOPVAL) : (bPercent ? SC_BOTPERC : SC_BOTVAL);
+ aEntry.eConnect = SC_AND;
+
+ rItem.meType = ScQueryEntry::ByString;
+ rItem.maString = rPool.intern(OUString::number(nCntOfTop10));
+
+ rStrm.Ignore(20);
+ return;
+ }
+
+ sal_uInt8 nType, nOper, nBoolErr, nVal;
+ sal_Int32 nRK;
+ double fVal;
+
+ sal_uInt8 nStrLen[2] = { 0, 0 };
+ ScQueryEntry aEntries[2];
+
+ for (size_t nE = 0; nE < 2; ++nE)
+ {
+ ScQueryEntry& rEntry = aEntries[nE];
+ ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ bool bIgnore = false;
+
+ nType = rStrm.ReaduInt8();
+ nOper = rStrm.ReaduInt8();
+ switch( nOper )
+ {
+ case EXC_AFOPER_LESS:
+ rEntry.eOp = SC_LESS;
+ break;
+ case EXC_AFOPER_EQUAL:
+ rEntry.eOp = SC_EQUAL;
+ break;
+ case EXC_AFOPER_LESSEQUAL:
+ rEntry.eOp = SC_LESS_EQUAL;
+ break;
+ case EXC_AFOPER_GREATER:
+ rEntry.eOp = SC_GREATER;
+ break;
+ case EXC_AFOPER_NOTEQUAL:
+ rEntry.eOp = SC_NOT_EQUAL;
+ break;
+ case EXC_AFOPER_GREATEREQUAL:
+ rEntry.eOp = SC_GREATER_EQUAL;
+ break;
+ default:
+ rEntry.eOp = SC_EQUAL;
+ }
+
+ switch( nType )
+ {
+ case EXC_AFTYPE_RK:
+ nRK = rStrm.ReadInt32();
+ rStrm.Ignore( 4 );
+ rItem.maString = rPool.intern(
+ CreateFromDouble(XclTools::GetDoubleFromRK(nRK)));
+ break;
+ case EXC_AFTYPE_DOUBLE:
+ fVal = rStrm.ReadDouble();
+ rItem.maString = rPool.intern(CreateFromDouble(fVal));
+ break;
+ case EXC_AFTYPE_STRING:
+ rStrm.Ignore( 4 );
+ nStrLen[ nE ] = rStrm.ReaduInt8();
+ rStrm.Ignore( 3 );
+ rItem.maString = svl::SharedString();
+ break;
+ case EXC_AFTYPE_BOOLERR:
+ nBoolErr = rStrm.ReaduInt8();
+ nVal = rStrm.ReaduInt8();
+ rStrm.Ignore( 6 );
+ rItem.maString = rPool.intern(OUString::number(nVal));
+ bIgnore = (nBoolErr != 0);
+ break;
+ case EXC_AFTYPE_EMPTY:
+ rEntry.SetQueryByEmpty();
+ break;
+ case EXC_AFTYPE_NOTEMPTY:
+ rEntry.SetQueryByNonEmpty();
+ break;
+ default:
+ rStrm.Ignore( 8 );
+ bIgnore = true;
+ }
+
+ if (!bIgnore)
+ {
+ rEntry.bDoQuery = true;
+ rItem.meType = ScQueryEntry::ByString;
+ rEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
+ rEntry.eConnect = nE ? eConn : SC_AND;
+ }
+ }
+
+ if (eConn == SC_AND)
+ {
+ for (size_t nE = 0; nE < 2; ++nE)
+ {
+ if (nStrLen[nE] && aEntries[nE].bDoQuery)
+ {
+ OUString aStr = rStrm.ReadUniString(nStrLen[nE]);
+ ExcelQueryToOooQuery(aStr, aEntries[nE]);
+ aEntries[nE].GetQueryItem().maString = rPool.intern(aStr);
+ aParam.AppendEntry() = aEntries[nE];
+ }
+ }
+ }
+ else
+ {
+ assert( eConn == SC_OR && "eConn should be SC_AND or SC_OR");
+ // Import only when both conditions are for simple equality, else
+ // import only the 1st condition due to conflict with the ordering of
+ // conditions. #i39464#.
+ //
+ // Example: Let A1 be a condition of column A, and B1 and B2
+ // conditions of column B, connected with OR. Excel performs 'A1 AND
+ // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
+ // instead.
+
+ if (bSimple1 && bSimple2 && nStrLen[0] && nStrLen[1])
+ {
+ // Two simple OR'ed equal conditions. We can import this correctly.
+ ScQueryEntry& rEntry = aParam.AppendEntry();
+ rEntry.bDoQuery = true;
+ rEntry.eOp = SC_EQUAL;
+ rEntry.eConnect = SC_AND;
+ ScQueryEntry::QueryItemsType aItems;
+ aItems.reserve(2);
+ ScQueryEntry::Item aItem1, aItem2;
+ aItem1.maString = rPool.intern(rStrm.ReadUniString(nStrLen[0]));
+ aItem1.meType = ScQueryEntry::ByString;
+ aItem2.maString = rPool.intern(rStrm.ReadUniString(nStrLen[1]));
+ aItem2.meType = ScQueryEntry::ByString;
+ aItems.push_back(aItem1);
+ aItems.push_back(aItem2);
+ rEntry.GetQueryItems().swap(aItems);
+ }
+ else if (nStrLen[0] && aEntries[0].bDoQuery)
+ {
+ // Due to conflict, we can import only the first condition.
+ OUString aStr = rStrm.ReadUniString(nStrLen[0]);
+ ExcelQueryToOooQuery(aStr, aEntries[0]);
+ aEntries[0].GetQueryItem().maString = rPool.intern(aStr);
+ aParam.AppendEntry() = aEntries[0];
+ }
+ }
+}
+
+void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange )
+{
+ if (pRange)
+ {
+ aCriteriaRange = *pRange;
+ bCriteria = true;
+ }
+ else
+ bCriteria = false;
+}
+
+void XclImpAutoFilterData::SetExtractPos( const ScAddress& rAddr )
+{
+ aParam.nDestCol = rAddr.Col();
+ aParam.nDestRow = rAddr.Row();
+ aParam.nDestTab = rAddr.Tab();
+ aParam.bInplace = false;
+ aParam.bDestPers = true;
+}
+
+void XclImpAutoFilterData::Apply()
+{
+ // Create the ScDBData() object if the AutoFilter is activated
+ // or if we need to create the Advanced Filter.
+ if( bActive || bCriteria)
+ {
+ ScDocument& rDoc = pExcRoot->pIR->GetDoc();
+ pCurrDBData = new ScDBData(STR_DB_LOCAL_NONAME, Tab(),
+ StartCol(),StartRow(), EndCol(),EndRow() );
+ if(bCriteria)
+ {
+ EnableRemoveFilter();
+
+ pCurrDBData->SetQueryParam( aParam );
+ pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
+ }
+ else
+ pCurrDBData->SetAdvancedQuerySource(nullptr);
+ rDoc.SetAnonymousDBData(Tab(), std::unique_ptr<ScDBData>(pCurrDBData));
+ }
+
+ if( bActive )
+ {
+ InsertQueryParam();
+ }
+}
+
+void XclImpAutoFilterData::EnableRemoveFilter()
+{
+ // only if this is a saved Advanced filter
+ if( !bActive && bAutoOrAdvanced )
+ {
+ ScQueryEntry& aEntry = aParam.AppendEntry();
+ aEntry.bDoQuery = true;
+ }
+
+ // TBD: force the automatic activation of the
+ // "Remove Filter" by setting a virtual mouse click
+ // inside the advanced range
+}
+
+void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange)
+{
+ if( !GetByTab( rRange.aStart.Tab() ) )
+ maFilters.push_back( std::make_shared<XclImpAutoFilterData>( pRoot, rRange ));
+}
+
+void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange& rRange )
+{
+ XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
+ if( pData )
+ pData->SetAdvancedRange( &rRange );
+}
+
+void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
+{
+ XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
+ if( pData )
+ pData->SetExtractPos( rRange.aStart );
+}
+
+void XclImpAutoFilterBuffer::Apply()
+{
+ for( const auto& rFilterPtr : maFilters )
+ rFilterPtr->Apply();
+}
+
+XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
+{
+ for( const auto& rFilterPtr : maFilters )
+ {
+ if( rFilterPtr->Tab() == nTab )
+ return rFilterPtr.get();
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */