diff options
Diffstat (limited to 'sc/source/filter/excel/excrecds.cxx')
-rw-r--r-- | sc/source/filter/excel/excrecds.cxx | 1051 |
1 files changed, 1051 insertions, 0 deletions
diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx new file mode 100644 index 000000000000..9a66325db419 --- /dev/null +++ b/sc/source/filter/excel/excrecds.cxx @@ -0,0 +1,1051 @@ +/************************************************************************* + * + * 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 "excrecds.hxx" + +#include <map> +#include <filter/msfilter/countryid.hxx> + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + +#include <sfx2/objsh.hxx> + +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editobj.hxx> +#include <editeng/editstat.hxx> + +#include <editeng/flditem.hxx> +#include <editeng/flstitem.hxx> + +#include <svx/algitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brshitem.hxx> +#include <svx/pageitem.hxx> +#include <editeng/paperinf.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/escpitem.hxx> +#include <svl/intitem.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <svtools/ctrltool.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <string.h> + +#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 "xeescher.hxx" +#include "xeformula.hxx" +#include "xelink.hxx" +#include "xename.hxx" +#include "xecontent.hxx" + +#include "xcl97rec.hxx" + +#include <oox/core/tokens.hxx> + +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<sal_uInt32>(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<sal_Int8>& 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<SCCOL>(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<sal_uInt16>(nCol) ) + return xFilter.get(); + } + xFilter.reset( new XclExpAutofilter( GetRoot(), static_cast<sal_uInt16>(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<sal_uInt16>(nCol) ) + return TRUE; + return FALSE; +} + +void ExcAutoFilterRecs::AddObjRecs() +{ + if( pFilterInfo ) + { + ScAddress aAddr( pFilterInfo->GetStartPos() ); + for( SCCOL nObj = 0, nCount = pFilterInfo->GetColCount(); nObj < nCount; nObj++ ) + { + XclObj* pObjRec = new XclObjDropDown( GetObjectManager(), aAddr, IsFiltered( nObj ) ); + GetObjectManager().AddObj( pObjRec ); + 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; +} + +// ============================================================================ + |