| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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" |
| |
| using namespace ::oox; |
| |
| using ::com::sun::star::uno::Sequence; |
| using ::rtl::OString; |
| |
| //--------------------------------------------------------- class ExcDummy_00 - |
| const sal_uInt8 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 sal_uInt8 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 sal_uInt8 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 sal_uInt8 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*/ ) |
| { |
| } |
| |
| |
| sal_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 |
| } |
| |
| |
| sal_uInt16 ExcDummyRec::GetNum( void ) const |
| { |
| return 0x0000; |
| } |
| |
| |
| |
| //------------------------------------------------------- class ExcBoolRecord - |
| |
| void ExcBoolRecord::SaveCont( XclExpStream& rStrm ) |
| { |
| rStrm << (sal_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; |
| } |
| |
| |
| sal_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; |
| } |
| |
| |
| |
| sal_uInt16 ExcBofW::GetNum( void ) const |
| { |
| return 0x0809; |
| } |
| |
| |
| |
| sal_Size ExcBofW::GetLen( void ) const |
| { |
| return 8; |
| } |
| |
| |
| |
| //-------------------------------------------------------------- class ExcEof - |
| |
| sal_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 sal_uInt8* ExcDummy_00::GetData( void ) const |
| { |
| return pMyData; |
| } |
| |
| |
| |
| //-------------------------------------------------------- class ExcDummy_04x - |
| |
| sal_Size ExcDummy_040::GetLen( void ) const |
| { |
| return nMyLen; |
| } |
| |
| |
| const sal_uInt8* ExcDummy_040::GetData( void ) const |
| { |
| return pMyData; |
| } |
| |
| |
| |
| |
| sal_Size ExcDummy_041::GetLen( void ) const |
| { |
| return nMyLen; |
| } |
| |
| |
| const sal_uInt8* 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 )) : sal_False; |
| } |
| |
| |
| sal_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(); |
| } |
| |
| |
| sal_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 << (sal_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 sal_uInt8* 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( sal_uInt8 nTp, sal_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 << (sal_uInt32)0 << (sal_uInt8) pText->Len() << (sal_uInt16)0 << (sal_uInt8)0; |
| break; |
| case EXC_AFTYPE_BOOLERR: |
| rStrm << (sal_uInt8)0 << (sal_uInt8)((fVal != 0) ? 1 : 0) << (sal_uInt32)0 << (sal_uInt16)0; |
| break; |
| default: |
| rStrm << (sal_uInt32)0 << (sal_uInt32)0; |
| } |
| } |
| |
| static const char* lcl_GetOperator( sal_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( sal_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, sal_uInt16 nC ) : |
| XclExpRecord( EXC_ID_AUTOFILTER, 24 ), |
| XclExpRoot( rRoot ), |
| nCol( nC ), |
| nFlags( 0 ) |
| { |
| } |
| |
| sal_Bool XclExpAutofilter::AddCondition( ScQueryConnect eConn, sal_uInt8 nType, sal_uInt8 nOp, |
| double fVal, String* pText, sal_Bool bSimple ) |
| { |
| if( !aCond[ 1 ].IsEmpty() ) |
| return sal_False; |
| |
| sal_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 sal_True; |
| } |
| |
| sal_Bool XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry ) |
| { |
| sal_Bool bConflict = sal_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 |
| } |
| } |
| } |
| |
| sal_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, sal_True ); |
| else if( !bLen && (rEntry.nVal == SC_NONEMPTYFIELDS) ) |
| bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_NOTEMPTY, EXC_AFOPER_NONE, 0.0, NULL, sal_True ); |
| // other conditions |
| else |
| { |
| double fVal = 0.0; |
| sal_uInt32 nIndex = 0; |
| sal_Bool bIsNum = bLen ? GetFormatter().IsNumberFormat( sText, nIndex, fVal ) : sal_True; |
| String* pText = bIsNum ? NULL : &sText; |
| |
| // top10 flags |
| sal_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:; |
| } |
| sal_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 | (sal_uInt16)(fVal) << 7); |
| } |
| // normal condition |
| else |
| { |
| sal_uInt8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING; |
| sal_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 |
| sal_uInt16 nIndex = 0; |
| sal_Bool bFound = sal_False; |
| sal_Bool bAdvanced = sal_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 |
| { |
| sal_Bool bConflict = sal_False; |
| sal_Bool bContLoop = sal_True; |
| sal_Bool bHasOr = sal_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(); |
| } |
| |
| sal_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 sal_True; |
| return sal_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; |
| } |
| |
| // ============================================================================ |
| |