/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: excrecds.cxx,v $ * $Revision: 1.88 $ * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" //------------------------------------------------------------------------ #include "excrecds.hxx" #include #include #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _SVSTDARR_USHORTS #include #include #include "global.hxx" #include "globstr.hrc" #include "docpool.hxx" #include "patattr.hxx" #include "cell.hxx" #include "document.hxx" #include "scextopt.hxx" #include "patattr.hxx" #include "attrib.hxx" #include "progress.hxx" #include "dociter.hxx" #include "rangenam.hxx" #include "dbcolect.hxx" #include "stlsheet.hxx" #include "stlpool.hxx" #include "editutil.hxx" #include "formula/errorcodes.hxx" #include "excdoc.hxx" #include "xeformula.hxx" #include "xelink.hxx" #include "xename.hxx" #include "xecontent.hxx" #include "xcl97rec.hxx" #include using ::com::sun::star::uno::Sequence; using ::rtl::OString; //--------------------------------------------------------- class ExcDummy_00 - const BYTE ExcDummy_00::pMyData[] = { 0x5c, 0x00, 0x20, 0x00, 0x04, 'C', 'a', 'l', 'c', // WRITEACCESS 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; const sal_Size ExcDummy_00::nMyLen = sizeof( ExcDummy_00::pMyData ); //-------------------------------------------------------- class ExcDummy_04x - const BYTE ExcDummy_040::pMyData[] = { 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, // BACKUP 0x8d, 0x00, 0x02, 0x00, 0x00, 0x00, // HIDEOBJ }; const sal_Size ExcDummy_040::nMyLen = sizeof( ExcDummy_040::pMyData ); const BYTE ExcDummy_041::pMyData[] = { 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, // PRECISION 0xda, 0x00, 0x02, 0x00, 0x00, 0x00 // BOOKBOOL }; const sal_Size ExcDummy_041::nMyLen = sizeof( ExcDummy_041::pMyData ); //-------------------------------------------------------- class ExcDummy_02a - const BYTE ExcDummy_02a::pMyData[] = { 0x0d, 0x00, 0x02, 0x00, 0x01, 0x00, // CALCMODE 0x0c, 0x00, 0x02, 0x00, 0x64, 0x00, // CALCCOUNT 0x0f, 0x00, 0x02, 0x00, 0x01, 0x00, // REFMODE 0x11, 0x00, 0x02, 0x00, 0x00, 0x00, // ITERATION 0x10, 0x00, 0x08, 0x00, 0xfc, 0xa9, 0xf1, 0xd2, 0x4d, // DELTA 0x62, 0x50, 0x3f, 0x5f, 0x00, 0x02, 0x00, 0x01, 0x00 // SAVERECALC }; const sal_Size ExcDummy_02a::nMyLen = sizeof( ExcDummy_02a::pMyData ); //----------------------------------------------------------- class ExcRecord - void ExcRecord::Save( XclExpStream& rStrm ) { SetRecHeader( GetNum(), GetLen() ); XclExpRecord::Save( rStrm ); } void ExcRecord::SaveCont( XclExpStream& /*rStrm*/ ) { } void ExcRecord::WriteBody( XclExpStream& rStrm ) { SaveCont( rStrm ); } //--------------------------------------------------------- class ExcEmptyRec - void ExcEmptyRec::Save( XclExpStream& /*rStrm*/ ) { } UINT16 ExcEmptyRec::GetNum() const { return 0; } sal_Size ExcEmptyRec::GetLen() const { return 0; } //------------------------------------------------------- class ExcRecordList - ExcRecordList::~ExcRecordList() { for( ExcRecord* pRec = First(); pRec; pRec = Next() ) delete pRec; } void ExcRecordList::Save( XclExpStream& rStrm ) { for( ExcRecord* pRec = First(); pRec; pRec = Next() ) pRec->Save( rStrm ); } //--------------------------------------------------------- class ExcDummyRec - void ExcDummyRec::Save( XclExpStream& rStrm ) { rStrm.Write( GetData(), GetLen() ); // raw write mode } UINT16 ExcDummyRec::GetNum( void ) const { return 0x0000; } //------------------------------------------------------- class ExcBoolRecord - void ExcBoolRecord::SaveCont( XclExpStream& rStrm ) { rStrm << (UINT16)(bVal ? 0x0001 : 0x0000); } sal_Size ExcBoolRecord::GetLen( void ) const { return 2; } //--------------------------------------------------------- class ExcBof_Base - ExcBof_Base::ExcBof_Base() : nRupBuild( 0x096C ), // copied from Excel nRupYear( 0x07C9 ) // copied from Excel { } //-------------------------------------------------------------- class ExcBof - ExcBof::ExcBof( void ) { nDocType = 0x0010; nVers = 0x0500; } void ExcBof::SaveCont( XclExpStream& rStrm ) { rStrm << nVers << nDocType << nRupBuild << nRupYear; } UINT16 ExcBof::GetNum( void ) const { return 0x0809; } sal_Size ExcBof::GetLen( void ) const { return 8; } //------------------------------------------------------------- class ExcBofW - ExcBofW::ExcBofW( void ) { nDocType = 0x0005; nVers = 0x0500; } void ExcBofW::SaveCont( XclExpStream& rStrm ) { rStrm << nVers << nDocType << nRupBuild << nRupYear; } UINT16 ExcBofW::GetNum( void ) const { return 0x0809; } sal_Size ExcBofW::GetLen( void ) const { return 8; } //-------------------------------------------------------------- class ExcEof - UINT16 ExcEof::GetNum( void ) const { return 0x000A; } sal_Size ExcEof::GetLen( void ) const { return 0; } //--------------------------------------------------------- class ExcDummy_00 - sal_Size ExcDummy_00::GetLen( void ) const { return nMyLen; } const BYTE* ExcDummy_00::GetData( void ) const { return pMyData; } //-------------------------------------------------------- class ExcDummy_04x - sal_Size ExcDummy_040::GetLen( void ) const { return nMyLen; } const BYTE* ExcDummy_040::GetData( void ) const { return pMyData; } sal_Size ExcDummy_041::GetLen( void ) const { return nMyLen; } const BYTE* ExcDummy_041::GetData( void ) const { return pMyData; } //------------------------------------------------------------- class Exc1904 - Exc1904::Exc1904( ScDocument& rDoc ) { Date* pDate = rDoc.GetFormatTable()->GetNullDate(); bVal = pDate ? (*pDate == Date( 1, 1, 1904 )) : FALSE; } UINT16 Exc1904::GetNum( void ) const { return 0x0022; } void Exc1904::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_date1904, XclXmlUtils::ToPsz( bVal ), FSEND ); } //------------------------------------------------------ class ExcBundlesheet - ExcBundlesheetBase::ExcBundlesheetBase( RootData& rRootData, SCTAB nTabNum ) : nStrPos( STREAM_SEEK_TO_END ), nOwnPos( STREAM_SEEK_TO_END ), nGrbit( rRootData.pER->GetTabInfo().IsVisibleTab( nTabNum ) ? 0x0000 : 0x0001 ), nTab( nTabNum ) { } ExcBundlesheetBase::ExcBundlesheetBase() : nStrPos( STREAM_SEEK_TO_END ), nOwnPos( STREAM_SEEK_TO_END ), nGrbit( 0x0000 ), nTab( SCTAB_GLOBAL ) { } void ExcBundlesheetBase::UpdateStreamPos( XclExpStream& rStrm ) { rStrm.SetSvStreamPos( nOwnPos ); rStrm.DisableEncryption(); rStrm << static_cast(nStrPos); rStrm.EnableEncryption(); } UINT16 ExcBundlesheetBase::GetNum( void ) const { return 0x0085; } ExcBundlesheet::ExcBundlesheet( RootData& rRootData, SCTAB _nTab ) : ExcBundlesheetBase( rRootData, _nTab ) { String sTabName = rRootData.pER->GetTabInfo().GetScTabName( _nTab ); DBG_ASSERT( sTabName.Len() < 256, "ExcBundlesheet::ExcBundlesheet - table name too long" ); aName = ByteString( sTabName, rRootData.pER->GetTextEncoding() ); } void ExcBundlesheet::SaveCont( XclExpStream& rStrm ) { nOwnPos = rStrm.GetSvStreamPos(); rStrm << (UINT32) 0x00000000 // dummy (stream position of the sheet) << nGrbit; rStrm.WriteByteString( aName ); // 8 bit length, max 255 chars } sal_Size ExcBundlesheet::GetLen() const { return 7 + Min( aName.Len(), (xub_StrLen) 255 ); } //--------------------------------------------------------- class ExcDummy_02 - sal_Size ExcDummy_02a::GetLen( void ) const { return nMyLen; } const BYTE* ExcDummy_02a::GetData( void ) const { return pMyData; } //--------------------------------------------------------- class ExcDummy_02 - XclExpCountry::XclExpCountry( const XclExpRoot& rRoot ) : XclExpRecord( EXC_ID_COUNTRY, 4 ) { /* #i31530# set document country as UI country too - needed for correct behaviour of number formats. */ mnUICountry = mnDocCountry = static_cast< sal_uInt16 >( ::msfilter::ConvertLanguageToCountry( rRoot.GetDocLanguage() ) ); } void XclExpCountry::WriteBody( XclExpStream& rStrm ) { rStrm << mnUICountry << mnDocCountry; } // XclExpWsbool =============================================================== XclExpWsbool::XclExpWsbool( bool bFitToPages, SCTAB nScTab, XclExpFilterManager* pManager ) : XclExpUInt16Record( EXC_ID_WSBOOL, EXC_WSBOOL_DEFAULTFLAGS ) , mnScTab( nScTab ) , mpManager( pManager ) { if( bFitToPages ) SetValue( GetValue() | EXC_WSBOOL_FITTOPAGE ); } void XclExpWsbool::SaveXml( XclExpXmlStream& rStrm ) { sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream(); rWorksheet->startElement( XML_sheetPr, // OOXTODO: XML_syncHorizontal, // OOXTODO: XML_syncVertical, // OOXTODO: XML_syncRef, // OOXTODO: XML_transitionEvaluation, // OOXTODO: XML_transitionEntry, // OOXTODO: XML_published, // OOXTODO: XML_codeName, XML_filterMode, mpManager ? XclXmlUtils::ToPsz( mpManager->HasFilterMode( mnScTab ) ) : NULL, // OOXTODO: XML_enableFormatConditionsCalculation, FSEND ); // OOXTODO: elements XML_tabColor, XML_outlinePr rWorksheet->singleElement( XML_pageSetUpPr, // OOXTODO: XML_autoPageBreaks, XML_fitToPage, XclXmlUtils::ToPsz( GetValue() & EXC_WSBOOL_FITTOPAGE ), FSEND ); rWorksheet->endElement( XML_sheetPr ); } // XclExpWindowProtection =============================================================== XclExpWindowProtection::XclExpWindowProtection(bool bValue) : XclExpBoolRecord(EXC_ID_WINDOWPROTECT, bValue) { } void XclExpWindowProtection::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_lockWindows, XclXmlUtils::ToPsz( GetBool() ), FSEND ); } // XclExpDocProtection =============================================================== XclExpProtection::XclExpProtection(bool bValue) : XclExpBoolRecord(EXC_ID_PROTECT, bValue) { } // ============================================================================ XclExpPassHash::XclExpPassHash(const Sequence& aHash) : XclExpRecord(EXC_ID_PASSWORD, 2), mnHash(0x0000) { if (aHash.getLength() >= 2) { mnHash = ((aHash[0] << 8) & 0xFFFF); mnHash |= (aHash[1] & 0xFF); } } XclExpPassHash::~XclExpPassHash() { } void XclExpPassHash::WriteBody(XclExpStream& rStrm) { rStrm << mnHash; } // ============================================================================ XclExpFiltermode::XclExpFiltermode() : XclExpEmptyRecord( EXC_ID_FILTERMODE ) { } // ---------------------------------------------------------------------------- XclExpAutofilterinfo::XclExpAutofilterinfo( const ScAddress& rStartPos, SCCOL nScCol ) : XclExpUInt16Record( EXC_ID_AUTOFILTERINFO, static_cast< sal_uInt16 >( nScCol ) ), maStartPos( rStartPos ) { } // ---------------------------------------------------------------------------- ExcFilterCondition::ExcFilterCondition() : nType( EXC_AFTYPE_NOTUSED ), nOper( EXC_AFOPER_EQUAL ), fVal( 0.0 ), pText( NULL ) { } ExcFilterCondition::~ExcFilterCondition() { if( pText ) delete pText; } sal_Size ExcFilterCondition::GetTextBytes() const { return pText ? (1 + pText->GetBufferSize()) : 0; } void ExcFilterCondition::SetCondition( UINT8 nTp, UINT8 nOp, double fV, String* pT ) { nType = nTp; nOper = nOp; fVal = fV; delete pText; pText = pT ? new XclExpString( *pT, EXC_STR_8BITLENGTH ) : NULL; } void ExcFilterCondition::Save( XclExpStream& rStrm ) { rStrm << nType << nOper; switch( nType ) { case EXC_AFTYPE_DOUBLE: rStrm << fVal; break; case EXC_AFTYPE_STRING: DBG_ASSERT( pText, "ExcFilterCondition::Save() -- pText is NULL!" ); rStrm << (UINT32)0 << (UINT8) pText->Len() << (UINT16)0 << (UINT8)0; break; case EXC_AFTYPE_BOOLERR: rStrm << (UINT8)0 << (UINT8)((fVal != 0) ? 1 : 0) << (UINT32)0 << (UINT16)0; break; default: rStrm << (UINT32)0 << (UINT32)0; } } static const char* lcl_GetOperator( UINT8 nOper ) { switch( nOper ) { case EXC_AFOPER_EQUAL: return "equal"; case EXC_AFOPER_GREATER: return "greaterThan"; case EXC_AFOPER_GREATEREQUAL: return "greaterThanOrEqual"; case EXC_AFOPER_LESS: return "lessThan"; case EXC_AFOPER_LESSEQUAL: return "lessThanOrEqual"; case EXC_AFOPER_NOTEQUAL: return "notEqual"; case EXC_AFOPER_NONE: default: return "**none**"; } } static OString lcl_GetValue( UINT8 nType, double fVal, XclExpString* pStr ) { switch( nType ) { case EXC_AFTYPE_STRING: return XclXmlUtils::ToOString( *pStr ); case EXC_AFTYPE_DOUBLE: return OString::valueOf( fVal ); case EXC_AFTYPE_BOOLERR: return OString::valueOf( (sal_Int32) ( fVal != 0 ? 1 : 0 ) ); default: return OString(); } } void ExcFilterCondition::SaveXml( XclExpXmlStream& rStrm ) { if( IsEmpty() ) return; rStrm.GetCurrentStream()->singleElement( XML_customFilter, XML_operator, lcl_GetOperator( nOper ), XML_val, lcl_GetValue( nType, fVal, pText ).getStr(), FSEND ); } void ExcFilterCondition::SaveText( XclExpStream& rStrm ) { if( nType == EXC_AFTYPE_STRING ) { DBG_ASSERT( pText, "ExcFilterCondition::SaveText() -- pText is NULL!" ); pText->WriteFlagField( rStrm ); pText->WriteBuffer( rStrm ); } } // ---------------------------------------------------------------------------- XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, UINT16 nC ) : XclExpRecord( EXC_ID_AUTOFILTER, 24 ), XclExpRoot( rRoot ), nCol( nC ), nFlags( 0 ) { } BOOL XclExpAutofilter::AddCondition( ScQueryConnect eConn, UINT8 nType, UINT8 nOp, double fVal, String* pText, BOOL bSimple ) { if( !aCond[ 1 ].IsEmpty() ) return FALSE; UINT16 nInd = aCond[ 0 ].IsEmpty() ? 0 : 1; if( nInd == 1 ) nFlags |= (eConn == SC_OR) ? EXC_AFFLAG_OR : EXC_AFFLAG_AND; if( bSimple ) nFlags |= (nInd == 0) ? EXC_AFFLAG_SIMPLE1 : EXC_AFFLAG_SIMPLE2; aCond[ nInd ].SetCondition( nType, nOp, fVal, pText ); AddRecSize( aCond[ nInd ].GetTextBytes() ); return TRUE; } BOOL XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry ) { BOOL bConflict = FALSE; String sText; if( rEntry.pStr ) { sText.Assign( *rEntry.pStr ); switch( rEntry.eOp ) { case SC_CONTAINS: case SC_DOES_NOT_CONTAIN: { sText.InsertAscii( "*" , 0 ); sText.AppendAscii( "*" ); } break; case SC_BEGINS_WITH: case SC_DOES_NOT_BEGIN_WITH: sText.AppendAscii( "*" ); break; case SC_ENDS_WITH: case SC_DOES_NOT_END_WITH: sText.InsertAscii( "*" , 0 ); break; default: { //nothing } } } BOOL bLen = sText.Len() > 0; // empty/nonempty fields if( !bLen && (rEntry.nVal == SC_EMPTYFIELDS) ) bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_EMPTY, EXC_AFOPER_NONE, 0.0, NULL, TRUE ); else if( !bLen && (rEntry.nVal == SC_NONEMPTYFIELDS) ) bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_NOTEMPTY, EXC_AFOPER_NONE, 0.0, NULL, TRUE ); // other conditions else { double fVal = 0.0; sal_uInt32 nIndex = 0; BOOL bIsNum = bLen ? GetFormatter().IsNumberFormat( sText, nIndex, fVal ) : TRUE; String* pText = bIsNum ? NULL : &sText; // top10 flags UINT16 nNewFlags = 0x0000; switch( rEntry.eOp ) { case SC_TOPVAL: nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP); break; case SC_BOTVAL: nNewFlags = EXC_AFFLAG_TOP10; break; case SC_TOPPERC: nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP | EXC_AFFLAG_TOP10PERC); break; case SC_BOTPERC: nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10PERC); break; default:; } BOOL bNewTop10 = ::get_flag( nNewFlags, EXC_AFFLAG_TOP10 ); bConflict = HasTop10() && bNewTop10; if( !bConflict ) { if( bNewTop10 ) { if( fVal < 0 ) fVal = 0; if( fVal >= 501 ) fVal = 500; nFlags |= (nNewFlags | (UINT16)(fVal) << 7); } // normal condition else { UINT8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING; UINT8 nOper = EXC_AFOPER_NONE; switch( rEntry.eOp ) { case SC_EQUAL: nOper = EXC_AFOPER_EQUAL; break; case SC_LESS: nOper = EXC_AFOPER_LESS; break; case SC_GREATER: nOper = EXC_AFOPER_GREATER; break; case SC_LESS_EQUAL: nOper = EXC_AFOPER_LESSEQUAL; break; case SC_GREATER_EQUAL: nOper = EXC_AFOPER_GREATEREQUAL; break; case SC_NOT_EQUAL: nOper = EXC_AFOPER_NOTEQUAL; break; case SC_CONTAINS: case SC_BEGINS_WITH: case SC_ENDS_WITH: nOper = EXC_AFOPER_EQUAL; break; case SC_DOES_NOT_CONTAIN: case SC_DOES_NOT_BEGIN_WITH: case SC_DOES_NOT_END_WITH: nOper = EXC_AFOPER_NOTEQUAL; break; default:; } bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText ); } } } return bConflict; } void XclExpAutofilter::WriteBody( XclExpStream& rStrm ) { rStrm << nCol << nFlags; aCond[ 0 ].Save( rStrm ); aCond[ 1 ].Save( rStrm ); aCond[ 0 ].SaveText( rStrm ); aCond[ 1 ].SaveText( rStrm ); } void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm ) { if( !HasCondition() ) return; sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream(); rWorksheet->startElement( XML_filterColumn, XML_colId, OString::valueOf( (sal_Int32) nCol ).getStr(), // OOXTODO: XML_hiddenButton, AutoFilter12 fHideArrow? // OOXTODO: XML_showButton, FSEND ); if( HasTop10() ) { rWorksheet->singleElement( XML_top10, XML_top, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10TOP ) ), XML_percent, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10PERC ) ), XML_val, OString::valueOf( (sal_Int32) (nFlags >> 7 ) ).getStr(), // OOXTODO: XML_filterVal, FSEND ); } rWorksheet->startElement( XML_customFilters, XML_and, XclXmlUtils::ToPsz( (nFlags & EXC_AFFLAG_ANDORMASK) == EXC_AFFLAG_AND ), FSEND ); aCond[ 0 ].SaveXml( rStrm ); aCond[ 1 ].SaveXml( rStrm ); rWorksheet->endElement( XML_customFilters ); // OOXTODO: XLM_colorFilter, XML_dynamicFilter, // XML_extLst, XML_filters, XML_iconFilter, XML_top10 rWorksheet->endElement( XML_filterColumn ); } // ---------------------------------------------------------------------------- ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab ) : XclExpRoot( rRoot ), pFilterMode( NULL ), pFilterInfo( NULL ) { ScDBCollection& rDBColl = GetDatabaseRanges(); XclExpNameManager& rNameMgr = GetNameManager(); // search for first DB-range with filter UINT16 nIndex = 0; BOOL bFound = FALSE; BOOL bAdvanced = FALSE; ScDBData* pData = NULL; ScRange aAdvRange; while( (nIndex < rDBColl.GetCount()) && !bFound ) { pData = rDBColl[ nIndex ]; if( pData ) { ScRange aRange; pData->GetArea( aRange ); bAdvanced = pData->GetAdvancedQuerySource( aAdvRange ); bFound = (aRange.aStart.Tab() == nTab) && (pData->HasQueryParam() || pData->HasAutoFilter() || bAdvanced); } if( !bFound ) nIndex++; } if( pData && bFound ) { ScQueryParam aParam; pData->GetQueryParam( aParam ); ScRange aRange( aParam.nCol1, aParam.nRow1, aParam.nTab, aParam.nCol2, aParam.nRow2, aParam.nTab ); SCCOL nColCnt = aParam.nCol2 - aParam.nCol1 + 1; maRef = aRange; // #i2394# #100489# built-in defined names must be sorted by containing sheet name rNameMgr.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE, aRange ); // advanced filter if( bAdvanced ) { // filter criteria, excel allows only same table if( aAdvRange.aStart.Tab() == nTab ) rNameMgr.InsertBuiltInName( EXC_BUILTIN_CRITERIA, aAdvRange ); // filter destination range, excel allows only same table if( !aParam.bInplace ) { ScRange aDestRange( aParam.nDestCol, aParam.nDestRow, aParam.nDestTab ); aDestRange.aEnd.IncCol( nColCnt - 1 ); if( aDestRange.aStart.Tab() == nTab ) rNameMgr.InsertBuiltInName( EXC_BUILTIN_EXTRACT, aDestRange ); } pFilterMode = new XclExpFiltermode; } // AutoFilter else { BOOL bConflict = FALSE; BOOL bContLoop = TRUE; BOOL bHasOr = FALSE; SCCOLROW nFirstField = aParam.GetEntry( 0 ).nField; // create AUTOFILTER records for filtered columns for( SCSIZE nEntry = 0; !bConflict && bContLoop && (nEntry < aParam.GetEntryCount()); nEntry++ ) { const ScQueryEntry& rEntry = aParam.GetEntry( nEntry ); bContLoop = rEntry.bDoQuery; if( bContLoop ) { XclExpAutofilter* pFilter = GetByCol( static_cast(rEntry.nField) - aRange.aStart.Col() ); if( nEntry > 0 ) bHasOr |= (rEntry.eConnect == SC_OR); bConflict = (nEntry > 1) && bHasOr; if( !bConflict ) bConflict = (nEntry == 1) && (rEntry.eConnect == SC_OR) && (nFirstField != rEntry.nField); if( !bConflict ) bConflict = pFilter->AddEntry( rEntry ); } } // additional tests for conflicts for( size_t nPos = 0, nSize = maFilterList.GetSize(); !bConflict && (nPos < nSize); ++nPos ) { XclExpAutofilterRef xFilter = maFilterList.GetRecord( nPos ); bConflict = xFilter->HasCondition() && xFilter->HasTop10(); } if( bConflict ) maFilterList.RemoveAllRecords(); if( !maFilterList.IsEmpty() ) pFilterMode = new XclExpFiltermode; pFilterInfo = new XclExpAutofilterinfo( aRange.aStart, nColCnt ); } } } ExcAutoFilterRecs::~ExcAutoFilterRecs() { delete pFilterMode; delete pFilterInfo; } XclExpAutofilter* ExcAutoFilterRecs::GetByCol( SCCOL nCol ) { XclExpAutofilterRef xFilter; for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos ) { xFilter = maFilterList.GetRecord( nPos ); if( xFilter->GetCol() == static_cast(nCol) ) return xFilter.get(); } xFilter.reset( new XclExpAutofilter( GetRoot(), static_cast(nCol) ) ); maFilterList.AppendRecord( xFilter ); return xFilter.get(); } BOOL ExcAutoFilterRecs::IsFiltered( SCCOL nCol ) { for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos ) if( maFilterList.GetRecord( nPos )->GetCol() == static_cast(nCol) ) return TRUE; return FALSE; } void ExcAutoFilterRecs::AddObjRecs() { if( pFilterInfo ) { ScAddress aAddr( pFilterInfo->GetStartPos() ); for( SCCOL nObj = 0, nCount = pFilterInfo->GetColCount(); nObj < nCount; nObj++ ) { XclObjDropDown* pObj = new XclObjDropDown( GetRoot(), aAddr, IsFiltered( nObj ) ); GetOldRoot().pObjRecs->Add( pObj ); aAddr.IncCol( 1 ); } } } void ExcAutoFilterRecs::Save( XclExpStream& rStrm ) { if( pFilterMode ) pFilterMode->Save( rStrm ); if( pFilterInfo ) pFilterInfo->Save( rStrm ); maFilterList.Save( rStrm ); } void ExcAutoFilterRecs::SaveXml( XclExpXmlStream& rStrm ) { if( maFilterList.IsEmpty() ) return; sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream(); rWorksheet->startElement( XML_autoFilter, XML_ref, XclXmlUtils::ToOString( maRef ).getStr(), FSEND ); // OOXTODO: XML_extLst, XML_sortState maFilterList.SaveXml( rStrm ); rWorksheet->endElement( XML_autoFilter ); } bool ExcAutoFilterRecs::HasFilterMode() const { return pFilterMode != NULL; } // ---------------------------------------------------------------------------- XclExpFilterManager::XclExpFilterManager( const XclExpRoot& rRoot ) : XclExpRoot( rRoot ) { } void XclExpFilterManager::InitTabFilter( SCTAB nScTab ) { maFilterMap[ nScTab ].reset( new ExcAutoFilterRecs( GetRoot(), nScTab ) ); } XclExpRecordRef XclExpFilterManager::CreateRecord( SCTAB nScTab ) { XclExpTabFilterRef xRec; XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab ); if( aIt != maFilterMap.end() ) { xRec = aIt->second; xRec->AddObjRecs(); } return xRec; } bool XclExpFilterManager::HasFilterMode( SCTAB nScTab ) { XclExpTabFilterRef xRec; XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab ); if( aIt != maFilterMap.end() ) { return aIt->second->HasFilterMode(); } return false; } // ============================================================================