diff options
Diffstat (limited to 'sc/source/filter/excel/excimp8.cxx')
-rw-r--r-- | sc/source/filter/excel/excimp8.cxx | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx new file mode 100644 index 000000000000..a1bbe57dbc0c --- /dev/null +++ b/sc/source/filter/excel/excimp8.cxx @@ -0,0 +1,859 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "excimp8.hxx" + +#include <scitems.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <unotools/fltrcfg.hxx> + +#include <svtools/wmf.hxx> + +#include <editeng/eeitem.hxx> + +#include <sfx2/docfile.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/request.hxx> +#include <sfx2/app.hxx> +#include <sfx2/docinf.hxx> +#include <sfx2/frame.hxx> + +#include <editeng/brshitem.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editobj.hxx> +#include <editeng/editstat.hxx> +#include <editeng/colritem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/flditem.hxx> +#include <svx/xflclit.hxx> + +#include <vcl/graph.hxx> +#include <vcl/bmpacc.hxx> +#include <sot/exchange.hxx> + +#include <svl/stritem.hxx> + +#include <tools/string.hxx> +#include <tools/urlobj.hxx> +#include <rtl/math.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/charclass.hxx> +#include <drwlayer.hxx> + +#include <boost/scoped_array.hpp> + +#include "cell.hxx" +#include "document.hxx" +#include "patattr.hxx" +#include "docpool.hxx" +#include "attrib.hxx" +#include "conditio.hxx" +#include "dbcolect.hxx" +#include "globalnames.hxx" +#include "editutil.hxx" +#include "markdata.hxx" +#include "rangenam.hxx" +#include "docoptio.hxx" +#include "globstr.hrc" +#include "fprogressbar.hxx" +#include "xltracer.hxx" +#include "xihelper.hxx" +#include "xipage.hxx" +#include "xicontent.hxx" +#include "xilink.hxx" +#include "xiescher.hxx" +#include "xipivot.hxx" + +#include "excform.hxx" +#include "scextopt.hxx" +#include "stlpool.hxx" +#include "stlsheet.hxx" +#include "detfunc.hxx" +#include "macromgr.hxx" + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <comphelper/mediadescriptor.hxx> +#include <cppuhelper/component_context.hxx> +#include <sfx2/app.hxx> +#include "xltoolbar.hxx" + + +using namespace com::sun::star; +using namespace ::comphelper; +using ::rtl::OUString; + +//OleNameOverrideContainer + +typedef ::cppu::WeakImplHelper1< container::XNameContainer > OleNameOverrideContainer_BASE; + +class OleNameOverrideContainer : public OleNameOverrideContainer_BASE +{ +private: + typedef boost::unordered_map< rtl::OUString, uno::Reference< container::XIndexContainer >, ::rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > > NamedIndexToOleName; + NamedIndexToOleName IdToOleNameHash; + ::osl::Mutex m_aMutex; +public: + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) { return container::XIndexContainer::static_type(0); } + virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return ( IdToOleNameHash.size() > 0 ); + } + // XNameAcess + virtual uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !hasByName(aName) ) + throw container::NoSuchElementException(); + return uno::makeAny( IdToOleNameHash[ aName ] ); + } + virtual uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + uno::Sequence< ::rtl::OUString > aResult( IdToOleNameHash.size() ); + NamedIndexToOleName::iterator it = IdToOleNameHash.begin(); + NamedIndexToOleName::iterator it_end = IdToOleNameHash.end(); + rtl::OUString* pName = aResult.getArray(); + for (; it != it_end; ++it, ++pName ) + *pName = it->first; + return aResult; + } + virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return ( IdToOleNameHash.find( aName ) != IdToOleNameHash.end() ); + } + + // XElementAccess + virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return IdToOleNameHash.size(); + } + // XNameContainer + virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, uno::RuntimeException) + { + ::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 ::rtl::OUString& aName ) throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + IdToOleNameHash.erase( IdToOleNameHash.find( aName ) ); + } + virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) + { + ::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; + } +}; + +// defined in docfunc.cxx ( really this needs a new name ) +script::ModuleInfo lcl_InitModuleInfo( SfxObjectShell& rDocSh, String& sModule ); + +ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) : + ImportExcel( rImpData, rStrm ) +{ + // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer + delete pFormConv; + pFormConv = pExcRoot->pFmlaConverter = new ExcelToSc8( GetRoot() ); +} + + +ImportExcel8::~ImportExcel8() +{ +} + + +void ImportExcel8::Calccount( void ) +{ + ScDocOptions aOpt = pD->GetDocOptions(); + aOpt.SetIterCount( aIn.ReaduInt16() ); + pD->SetDocOptions( aOpt ); +} + + +void ImportExcel8::Precision( void ) +{ + ScDocOptions aOpt = pD->GetDocOptions(); + aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 ); + pD->SetDocOptions( aOpt ); +} + + +void ImportExcel8::Delta( void ) +{ + ScDocOptions aOpt = pD->GetDocOptions(); + aOpt.SetIterEps( aIn.ReadDouble() ); + pD->SetDocOptions( aOpt ); +} + + +void ImportExcel8::Iteration( void ) +{ + ScDocOptions aOpt = pD->GetDocOptions(); + aOpt.SetIter( aIn.ReaduInt16() == 1 ); + pD->SetDocOptions( aOpt ); +} + + +void ImportExcel8::Boundsheet( void ) +{ + sal_uInt8 nLen; + sal_uInt16 nGrbit; + + aIn.DisableDecryption(); + maSheetOffsets.push_back( aIn.ReaduInt32() ); + aIn.EnableDecryption(); + aIn >> nGrbit >> nLen; + + String aName( aIn.ReadUniString( nLen ) ); + GetTabInfo().AppendXclTabName( aName, nBdshtTab ); + + SCTAB nScTab = static_cast< SCTAB >( nBdshtTab ); + if( nScTab > 0 ) + { + DBG_ASSERT( !pD->HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" ); + pD->MakeTable( nScTab ); + } + + if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) ) + pD->SetVisible( nScTab, false ); + + if( !pD->RenameTab( nScTab, aName ) ) + { + pD->CreateValidTabName( aName ); + pD->RenameTab( nScTab, aName ); + } + + nBdshtTab++; +} + + +void ImportExcel8::Scenman( void ) +{ + sal_uInt16 nLastDispl; + + aIn.Ignore( 4 ); + aIn >> nLastDispl; + + aScenList.nLastScenario = nLastDispl; +} + + +void ImportExcel8::Scenario( void ) +{ + aScenList.aEntries.push_back( new ExcScenario( aIn, *pExcRoot ) ); +} + + +void ImportExcel8::Labelsst( void ) +{ + XclAddress aXclPos; + sal_uInt16 nXF; + sal_uInt32 nSst; + + aIn >> aXclPos >> nXF >> nSst; + + ScAddress aScPos( ScAddress::UNINITIALIZED ); + if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) ) + { + GetXFRangeBuffer().SetXF( aScPos, nXF ); + if( ScBaseCell* pCell = GetSst().CreateCell( nSst, nXF ) ) + GetDoc().PutCell( aScPos.Col(), aScPos.Row(), aScPos.Tab(), pCell ); + } +} + + +void ImportExcel8::SheetProtection( void ) +{ + GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() ); +} + +void ImportExcel8::ReadBasic( void ) +{ + SfxObjectShell* pShell = GetDocShell(); + SotStorageRef xRootStrg = GetRootStorage(); + SvtFilterOptions* pFilterOpt = SvtFilterOptions::Get(); + if( pShell && xRootStrg.Is() ) try + { + bool bLoadCode = pFilterOpt->IsLoadExcelBasicCode(); + bool bLoadExecutable = pFilterOpt->IsLoadExcelBasicExecutable(); + bool bLoadStrg = pFilterOpt->IsLoadExcelBasicStorage(); + // #FIXME need to get rid of this, we can also do this from within oox + // via the "ooo.vba.VBAGlobals" service + if( bLoadCode || bLoadStrg ) + { + bool bAsComment = !bLoadExecutable; + + if ( !bAsComment ) + { + // see if we have the XCB stream + SvStorageStreamRef xXCB = xRootStrg->OpenSotStream( String( RTL_CONSTASCII_USTRINGPARAM( "XCB" ) ), STREAM_STD_READ | STREAM_NOCREATE ); + if ( xXCB.Is()|| SVSTREAM_OK == xXCB->GetError() ) + { + CTBWrapper wrapper; + if ( wrapper.Read( xXCB ) ) + { +#if OSL_DEBUG_LEVEL > 1 + wrapper.Print( stderr ); +#endif + wrapper.ImportCustomToolBar( *pShell ); + } + } + } + } + try + { + uno::Reference< lang::XComponent > xComponent( pShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Sequence< beans::NamedValue > aArgSeq( 1 ); + + // collect names of embedded form controls, as specified in the VBA project + aArgSeq[ 0 ].Name = CREATE_OUSTRING( "OleNameOverrideInfo" ); + uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer ); + aArgSeq[ 0 ].Value <<= xOleNameOverrideSink; + + uno::Sequence< uno::Any > aArgs( 2 ); + // framework calls filter objects with factory as first argument + aArgs[ 0 ] <<= getProcessServiceFactory(); + aArgs[ 1 ] <<= aArgSeq; + + uno::Reference< document::XImporter > xImporter( ScfApiHelper::CreateInstanceWithArgs( CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelVbaProjectFilter" ), aArgs ), uno::UNO_QUERY_THROW ); + xImporter->setTargetDocument( xComponent ); + + MediaDescriptor aMediaDesc; + SfxMedium& rMedium = GetMedium(); + SfxItemSet* pItemSet = rMedium.GetItemSet(); + if( pItemSet ) + { + if( const SfxStringItem* pItem = static_cast< const SfxStringItem* >( pItemSet->GetItem( SID_FILE_NAME ) ) ) + aMediaDesc[ MediaDescriptor::PROP_URL() ] <<= ::rtl::OUString( pItem->GetValue() ); + if( const SfxStringItem* pItem = static_cast< const SfxStringItem* >( pItemSet->GetItem( SID_PASSWORD ) ) ) + aMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= ::rtl::OUString( pItem->GetValue() ); + } + aMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ] <<= rMedium.GetInputStream(); + aMediaDesc[ MediaDescriptor::PROP_INTERACTIONHANDLER() ] <<= rMedium.GetInteractionHandler(); + + // call the filter + uno::Reference< document::XFilter > xFilter( xImporter, uno::UNO_QUERY_THROW ); + xFilter->filter( aMediaDesc.getAsConstPropertyValueList() ); + GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink ); + } + catch( uno::Exception& ) + { + } + } + catch( uno::Exception& ) + { + } +} + + +void ImportExcel8::EndSheet( void ) +{ + ImportExcel::EndSheet(); + GetCondFormatManager().Apply(); + GetValidationManager().Apply(); +} + + +void ImportExcel8::PostDocLoad( void ) +{ + // reading basic has been delayed until sheet objects (codenames etc.) are read + if( HasBasic() ) + ReadBasic(); + // #i11776# filtered ranges before outlines and hidden rows + if( pExcRoot->pAutoFilterBuffer ) + pExcRoot->pAutoFilterBuffer->Apply(); + + GetWebQueryBuffer().Apply(); //! test if extant + GetSheetProtectBuffer().Apply(); + GetDocProtectBuffer().Apply(); + + ImportExcel::PostDocLoad(); + + // Scenarien bemachen! ACHTUNG: Hier wird Tabellen-Anzahl im Dokument erhoeht!! + if( !pD->IsClipboard() && aScenList.aEntries.size() ) + { + pD->UpdateChartListenerCollection(); // references in charts must be updated + + aScenList.Apply( GetRoot() ); + } + + // read doc info (no docshell while pasting from clipboard) + LoadDocumentProperties(); + + // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available + // when formula cells are calculated, for the GETPIVOTDATA function. +} + +void ImportExcel8::LoadDocumentProperties() +{ + // no docshell while pasting from clipboard + if( SfxObjectShell* pShell = GetDocShell() ) + { + // BIFF5+ without storage is possible + SotStorageRef 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 ); + } + catch( uno::Exception& ) + { + } + } +} + +//___________________________________________________________________ +// autofilter + +void ImportExcel8::FilterMode( void ) +{ + // 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( void ) +{ + if( !pExcRoot->pAutoFilterBuffer ) return; + + XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() ); + if( pData ) + { + pData->SetAdvancedRange( NULL ); + pData->Activate(); + } +} + +void ImportExcel8::AutoFilter( void ) +{ + if( !pExcRoot->pAutoFilterBuffer ) return; + + XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() ); + if( pData ) + pData->ReadAutoFilter( aIn ); +} + + + +XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) : + ExcRoot( pRoot ), + pCurrDBData(NULL), + nFirstEmpty( 0 ), + bActive( false ), + bHasConflict( 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 = sal_True; + +} + +void XclImpAutoFilterData::CreateFromDouble( String& rStr, double fVal ) +{ + rStr += String( ::rtl::math::doubleToUString( fVal, + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0), sal_True)); +} + +void XclImpAutoFilterData::SetCellAttribs() +{ + ScDocument& rDoc = pExcRoot->pIR->GetDoc(); + for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ ) + { + sal_Int16 nFlag = ((ScMergeFlagAttr*) rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG ))->GetValue(); + rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | SC_MF_AUTO) ); + } +} + +void XclImpAutoFilterData::InsertQueryParam() +{ + if( pCurrDBData && !bHasConflict ) + { + ScRange aAdvRange; + sal_Bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange ); + if( bHasAdv ) + pExcRoot->pIR->GetDoc().CreateQueryParam( aAdvRange.aStart.Col(), + aAdvRange.aStart.Row(), aAdvRange.aEnd.Col(), aAdvRange.aEnd.Row(), + aAdvRange.aStart.Tab(), aParam ); + + pCurrDBData->SetQueryParam( aParam ); + if( bHasAdv ) + pCurrDBData->SetAdvancedQuerySource( &aAdvRange ); + else + { + pCurrDBData->SetAutoFilter( sal_True ); + SetCellAttribs(); + } + } +} + +static void ExcelQueryToOooQuery( ScQueryEntry& rEntry ) +{ + if( ( rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL ) || rEntry.pStr == NULL ) + return; + else + { + xub_StrLen nLen = rEntry.pStr->Len(); + sal_Unicode nStart = rEntry.pStr->GetChar( 0 ); + sal_Unicode nEnd = rEntry.pStr->GetChar( nLen-1 ); + if( nLen >2 && nStart == '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( nLen-1, 1 ); + rEntry.pStr->Erase( 0, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN; + } + else if( nLen > 1 && nStart == '*' && nEnd != '*' ) + { + rEntry.pStr->Erase( 0, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH; + } + else if( nLen > 1 && nStart != '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( nLen-1, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH; + } + else if( nLen == 2 && nStart == '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( 0, 1 ); + } + } +} + +void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm ) +{ + sal_uInt16 nCol, nFlags; + rStrm >> nCol >> nFlags; + + ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND ); + sal_Bool bTop10 = ::get_flag( nFlags, EXC_AFFLAG_TOP10 ); + sal_Bool bTopOfTop10 = ::get_flag( nFlags, EXC_AFFLAG_TOP10TOP ); + sal_Bool bPercent = ::get_flag( nFlags, EXC_AFFLAG_TOP10PERC ); + sal_uInt16 nCntOfTop10 = nFlags >> 7; + SCSIZE nCount = aParam.GetEntryCount(); + + if( bTop10 ) + { + if( nFirstEmpty < nCount ) + { + ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty ); + aEntry.bDoQuery = sal_True; + aEntry.bQueryByString = sal_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; + aEntry.pStr->Assign( String::CreateFromInt32( (sal_Int32) nCntOfTop10 ) ); + + rStrm.Ignore( 20 ); + nFirstEmpty++; + } + } + else + { + sal_uInt8 nE, nType, nOper, nBoolErr, nVal; + sal_Int32 nRK; + double fVal; + sal_Bool bIgnore; + + sal_uInt8 nStrLen[ 2 ] = { 0, 0 }; + ScQueryEntry *pQueryEntries[ 2 ] = { NULL, NULL }; + + for( nE = 0; nE < 2; nE++ ) + { + if( nFirstEmpty < nCount ) + { + ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty ); + pQueryEntries[ nE ] = &aEntry; + bIgnore = false; + + rStrm >> nType >> nOper; + switch( nOper ) + { + case EXC_AFOPER_LESS: + aEntry.eOp = SC_LESS; + break; + case EXC_AFOPER_EQUAL: + aEntry.eOp = SC_EQUAL; + break; + case EXC_AFOPER_LESSEQUAL: + aEntry.eOp = SC_LESS_EQUAL; + break; + case EXC_AFOPER_GREATER: + aEntry.eOp = SC_GREATER; + break; + case EXC_AFOPER_NOTEQUAL: + aEntry.eOp = SC_NOT_EQUAL; + break; + case EXC_AFOPER_GREATEREQUAL: + aEntry.eOp = SC_GREATER_EQUAL; + break; + default: + aEntry.eOp = SC_EQUAL; + } + + switch( nType ) + { + case EXC_AFTYPE_RK: + rStrm >> nRK; + rStrm.Ignore( 4 ); + CreateFromDouble( *aEntry.pStr, XclTools::GetDoubleFromRK( nRK ) ); + break; + case EXC_AFTYPE_DOUBLE: + rStrm >> fVal; + CreateFromDouble( *aEntry.pStr, fVal ); + break; + case EXC_AFTYPE_STRING: + rStrm.Ignore( 4 ); + rStrm >> nStrLen[ nE ]; + rStrm.Ignore( 3 ); + aEntry.pStr->Erase(); + break; + case EXC_AFTYPE_BOOLERR: + rStrm >> nBoolErr >> nVal; + rStrm.Ignore( 6 ); + aEntry.pStr->Assign( String::CreateFromInt32( (sal_Int32) nVal ) ); + bIgnore = (sal_Bool) nBoolErr; + break; + case EXC_AFTYPE_EMPTY: + aEntry.bQueryByString = false; + aEntry.nVal = SC_EMPTYFIELDS; + aEntry.eOp = SC_EQUAL; + break; + case EXC_AFTYPE_NOTEMPTY: + aEntry.bQueryByString = false; + aEntry.nVal = SC_NONEMPTYFIELDS; + aEntry.eOp = SC_EQUAL; + break; + default: + rStrm.Ignore( 8 ); + bIgnore = sal_True; + } + + /* #i39464# conflict, if two conditions of one column are 'OR'ed, + and they follow conditions of other columns. + 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( (nFirstEmpty > 1) && nE && (eConn == SC_OR) && !bIgnore ) + bHasConflict = sal_True; + if( !bHasConflict && !bIgnore ) + { + aEntry.bDoQuery = sal_True; + aEntry.bQueryByString = sal_True; + aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol)); + aEntry.eConnect = nE ? eConn : SC_AND; + nFirstEmpty++; + } + } + else + rStrm.Ignore( 10 ); + } + + for( nE = 0; nE < 2; nE++ ) + if( nStrLen[ nE ] && pQueryEntries[ nE ] ) + { + pQueryEntries[ nE ]->pStr->Assign ( rStrm.ReadUniString( nStrLen[ nE ] ) ); + ExcelQueryToOooQuery( *pQueryEntries[ nE ] ); + } + + } +} + +void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange ) +{ + if (pRange) + { + aCriteriaRange = *pRange; + bCriteria = sal_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 = sal_True; +} + +void XclImpAutoFilterData::Apply() +{ + CreateScDBData(); + + if( bActive ) + { + InsertQueryParam(); + + // #i38093# rows hidden by filter need extra flag, but CR_FILTERED is not set here yet +// SCROW nRow1 = StartRow(); +// SCROW nRow2 = EndRow(); +// size_t nRows = nRow2 - nRow1 + 1; +// boost::scoped_array<sal_uInt8> pFlags( new sal_uInt8[nRows]); +// pExcRoot->pDoc->GetRowFlagsArray( Tab()).FillDataArray( nRow1, nRow2, +// pFlags.get()); +// for (size_t j=0; j<nRows; ++j) +// { +// if ((pFlags[j] & CR_HIDDEN) && !(pFlags[j] & CR_FILTERED)) +// pExcRoot->pDoc->SetRowFlags( nRow1 + j, Tab(), +// pFlags[j] | CR_FILTERED ); +// } + } +} + +void XclImpAutoFilterData::CreateScDBData() +{ + + // Create the ScDBData() object if the AutoFilter is activated + // or if we need to create the Advanced Filter. + if( bActive || bCriteria) + { + ScDocument* pDoc = pExcRoot->pIR->GetDocPtr(); + String aNewName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(STR_DB_LOCAL_NONAME)); + pCurrDBData = new ScDBData(aNewName , Tab(), + StartCol(),StartRow(), EndCol(),EndRow() ); + if(bCriteria) + { + EnableRemoveFilter(); + + pCurrDBData->SetQueryParam( aParam ); + pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange); + } + else + pCurrDBData->SetAdvancedQuerySource(NULL); + pDoc->SetAnonymousDBData(Tab(), pCurrDBData); + } + +} + +void XclImpAutoFilterData::EnableRemoveFilter() +{ + // only if this is a saved Advanced filter + if( !bActive && bAutoOrAdvanced ) + { + ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty ); + aEntry.bDoQuery = sal_True; + ++nFirstEmpty; + } + + // TBD: force the automatic activation of the + // "Remove Filter" by setting a virtual mouse click + // inside the advanced range +} + +XclImpAutoFilterBuffer::XclImpAutoFilterBuffer() +{ +} + +XclImpAutoFilterBuffer::~XclImpAutoFilterBuffer() +{ + for( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() ) + delete pData; +} + +void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange) +{ + if( !GetByTab( rRange.aStart.Tab() ) ) + Append( new 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( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() ) + pData->Apply(); +} + +XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab ) +{ + for( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() ) + if( pData->Tab() == nTab ) + return pData; + return NULL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |