1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "excrecds.hxx"
23 #include <filter/msfilter/countryid.hxx>
25 #include "scitems.hxx"
26 #include <editeng/eeitem.hxx>
28 #include <sfx2/objsh.hxx>
30 #include <editeng/editdata.hxx>
31 #include <editeng/editeng.hxx>
32 #include <editeng/editobj.hxx>
33 #include <editeng/editstat.hxx>
35 #include <editeng/flditem.hxx>
36 #include <editeng/flstitem.hxx>
38 #include <svx/algitem.hxx>
39 #include <editeng/boxitem.hxx>
40 #include <editeng/brushitem.hxx>
41 #include <svx/pageitem.hxx>
42 #include <editeng/paperinf.hxx>
43 #include <editeng/sizeitem.hxx>
44 #include <editeng/ulspitem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/escapementitem.hxx>
47 #include <svl/intitem.hxx>
48 #include <svl/zforlist.hxx>
49 #include <svl/zformat.hxx>
50 #include <svtools/ctrltool.hxx>
55 #include "globstr.hrc"
56 #include "docpool.hxx"
57 #include "patattr.hxx"
58 #include "formulacell.hxx"
59 #include "document.hxx"
60 #include "scextopt.hxx"
62 #include "progress.hxx"
63 #include "dociter.hxx"
64 #include "rangenam.hxx"
66 #include "stlsheet.hxx"
67 #include "stlpool.hxx"
68 #include "editutil.hxx"
69 #include <formula/errorcodes.hxx>
70 #include "queryentry.hxx"
71 #include "queryparam.hxx"
74 #include "xeescher.hxx"
75 #include "xeformula.hxx"
78 #include "xecontent.hxx"
80 #include "xcl97rec.hxx"
81 #include "tabprotection.hxx"
83 using namespace ::oox
;
85 using ::com::sun::star::uno::Sequence
;
87 //--------------------------------------------------------- class ExcDummy_00 -
88 const sal_uInt8
ExcDummy_00::pMyData
[] = {
89 0x5c, 0x00, 0x20, 0x00, 0x04, 'C', 'a', 'l', 'c', // WRITEACCESS
90 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
91 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
92 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
94 const sal_Size
ExcDummy_00::nMyLen
= sizeof( ExcDummy_00::pMyData
);
96 //-------------------------------------------------------- class ExcDummy_04x -
97 const sal_uInt8
ExcDummy_040::pMyData
[] = {
98 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, // BACKUP
99 0x8d, 0x00, 0x02, 0x00, 0x00, 0x00, // HIDEOBJ
101 const sal_Size
ExcDummy_040::nMyLen
= sizeof( ExcDummy_040::pMyData
);
103 const sal_uInt8
ExcDummy_041::pMyData
[] = {
104 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, // PRECISION
105 0xda, 0x00, 0x02, 0x00, 0x00, 0x00 // BOOKBOOL
107 const sal_Size
ExcDummy_041::nMyLen
= sizeof( ExcDummy_041::pMyData
);
109 //-------------------------------------------------------- class ExcDummy_02a -
110 const sal_uInt8
ExcDummy_02a::pMyData
[] = {
111 0x0d, 0x00, 0x02, 0x00, 0x01, 0x00, // CALCMODE
112 0x0c, 0x00, 0x02, 0x00, 0x64, 0x00, // CALCCOUNT
113 0x0f, 0x00, 0x02, 0x00, 0x01, 0x00, // REFMODE
114 0x11, 0x00, 0x02, 0x00, 0x00, 0x00, // ITERATION
115 0x10, 0x00, 0x08, 0x00, 0xfc, 0xa9, 0xf1, 0xd2, 0x4d, // DELTA
117 0x5f, 0x00, 0x02, 0x00, 0x01, 0x00 // SAVERECALC
119 const sal_Size
ExcDummy_02a::nMyLen
= sizeof( ExcDummy_02a::pMyData
);
121 //----------------------------------------------------------- class ExcRecord -
123 void ExcRecord::Save( XclExpStream
& rStrm
)
125 SetRecHeader( GetNum(), GetLen() );
126 XclExpRecord::Save( rStrm
);
129 void ExcRecord::SaveCont( XclExpStream
& /*rStrm*/ )
133 void ExcRecord::WriteBody( XclExpStream
& rStrm
)
138 void ExcRecord::SaveXml( XclExpXmlStream
& /*rStrm*/ )
142 //--------------------------------------------------------- class ExcEmptyRec -
144 void ExcEmptyRec::Save( XclExpStream
& /*rStrm*/ )
148 sal_uInt16
ExcEmptyRec::GetNum() const
153 sal_Size
ExcEmptyRec::GetLen() const
158 //--------------------------------------------------------- class ExcDummyRec -
160 void ExcDummyRec::Save( XclExpStream
& rStrm
)
162 rStrm
.Write( GetData(), GetLen() ); // raw write mode
165 sal_uInt16
ExcDummyRec::GetNum() const
170 //------------------------------------------------------- class ExcBoolRecord -
172 void ExcBoolRecord::SaveCont( XclExpStream
& rStrm
)
174 rStrm
<< (sal_uInt16
)(bVal
? 0x0001 : 0x0000);
177 sal_Size
ExcBoolRecord::GetLen() const
182 //--------------------------------------------------------- class ExcBof_Base -
184 ExcBof_Base::ExcBof_Base()
187 , nRupBuild(0x096C) // copied from Excel
188 , nRupYear(0x07C9) // copied from Excel
192 //-------------------------------------------------------------- class ExcBof -
200 void ExcBof::SaveCont( XclExpStream
& rStrm
)
202 rStrm
<< nVers
<< nDocType
<< nRupBuild
<< nRupYear
;
205 sal_uInt16
ExcBof::GetNum() const
210 sal_Size
ExcBof::GetLen() const
215 //------------------------------------------------------------- class ExcBofW -
223 void ExcBofW::SaveCont( XclExpStream
& rStrm
)
225 rStrm
<< nVers
<< nDocType
<< nRupBuild
<< nRupYear
;
228 sal_uInt16
ExcBofW::GetNum() const
233 sal_Size
ExcBofW::GetLen() const
238 //-------------------------------------------------------------- class ExcEof -
240 sal_uInt16
ExcEof::GetNum() const
245 sal_Size
ExcEof::GetLen() const
250 //--------------------------------------------------------- class ExcDummy_00 -
252 sal_Size
ExcDummy_00::GetLen() const
257 const sal_uInt8
* ExcDummy_00::GetData() const
262 //-------------------------------------------------------- class ExcDummy_04x -
264 sal_Size
ExcDummy_040::GetLen() const
269 const sal_uInt8
* ExcDummy_040::GetData() const
274 sal_Size
ExcDummy_041::GetLen() const
279 const sal_uInt8
* ExcDummy_041::GetData() const
284 //------------------------------------------------------------- class Exc1904 -
286 Exc1904::Exc1904( ScDocument
& rDoc
)
288 Date
* pDate
= rDoc
.GetFormatTable()->GetNullDate();
289 bVal
= pDate
&& (*pDate
== Date( 1, 1, 1904 ));
290 bDateCompatibility
= pDate
&& !( *pDate
== Date( 30, 12, 1899 ));
293 sal_uInt16
Exc1904::GetNum() const
298 void Exc1904::SaveXml( XclExpXmlStream
& rStrm
)
300 bool bISOIEC
= ( rStrm
.getVersion() == oox::core::ISOIEC_29500_2008
);
304 rStrm
.WriteAttributes(
305 XML_dateCompatibility
, XclXmlUtils::ToPsz( bDateCompatibility
),
309 if( !bISOIEC
|| bDateCompatibility
)
311 rStrm
.WriteAttributes(
312 XML_date1904
, XclXmlUtils::ToPsz( bVal
),
317 //------------------------------------------------------ class ExcBundlesheet -
319 ExcBundlesheetBase::ExcBundlesheetBase( RootData
& rRootData
, SCTAB nTabNum
) :
320 m_nStrPos( STREAM_SEEK_TO_END
),
321 m_nOwnPos( STREAM_SEEK_TO_END
),
322 nGrbit( rRootData
.pER
->GetTabInfo().IsVisibleTab( nTabNum
) ? 0x0000 : 0x0001 ),
327 ExcBundlesheetBase::ExcBundlesheetBase() :
328 m_nStrPos( STREAM_SEEK_TO_END
),
329 m_nOwnPos( STREAM_SEEK_TO_END
),
335 void ExcBundlesheetBase::UpdateStreamPos( XclExpStream
& rStrm
)
337 rStrm
.SetSvStreamPos( m_nOwnPos
);
338 rStrm
.DisableEncryption();
339 rStrm
<< static_cast<sal_uInt32
>(m_nStrPos
);
340 rStrm
.EnableEncryption();
343 sal_uInt16
ExcBundlesheetBase::GetNum() const
348 ExcBundlesheet::ExcBundlesheet( RootData
& rRootData
, SCTAB _nTab
) :
349 ExcBundlesheetBase( rRootData
, _nTab
)
351 OUString sTabName
= rRootData
.pER
->GetTabInfo().GetScTabName( _nTab
);
352 OSL_ENSURE( sTabName
.getLength() < 256, "ExcBundlesheet::ExcBundlesheet - table name too long" );
353 aName
= OUStringToOString(sTabName
, rRootData
.pER
->GetTextEncoding());
356 void ExcBundlesheet::SaveCont( XclExpStream
& rStrm
)
358 m_nOwnPos
= rStrm
.GetSvStreamPos();
359 rStrm
<< (sal_uInt32
) 0x00000000 // dummy (stream position of the sheet)
361 rStrm
.WriteByteString(aName
); // 8 bit length, max 255 chars
364 sal_Size
ExcBundlesheet::GetLen() const
366 return 7 + std::min( aName
.getLength(), (sal_Int32
) 255 );
369 //--------------------------------------------------------- class ExcDummy_02 -
371 sal_Size
ExcDummy_02a::GetLen() const
376 const sal_uInt8
* ExcDummy_02a::GetData() const
380 //--------------------------------------------------------- class ExcDummy_02 -
382 XclExpCountry::XclExpCountry( const XclExpRoot
& rRoot
) :
383 XclExpRecord( EXC_ID_COUNTRY
, 4 )
385 /* #i31530# set document country as UI country too -
386 needed for correct behaviour of number formats. */
387 mnUICountry
= mnDocCountry
= static_cast< sal_uInt16
>(
388 ::msfilter::ConvertLanguageToCountry( rRoot
.GetDocLanguage() ) );
391 void XclExpCountry::WriteBody( XclExpStream
& rStrm
)
393 rStrm
<< mnUICountry
<< mnDocCountry
;
396 // XclExpWsbool ===============================================================
398 XclExpWsbool::XclExpWsbool( bool bFitToPages
)
399 : XclExpUInt16Record( EXC_ID_WSBOOL
, EXC_WSBOOL_DEFAULTFLAGS
)
402 SetValue( GetValue() | EXC_WSBOOL_FITTOPAGE
);
405 XclExpXmlSheetPr::XclExpXmlSheetPr( bool bFitToPages
, SCTAB nScTab
, const Color
& rTabColor
, XclExpFilterManager
* pManager
) :
406 mnScTab(nScTab
), mpManager(pManager
), mbFitToPage(bFitToPages
), maTabColor(rTabColor
) {}
408 void XclExpXmlSheetPr::SaveXml( XclExpXmlStream
& rStrm
)
410 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
411 rWorksheet
->startElement( XML_sheetPr
,
412 // OOXTODO: XML_syncHorizontal,
413 // OOXTODO: XML_syncVertical,
414 // OOXTODO: XML_syncRef,
415 // OOXTODO: XML_transitionEvaluation,
416 // OOXTODO: XML_transitionEntry,
417 // OOXTODO: XML_published,
418 // OOXTODO: XML_codeName,
419 XML_filterMode
, mpManager
? XclXmlUtils::ToPsz( mpManager
->HasFilterMode( mnScTab
) ) : nullptr,
420 // OOXTODO: XML_enableFormatConditionsCalculation,
423 // Note : the order of child elements is significant. Don't change the order.
425 // OOXTODO: XML_outlinePr
427 if (maTabColor
!= Color(COL_AUTO
))
428 rWorksheet
->singleElement(
429 XML_tabColor
, XML_rgb
, XclXmlUtils::ToOString(maTabColor
).getStr(), FSEND
);
431 rWorksheet
->singleElement(XML_pageSetUpPr
,
432 // OOXTODO: XML_autoPageBreaks,
433 XML_fitToPage
, XclXmlUtils::ToPsz(mbFitToPage
), FSEND
);
435 rWorksheet
->endElement( XML_sheetPr
);
438 // XclExpWindowProtection ===============================================================
440 XclExpWindowProtection::XclExpWindowProtection(bool bValue
) :
441 XclExpBoolRecord(EXC_ID_WINDOWPROTECT
, bValue
)
445 void XclExpWindowProtection::SaveXml( XclExpXmlStream
& rStrm
)
447 rStrm
.WriteAttributes(
448 XML_lockWindows
, XclXmlUtils::ToPsz( GetBool() ),
452 // XclExpDocProtection ===============================================================
454 XclExpProtection::XclExpProtection(bool bValue
) :
455 XclExpBoolRecord(EXC_ID_PROTECT
, bValue
)
459 XclExpSheetProtection::XclExpSheetProtection(bool bValue
, SCTAB nTab
) :
460 XclExpProtection( bValue
),
465 void XclExpSheetProtection::SaveXml( XclExpXmlStream
& rStrm
)
467 ScDocument
& rDoc
= rStrm
.GetRoot().GetDoc();
468 const ScTableProtection
* pTabProtect
= rDoc
.GetTabProtection(mnTab
);
471 Sequence
<sal_Int8
> aHash
= pTabProtect
->getPasswordHash(PASSHASH_XL
);
473 if (aHash
.getLength() >= 2)
475 sHash
= OString::number(
476 ( static_cast<sal_uInt8
>(aHash
[0]) << 8
477 | static_cast<sal_uInt8
>(aHash
[1]) ),
480 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
481 rWorksheet
->singleElement( XML_sheetProtection
,
482 XML_sheet
, XclXmlUtils::ToPsz( true ),
483 XML_password
, sHash
.isEmpty()? nullptr : sHash
.getStr(),
484 XML_objects
, pTabProtect
->isOptionEnabled( ScTableProtection::OBJECTS
) ? nullptr : XclXmlUtils::ToPsz( true ),
485 XML_scenarios
, pTabProtect
->isOptionEnabled( ScTableProtection::SCENARIOS
) ? nullptr : XclXmlUtils::ToPsz( true ),
486 XML_formatCells
, pTabProtect
->isOptionEnabled( ScTableProtection::FORMAT_CELLS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
487 XML_formatColumns
, pTabProtect
->isOptionEnabled( ScTableProtection::FORMAT_COLUMNS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
488 XML_formatRows
, pTabProtect
->isOptionEnabled( ScTableProtection::FORMAT_ROWS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
489 XML_insertColumns
, pTabProtect
->isOptionEnabled( ScTableProtection::INSERT_COLUMNS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
490 XML_insertRows
, pTabProtect
->isOptionEnabled( ScTableProtection::INSERT_ROWS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
491 XML_insertHyperlinks
, pTabProtect
->isOptionEnabled( ScTableProtection::INSERT_HYPERLINKS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
492 XML_deleteColumns
, pTabProtect
->isOptionEnabled( ScTableProtection::DELETE_COLUMNS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
493 XML_deleteRows
, pTabProtect
->isOptionEnabled( ScTableProtection::DELETE_ROWS
) ? XclXmlUtils::ToPsz( false ) : nullptr,
494 XML_selectLockedCells
, pTabProtect
->isOptionEnabled( ScTableProtection::SELECT_LOCKED_CELLS
) ? nullptr : XclXmlUtils::ToPsz( true ),
495 XML_sort
, pTabProtect
->isOptionEnabled( ScTableProtection::SORT
) ? XclXmlUtils::ToPsz( false ) : nullptr,
496 XML_autoFilter
, pTabProtect
->isOptionEnabled( ScTableProtection::AUTOFILTER
) ? XclXmlUtils::ToPsz( false ) : nullptr,
497 XML_pivotTables
, pTabProtect
->isOptionEnabled( ScTableProtection::PIVOT_TABLES
) ? XclXmlUtils::ToPsz( false ) : nullptr,
498 XML_selectUnlockedCells
, pTabProtect
->isOptionEnabled( ScTableProtection::SELECT_UNLOCKED_CELLS
) ? nullptr : XclXmlUtils::ToPsz( true ),
501 const ::std::vector
<ScEnhancedProtection
>& rProts( pTabProtect
->getEnhancedProtection());
504 rWorksheet
->startElement( XML_protectedRanges
, FSEND
);
505 for (::std::vector
<ScEnhancedProtection
>::const_iterator
it( rProts
.begin()), end( rProts
.end());
508 SAL_WARN_IF( (*it
).maSecurityDescriptorXML
.isEmpty() && !(*it
).maSecurityDescriptor
.empty(),
509 "sc.filter", "XclExpSheetProtection::SaveXml: losing BIFF security descriptor");
510 rWorksheet
->singleElement( XML_protectedRange
,
511 XML_name
, (*it
).maTitle
.isEmpty() ? nullptr : XclXmlUtils::ToOString( (*it
).maTitle
).getStr(),
512 XML_securityDescriptor
, (*it
).maSecurityDescriptorXML
.isEmpty() ? nullptr : XclXmlUtils::ToOString( (*it
).maSecurityDescriptorXML
).getStr(),
513 /* XXX 'password' is not part of OOXML, but Excel2013
514 * writes it if loaded from BIFF, in which case
515 * 'algorithmName', 'hashValue', 'saltValue' and
516 * 'spinCount' are absent; so do we if it was present. */
517 XML_password
, (*it
).mnPasswordVerifier
? OString::number( (*it
).mnPasswordVerifier
, 16).getStr() : nullptr,
518 XML_algorithmName
, (*it
).maAlgorithmName
.isEmpty() ? nullptr : XclXmlUtils::ToOString( (*it
).maAlgorithmName
).getStr(),
519 XML_hashValue
, (*it
).maHashValue
.isEmpty() ? nullptr : XclXmlUtils::ToOString( (*it
).maHashValue
).getStr(),
520 XML_saltValue
, (*it
).maSaltValue
.isEmpty() ? nullptr : XclXmlUtils::ToOString( (*it
).maSaltValue
).getStr(),
521 XML_spinCount
, (*it
).mnSpinCount
? OString::number( (*it
).mnSpinCount
).getStr() : nullptr,
522 XML_sqref
, (*it
).maRangeList
.Is() ? XclXmlUtils::ToOString( *(*it
).maRangeList
).getStr() : nullptr,
525 rWorksheet
->endElement( XML_protectedRanges
);
530 XclExpPassHash::XclExpPassHash(const Sequence
<sal_Int8
>& aHash
) :
531 XclExpRecord(EXC_ID_PASSWORD
, 2),
534 if (aHash
.getLength() >= 2)
536 mnHash
= ((aHash
[0] << 8) & 0xFFFF);
537 mnHash
|= (aHash
[1] & 0xFF);
541 XclExpPassHash::~XclExpPassHash()
545 void XclExpPassHash::WriteBody(XclExpStream
& rStrm
)
550 XclExpFiltermode::XclExpFiltermode() :
551 XclExpEmptyRecord( EXC_ID_FILTERMODE
)
555 XclExpAutofilterinfo::XclExpAutofilterinfo( const ScAddress
& rStartPos
, SCCOL nScCol
) :
556 XclExpUInt16Record( EXC_ID_AUTOFILTERINFO
, static_cast< sal_uInt16
>( nScCol
) ),
557 maStartPos( rStartPos
)
561 ExcFilterCondition::ExcFilterCondition() :
562 nType( EXC_AFTYPE_NOTUSED
),
563 nOper( EXC_AFOPER_EQUAL
),
569 ExcFilterCondition::~ExcFilterCondition()
574 sal_Size
ExcFilterCondition::GetTextBytes() const
576 return pText
? (1 + pText
->GetBufferSize()) : 0;
579 void ExcFilterCondition::SetCondition( sal_uInt8 nTp
, sal_uInt8 nOp
, double fV
, OUString
* pT
)
586 (pT
) ? pText
= new XclExpString( *pT
, EXC_STR_8BITLENGTH
) : pText
= nullptr;
589 void ExcFilterCondition::Save( XclExpStream
& rStrm
)
591 rStrm
<< nType
<< nOper
;
594 case EXC_AFTYPE_DOUBLE
:
597 case EXC_AFTYPE_STRING
:
598 OSL_ENSURE( pText
, "ExcFilterCondition::Save() -- pText is NULL!" );
599 rStrm
<< (sal_uInt32
)0 << (sal_uInt8
) pText
->Len() << (sal_uInt16
)0 << (sal_uInt8
)0;
601 case EXC_AFTYPE_BOOLERR
:
602 rStrm
<< (sal_uInt8
)0 << (sal_uInt8
)((fVal
!= 0) ? 1 : 0) << (sal_uInt32
)0 << (sal_uInt16
)0;
605 rStrm
<< (sal_uInt32
)0 << (sal_uInt32
)0;
609 static const char* lcl_GetOperator( sal_uInt8 nOper
)
613 case EXC_AFOPER_EQUAL
: return "equal";
614 case EXC_AFOPER_GREATER
: return "greaterThan";
615 case EXC_AFOPER_GREATEREQUAL
: return "greaterThanOrEqual";
616 case EXC_AFOPER_LESS
: return "lessThan";
617 case EXC_AFOPER_LESSEQUAL
: return "lessThanOrEqual";
618 case EXC_AFOPER_NOTEQUAL
: return "notEqual";
619 case EXC_AFOPER_NONE
:
620 default: return "**none**";
624 static OString
lcl_GetValue( sal_uInt8 nType
, double fVal
, XclExpString
* pStr
)
628 case EXC_AFTYPE_STRING
: return XclXmlUtils::ToOString( *pStr
);
629 case EXC_AFTYPE_DOUBLE
: return OString::number( fVal
);
630 case EXC_AFTYPE_BOOLERR
: return OString::number( ( fVal
!= 0 ? 1 : 0 ) );
631 default: return OString();
635 void ExcFilterCondition::SaveXml( XclExpXmlStream
& rStrm
)
640 rStrm
.GetCurrentStream()->singleElement( XML_customFilter
,
641 XML_operator
, lcl_GetOperator( nOper
),
642 XML_val
, lcl_GetValue( nType
, fVal
, pText
).getStr(),
646 void ExcFilterCondition::SaveText( XclExpStream
& rStrm
)
648 if( nType
== EXC_AFTYPE_STRING
)
650 OSL_ENSURE( pText
, "ExcFilterCondition::SaveText() -- pText is NULL!" );
651 pText
->WriteFlagField( rStrm
);
652 pText
->WriteBuffer( rStrm
);
656 XclExpAutofilter::XclExpAutofilter( const XclExpRoot
& rRoot
, sal_uInt16 nC
) :
657 XclExpRecord( EXC_ID_AUTOFILTER
, 24 ),
659 meType(FilterCondition
),
665 bool XclExpAutofilter::AddCondition( ScQueryConnect eConn
, sal_uInt8 nType
, sal_uInt8 nOp
,
666 double fVal
, OUString
* pText
, bool bSimple
)
668 if( !aCond
[ 1 ].IsEmpty() )
671 sal_uInt16 nInd
= aCond
[ 0 ].IsEmpty() ? 0 : 1;
674 nFlags
|= (eConn
== SC_OR
) ? EXC_AFFLAG_OR
: EXC_AFFLAG_AND
;
676 nFlags
|= (nInd
== 0) ? EXC_AFFLAG_SIMPLE1
: EXC_AFFLAG_SIMPLE2
;
678 aCond
[ nInd
].SetCondition( nType
, nOp
, fVal
, pText
);
680 AddRecSize( aCond
[ nInd
].GetTextBytes() );
685 bool XclExpAutofilter::HasCondition() const
687 return !aCond
[0].IsEmpty();
690 bool XclExpAutofilter::AddEntry( const ScQueryEntry
& rEntry
)
692 const ScQueryEntry::QueryItemsType
& rItems
= rEntry
.GetQueryItems();
696 if (GetOutput() != EXC_OUTPUT_BINARY
&& rItems
.size() > 1)
697 return AddMultiValueEntry(rEntry
);
699 bool bConflict
= false;
701 const ScQueryEntry::Item
& rItem
= rItems
[0];
702 if (!rItem
.maString
.isEmpty())
704 sText
= rItem
.maString
.getString();
708 case SC_DOES_NOT_CONTAIN
:
710 sText
= "*" + sText
+ "*";
714 case SC_DOES_NOT_BEGIN_WITH
:
718 case SC_DOES_NOT_END_WITH
:
728 bool bLen
= sText
.getLength() > 0;
730 // empty/nonempty fields
731 if (rEntry
.IsQueryByEmpty())
732 bConflict
= !AddCondition( rEntry
.eConnect
, EXC_AFTYPE_EMPTY
, EXC_AFOPER_NONE
, 0.0, nullptr, true );
733 else if(rEntry
.IsQueryByNonEmpty())
734 bConflict
= !AddCondition( rEntry
.eConnect
, EXC_AFTYPE_NOTEMPTY
, EXC_AFOPER_NONE
, 0.0, nullptr, true );
739 sal_uInt32 nIndex
= 0;
740 bool bIsNum
= !bLen
|| GetFormatter().IsNumberFormat( sText
, nIndex
, fVal
);
742 (bIsNum
) ? pText
= nullptr : pText
= &sText
;
745 sal_uInt16 nNewFlags
= 0x0000;
749 nNewFlags
= (EXC_AFFLAG_TOP10
| EXC_AFFLAG_TOP10TOP
);
752 nNewFlags
= EXC_AFFLAG_TOP10
;
755 nNewFlags
= (EXC_AFFLAG_TOP10
| EXC_AFFLAG_TOP10TOP
| EXC_AFFLAG_TOP10PERC
);
758 nNewFlags
= (EXC_AFFLAG_TOP10
| EXC_AFFLAG_TOP10PERC
);
762 bool bNewTop10
= ::get_flag( nNewFlags
, EXC_AFFLAG_TOP10
);
764 bConflict
= HasTop10() && bNewTop10
;
769 if( fVal
< 0 ) fVal
= 0;
770 if( fVal
>= 501 ) fVal
= 500;
771 nFlags
|= (nNewFlags
| (sal_uInt16
)(fVal
) << 7);
776 sal_uInt8 nType
= bIsNum
? EXC_AFTYPE_DOUBLE
: EXC_AFTYPE_STRING
;
777 sal_uInt8 nOper
= EXC_AFOPER_NONE
;
781 case SC_EQUAL
: nOper
= EXC_AFOPER_EQUAL
; break;
782 case SC_LESS
: nOper
= EXC_AFOPER_LESS
; break;
783 case SC_GREATER
: nOper
= EXC_AFOPER_GREATER
; break;
784 case SC_LESS_EQUAL
: nOper
= EXC_AFOPER_LESSEQUAL
; break;
785 case SC_GREATER_EQUAL
: nOper
= EXC_AFOPER_GREATEREQUAL
; break;
786 case SC_NOT_EQUAL
: nOper
= EXC_AFOPER_NOTEQUAL
; break;
790 nOper
= EXC_AFOPER_EQUAL
; break;
791 case SC_DOES_NOT_CONTAIN
:
792 case SC_DOES_NOT_BEGIN_WITH
:
793 case SC_DOES_NOT_END_WITH
:
794 nOper
= EXC_AFOPER_NOTEQUAL
; break;
797 bConflict
= !AddCondition( rEntry
.eConnect
, nType
, nOper
, fVal
, pText
);
804 bool XclExpAutofilter::AddMultiValueEntry( const ScQueryEntry
& rEntry
)
807 const ScQueryEntry::QueryItemsType
& rItems
= rEntry
.GetQueryItems();
808 ScQueryEntry::QueryItemsType::const_iterator itr
= rItems
.begin(), itrEnd
= rItems
.end();
809 for (; itr
!= itrEnd
; ++itr
)
810 maMultiValues
.push_back(itr
->maString
.getString());
815 void XclExpAutofilter::WriteBody( XclExpStream
& rStrm
)
817 rStrm
<< nCol
<< nFlags
;
818 aCond
[ 0 ].Save( rStrm
);
819 aCond
[ 1 ].Save( rStrm
);
820 aCond
[ 0 ].SaveText( rStrm
);
821 aCond
[ 1 ].SaveText( rStrm
);
824 void XclExpAutofilter::SaveXml( XclExpXmlStream
& rStrm
)
826 if (meType
== FilterCondition
&& !HasCondition())
829 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
831 rWorksheet
->startElement( XML_filterColumn
,
832 XML_colId
, OString::number( nCol
).getStr(),
833 // OOXTODO: XML_hiddenButton, AutoFilter12 fHideArrow?
834 // OOXTODO: XML_showButton,
839 case FilterCondition
:
843 rWorksheet
->singleElement( XML_top10
,
844 XML_top
, XclXmlUtils::ToPsz( get_flag( nFlags
, EXC_AFFLAG_TOP10TOP
) ),
845 XML_percent
, XclXmlUtils::ToPsz( get_flag( nFlags
, EXC_AFFLAG_TOP10PERC
) ),
846 XML_val
, OString::number( (nFlags
>> 7 ) ).getStr(),
847 // OOXTODO: XML_filterVal,
851 rWorksheet
->startElement( XML_customFilters
,
852 XML_and
, XclXmlUtils::ToPsz( (nFlags
& EXC_AFFLAG_ANDORMASK
) == EXC_AFFLAG_AND
),
854 aCond
[ 0 ].SaveXml( rStrm
);
855 aCond
[ 1 ].SaveXml( rStrm
);
856 rWorksheet
->endElement( XML_customFilters
);
857 // OOXTODO: XLM_colorFilter, XML_dynamicFilter,
858 // XML_extLst, XML_filters, XML_iconFilter, XML_top10
863 rWorksheet
->startElement(XML_filters
, FSEND
);
864 std::vector
<OUString
>::const_iterator itr
= maMultiValues
.begin(), itrEnd
= maMultiValues
.end();
865 for (; itr
!= itrEnd
; ++itr
)
867 OString aStr
= OUStringToOString(*itr
, RTL_TEXTENCODING_UTF8
);
868 const char* pz
= aStr
.getStr();
869 rWorksheet
->singleElement(XML_filter
, XML_val
, pz
, FSEND
);
871 rWorksheet
->endElement(XML_filters
);
875 rWorksheet
->endElement( XML_filterColumn
);
878 ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot
& rRoot
, SCTAB nTab
, const ScDBData
* pDefinedData
) :
880 pFilterMode( nullptr ),
881 pFilterInfo( nullptr )
882 , mbAutoFilter (false)
884 XclExpNameManager
& rNameMgr
= GetNameManager();
887 bool bAdvanced
= false;
888 const ScDBData
* pData
= (pDefinedData
? pDefinedData
: rRoot
.GetDoc().GetAnonymousDBData(nTab
));
892 bAdvanced
= pData
->GetAdvancedQuerySource( aAdvRange
);
893 bFound
= (pData
->HasQueryParam() || pData
->HasAutoFilter() || bAdvanced
);
898 pData
->GetQueryParam( aParam
);
900 ScRange
aRange( aParam
.nCol1
, aParam
.nRow1
, aParam
.nTab
,
901 aParam
.nCol2
, aParam
.nRow2
, aParam
.nTab
);
902 SCCOL nColCnt
= aParam
.nCol2
- aParam
.nCol1
+ 1;
906 // #i2394# built-in defined names must be sorted by containing sheet name
908 rNameMgr
.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE
, aRange
);
913 // filter criteria, excel allows only same table
914 if( !pDefinedData
&& aAdvRange
.aStart
.Tab() == nTab
)
915 rNameMgr
.InsertBuiltInName( EXC_BUILTIN_CRITERIA
, aAdvRange
);
917 // filter destination range, excel allows only same table
918 if( !aParam
.bInplace
)
920 ScRange
aDestRange( aParam
.nDestCol
, aParam
.nDestRow
, aParam
.nDestTab
);
921 aDestRange
.aEnd
.IncCol( nColCnt
- 1 );
922 if( !pDefinedData
&& aDestRange
.aStart
.Tab() == nTab
)
923 rNameMgr
.InsertBuiltInName( EXC_BUILTIN_EXTRACT
, aDestRange
);
926 pFilterMode
= new XclExpFiltermode
;
931 bool bConflict
= false;
932 bool bContLoop
= true;
934 SCCOLROW nFirstField
= aParam
.GetEntry( 0 ).nField
;
936 // create AUTOFILTER records for filtered columns
937 for( SCSIZE nEntry
= 0; !bConflict
&& bContLoop
&& (nEntry
< aParam
.GetEntryCount()); nEntry
++ )
939 const ScQueryEntry
& rEntry
= aParam
.GetEntry( nEntry
);
941 bContLoop
= rEntry
.bDoQuery
;
944 XclExpAutofilter
* pFilter
= GetByCol( static_cast<SCCOL
>(rEntry
.nField
) - aRange
.aStart
.Col() );
947 bHasOr
|= (rEntry
.eConnect
== SC_OR
);
949 bConflict
= (nEntry
> 1) && bHasOr
;
951 bConflict
= (nEntry
== 1) && (rEntry
.eConnect
== SC_OR
) &&
952 (nFirstField
!= rEntry
.nField
);
954 bConflict
= pFilter
->AddEntry( rEntry
);
958 // additional tests for conflicts
959 for( size_t nPos
= 0, nSize
= maFilterList
.GetSize(); !bConflict
&& (nPos
< nSize
); ++nPos
)
961 XclExpAutofilterRef xFilter
= maFilterList
.GetRecord( nPos
);
962 bConflict
= xFilter
->HasCondition() && xFilter
->HasTop10();
966 maFilterList
.RemoveAllRecords();
968 if( !maFilterList
.IsEmpty() )
969 pFilterMode
= new XclExpFiltermode
;
970 pFilterInfo
= new XclExpAutofilterinfo( aRange
.aStart
, nColCnt
);
972 if (maFilterList
.IsEmpty () && !bConflict
)
978 ExcAutoFilterRecs::~ExcAutoFilterRecs()
984 XclExpAutofilter
* ExcAutoFilterRecs::GetByCol( SCCOL nCol
)
986 XclExpAutofilterRef xFilter
;
987 for( size_t nPos
= 0, nSize
= maFilterList
.GetSize(); nPos
< nSize
; ++nPos
)
989 xFilter
= maFilterList
.GetRecord( nPos
);
990 if( xFilter
->GetCol() == static_cast<sal_uInt16
>(nCol
) )
991 return xFilter
.get();
993 xFilter
.reset( new XclExpAutofilter( GetRoot(), static_cast<sal_uInt16
>(nCol
) ) );
994 maFilterList
.AppendRecord( xFilter
);
995 return xFilter
.get();
998 bool ExcAutoFilterRecs::IsFiltered( SCCOL nCol
)
1000 for( size_t nPos
= 0, nSize
= maFilterList
.GetSize(); nPos
< nSize
; ++nPos
)
1001 if( maFilterList
.GetRecord( nPos
)->GetCol() == static_cast<sal_uInt16
>(nCol
) )
1006 void ExcAutoFilterRecs::AddObjRecs()
1010 ScAddress
aAddr( pFilterInfo
->GetStartPos() );
1011 for( SCCOL nObj
= 0, nCount
= pFilterInfo
->GetColCount(); nObj
< nCount
; nObj
++ )
1013 XclObj
* pObjRec
= new XclObjDropDown( GetObjectManager(), aAddr
, IsFiltered( nObj
) );
1014 GetObjectManager().AddObj( pObjRec
);
1020 void ExcAutoFilterRecs::Save( XclExpStream
& rStrm
)
1023 pFilterMode
->Save( rStrm
);
1025 pFilterInfo
->Save( rStrm
);
1026 maFilterList
.Save( rStrm
);
1029 void ExcAutoFilterRecs::SaveXml( XclExpXmlStream
& rStrm
)
1031 if( maFilterList
.IsEmpty() && !mbAutoFilter
)
1034 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1035 rWorksheet
->startElement( XML_autoFilter
,
1036 XML_ref
, XclXmlUtils::ToOString( maRef
).getStr(),
1038 // OOXTODO: XML_extLst, XML_sortState
1039 if( !maFilterList
.IsEmpty() )
1040 maFilterList
.SaveXml( rStrm
);
1041 rWorksheet
->endElement( XML_autoFilter
);
1044 bool ExcAutoFilterRecs::HasFilterMode() const
1046 return pFilterMode
!= nullptr;
1049 XclExpFilterManager::XclExpFilterManager( const XclExpRoot
& rRoot
) :
1054 void XclExpFilterManager::InitTabFilter( SCTAB nScTab
)
1056 maFilterMap
[ nScTab
].reset( new ExcAutoFilterRecs( GetRoot(), nScTab
, nullptr ) );
1059 XclExpRecordRef
XclExpFilterManager::CreateRecord( SCTAB nScTab
)
1061 XclExpTabFilterRef xRec
;
1062 XclExpTabFilterMap::iterator aIt
= maFilterMap
.find( nScTab
);
1063 if( aIt
!= maFilterMap
.end() )
1071 bool XclExpFilterManager::HasFilterMode( SCTAB nScTab
)
1073 XclExpTabFilterRef xRec
;
1074 XclExpTabFilterMap::iterator aIt
= maFilterMap
.find( nScTab
);
1075 if( aIt
!= maFilterMap
.end() )
1077 return aIt
->second
->HasFilterMode();
1082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */