Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / excel / excrecds.cxx
bloba1e3acd228f1707bfc83bb03796219589d3075fc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <map>
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>
52 #include <string.h>
54 #include "global.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"
61 #include "attrib.hxx"
62 #include "progress.hxx"
63 #include "dociter.hxx"
64 #include "rangenam.hxx"
65 #include "dbdata.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"
73 #include "excdoc.hxx"
74 #include "xeescher.hxx"
75 #include "xeformula.hxx"
76 #include "xelink.hxx"
77 #include "xename.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
116 0x62, 0x50, 0x3f,
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 )
135 SaveCont( rStrm );
138 void ExcRecord::SaveXml( XclExpXmlStream& /*rStrm*/ )
142 //--------------------------------------------------------- class ExcEmptyRec -
144 void ExcEmptyRec::Save( XclExpStream& /*rStrm*/ )
148 sal_uInt16 ExcEmptyRec::GetNum() const
150 return 0;
153 sal_Size ExcEmptyRec::GetLen() const
155 return 0;
158 //--------------------------------------------------------- class ExcDummyRec -
160 void ExcDummyRec::Save( XclExpStream& rStrm )
162 rStrm.Write( GetData(), GetLen() ); // raw write mode
165 sal_uInt16 ExcDummyRec::GetNum() const
167 return 0x0000;
170 //------------------------------------------------------- class ExcBoolRecord -
172 void ExcBoolRecord::SaveCont( XclExpStream& rStrm )
174 rStrm << (sal_uInt16)(bVal ? 0x0001 : 0x0000);
177 sal_Size ExcBoolRecord::GetLen() const
179 return 2;
182 //--------------------------------------------------------- class ExcBof_Base -
184 ExcBof_Base::ExcBof_Base()
185 : nDocType(0)
186 , nVers(0)
187 , nRupBuild(0x096C) // copied from Excel
188 , nRupYear(0x07C9) // copied from Excel
192 //-------------------------------------------------------------- class ExcBof -
194 ExcBof::ExcBof()
196 nDocType = 0x0010;
197 nVers = 0x0500;
200 void ExcBof::SaveCont( XclExpStream& rStrm )
202 rStrm << nVers << nDocType << nRupBuild << nRupYear;
205 sal_uInt16 ExcBof::GetNum() const
207 return 0x0809;
210 sal_Size ExcBof::GetLen() const
212 return 8;
215 //------------------------------------------------------------- class ExcBofW -
217 ExcBofW::ExcBofW()
219 nDocType = 0x0005;
220 nVers = 0x0500;
223 void ExcBofW::SaveCont( XclExpStream& rStrm )
225 rStrm << nVers << nDocType << nRupBuild << nRupYear;
228 sal_uInt16 ExcBofW::GetNum() const
230 return 0x0809;
233 sal_Size ExcBofW::GetLen() const
235 return 8;
238 //-------------------------------------------------------------- class ExcEof -
240 sal_uInt16 ExcEof::GetNum() const
242 return 0x000A;
245 sal_Size ExcEof::GetLen() const
247 return 0;
250 //--------------------------------------------------------- class ExcDummy_00 -
252 sal_Size ExcDummy_00::GetLen() const
254 return nMyLen;
257 const sal_uInt8* ExcDummy_00::GetData() const
259 return pMyData;
262 //-------------------------------------------------------- class ExcDummy_04x -
264 sal_Size ExcDummy_040::GetLen() const
266 return nMyLen;
269 const sal_uInt8* ExcDummy_040::GetData() const
271 return pMyData;
274 sal_Size ExcDummy_041::GetLen() const
276 return nMyLen;
279 const sal_uInt8* ExcDummy_041::GetData() const
281 return pMyData;
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
295 return 0x0022;
298 void Exc1904::SaveXml( XclExpXmlStream& rStrm )
300 bool bISOIEC = ( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 );
302 if( bISOIEC )
304 rStrm.WriteAttributes(
305 XML_dateCompatibility, XclXmlUtils::ToPsz( bDateCompatibility ),
306 FSEND );
309 if( !bISOIEC || bDateCompatibility )
311 rStrm.WriteAttributes(
312 XML_date1904, XclXmlUtils::ToPsz( bVal ),
313 FSEND );
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 ),
323 nTab( nTabNum )
327 ExcBundlesheetBase::ExcBundlesheetBase() :
328 m_nStrPos( STREAM_SEEK_TO_END ),
329 m_nOwnPos( STREAM_SEEK_TO_END ),
330 nGrbit( 0x0000 ),
331 nTab( SCTAB_GLOBAL )
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
345 return 0x0085;
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)
360 << nGrbit;
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
373 return nMyLen;
376 const sal_uInt8* ExcDummy_02a::GetData() const
378 return pMyData;
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 )
401 if( bFitToPages )
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,
421 FSEND );
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() ),
449 FSEND );
452 // XclExpDocProtection ===============================================================
454 XclExpProtection::XclExpProtection(bool bValue) :
455 XclExpBoolRecord(EXC_ID_PROTECT, bValue)
459 XclExpSheetProtection::XclExpSheetProtection(bool bValue, SCTAB nTab ) :
460 XclExpProtection( bValue),
461 mnTab(nTab)
465 void XclExpSheetProtection::SaveXml( XclExpXmlStream& rStrm )
467 ScDocument& rDoc = rStrm.GetRoot().GetDoc();
468 const ScTableProtection* pTabProtect = rDoc.GetTabProtection(mnTab);
469 if ( pTabProtect )
471 Sequence<sal_Int8> aHash = pTabProtect->getPasswordHash(PASSHASH_XL);
472 OString sHash;
473 if (aHash.getLength() >= 2)
475 sHash = OString::number(
476 ( static_cast<sal_uInt8>(aHash[0]) << 8
477 | static_cast<sal_uInt8>(aHash[1]) ),
478 16 );
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 ),
499 FSEND );
501 const ::std::vector<ScEnhancedProtection>& rProts( pTabProtect->getEnhancedProtection());
502 if (!rProts.empty())
504 rWorksheet->startElement( XML_protectedRanges, FSEND);
505 for (::std::vector<ScEnhancedProtection>::const_iterator it( rProts.begin()), end( rProts.end());
506 it != end; ++it)
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,
523 FSEND);
525 rWorksheet->endElement( XML_protectedRanges);
530 XclExpPassHash::XclExpPassHash(const Sequence<sal_Int8>& aHash) :
531 XclExpRecord(EXC_ID_PASSWORD, 2),
532 mnHash(0x0000)
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)
547 rStrm << mnHash;
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 ),
564 fVal( 0.0 ),
565 pText( nullptr )
569 ExcFilterCondition::~ExcFilterCondition()
571 delete pText;
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 )
581 nType = nTp;
582 nOper = nOp;
583 fVal = fV;
585 delete pText;
586 (pT) ? pText = new XclExpString( *pT, EXC_STR_8BITLENGTH ) : pText = nullptr;
589 void ExcFilterCondition::Save( XclExpStream& rStrm )
591 rStrm << nType << nOper;
592 switch( nType )
594 case EXC_AFTYPE_DOUBLE:
595 rStrm << fVal;
596 break;
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;
600 break;
601 case EXC_AFTYPE_BOOLERR:
602 rStrm << (sal_uInt8)0 << (sal_uInt8)((fVal != 0) ? 1 : 0) << (sal_uInt32)0 << (sal_uInt16)0;
603 break;
604 default:
605 rStrm << (sal_uInt32)0 << (sal_uInt32)0;
609 static const char* lcl_GetOperator( sal_uInt8 nOper )
611 switch( 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 )
626 switch( nType )
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 )
637 if( IsEmpty() )
638 return;
640 rStrm.GetCurrentStream()->singleElement( XML_customFilter,
641 XML_operator, lcl_GetOperator( nOper ),
642 XML_val, lcl_GetValue( nType, fVal, pText ).getStr(),
643 FSEND );
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 ),
658 XclExpRoot( rRoot ),
659 meType(FilterCondition),
660 nCol( nC ),
661 nFlags( 0 )
665 bool XclExpAutofilter::AddCondition( ScQueryConnect eConn, sal_uInt8 nType, sal_uInt8 nOp,
666 double fVal, OUString* pText, bool bSimple )
668 if( !aCond[ 1 ].IsEmpty() )
669 return false;
671 sal_uInt16 nInd = aCond[ 0 ].IsEmpty() ? 0 : 1;
673 if( nInd == 1 )
674 nFlags |= (eConn == SC_OR) ? EXC_AFFLAG_OR : EXC_AFFLAG_AND;
675 if( bSimple )
676 nFlags |= (nInd == 0) ? EXC_AFFLAG_SIMPLE1 : EXC_AFFLAG_SIMPLE2;
678 aCond[ nInd ].SetCondition( nType, nOp, fVal, pText );
680 AddRecSize( aCond[ nInd ].GetTextBytes() );
682 return true;
685 bool XclExpAutofilter::HasCondition() const
687 return !aCond[0].IsEmpty();
690 bool XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry )
692 const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
693 if (rItems.empty())
694 return true;
696 if (GetOutput() != EXC_OUTPUT_BINARY && rItems.size() > 1)
697 return AddMultiValueEntry(rEntry);
699 bool bConflict = false;
700 OUString sText;
701 const ScQueryEntry::Item& rItem = rItems[0];
702 if (!rItem.maString.isEmpty())
704 sText = rItem.maString.getString();
705 switch( rEntry.eOp )
707 case SC_CONTAINS:
708 case SC_DOES_NOT_CONTAIN:
710 sText = "*" + sText + "*";
712 break;
713 case SC_BEGINS_WITH:
714 case SC_DOES_NOT_BEGIN_WITH:
715 sText += "*";
716 break;
717 case SC_ENDS_WITH:
718 case SC_DOES_NOT_END_WITH:
719 sText = "*" + sText;
720 break;
721 default:
723 //nothing
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 );
735 // other conditions
736 else
738 double fVal = 0.0;
739 sal_uInt32 nIndex = 0;
740 bool bIsNum = !bLen || GetFormatter().IsNumberFormat( sText, nIndex, fVal );
741 OUString* pText;
742 (bIsNum) ? pText = nullptr : pText = &sText;
744 // top10 flags
745 sal_uInt16 nNewFlags = 0x0000;
746 switch( rEntry.eOp )
748 case SC_TOPVAL:
749 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP);
750 break;
751 case SC_BOTVAL:
752 nNewFlags = EXC_AFFLAG_TOP10;
753 break;
754 case SC_TOPPERC:
755 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP | EXC_AFFLAG_TOP10PERC);
756 break;
757 case SC_BOTPERC:
758 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10PERC);
759 break;
760 default:;
762 bool bNewTop10 = ::get_flag( nNewFlags, EXC_AFFLAG_TOP10 );
764 bConflict = HasTop10() && bNewTop10;
765 if( !bConflict )
767 if( bNewTop10 )
769 if( fVal < 0 ) fVal = 0;
770 if( fVal >= 501 ) fVal = 500;
771 nFlags |= (nNewFlags | (sal_uInt16)(fVal) << 7);
773 // normal condition
774 else
776 sal_uInt8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING;
777 sal_uInt8 nOper = EXC_AFOPER_NONE;
779 switch( rEntry.eOp )
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;
787 case SC_CONTAINS:
788 case SC_BEGINS_WITH:
789 case SC_ENDS_WITH:
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;
795 default:;
797 bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText );
801 return bConflict;
804 bool XclExpAutofilter::AddMultiValueEntry( const ScQueryEntry& rEntry )
806 meType = MultiValue;
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());
812 return false;
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())
827 return;
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,
835 FSEND );
837 switch (meType)
839 case FilterCondition:
841 if( HasTop10() )
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,
848 FSEND );
851 rWorksheet->startElement( XML_customFilters,
852 XML_and, XclXmlUtils::ToPsz( (nFlags & EXC_AFFLAG_ANDORMASK) == EXC_AFFLAG_AND ),
853 FSEND );
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
860 break;
861 case MultiValue:
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);
873 break;
875 rWorksheet->endElement( XML_filterColumn );
878 ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab, const ScDBData* pDefinedData ) :
879 XclExpRoot( rRoot ),
880 pFilterMode( nullptr ),
881 pFilterInfo( nullptr )
882 , mbAutoFilter (false)
884 XclExpNameManager& rNameMgr = GetNameManager();
886 bool bFound = false;
887 bool bAdvanced = false;
888 const ScDBData* pData = (pDefinedData ? pDefinedData : rRoot.GetDoc().GetAnonymousDBData(nTab));
889 ScRange aAdvRange;
890 if (pData)
892 bAdvanced = pData->GetAdvancedQuerySource( aAdvRange );
893 bFound = (pData->HasQueryParam() || pData->HasAutoFilter() || bAdvanced);
895 if( bFound )
897 ScQueryParam aParam;
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;
904 maRef = aRange;
906 // #i2394# built-in defined names must be sorted by containing sheet name
907 if (!pDefinedData)
908 rNameMgr.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE, aRange );
910 // advanced filter
911 if( bAdvanced )
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;
928 // AutoFilter
929 else
931 bool bConflict = false;
932 bool bContLoop = true;
933 bool bHasOr = false;
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;
942 if( bContLoop )
944 XclExpAutofilter* pFilter = GetByCol( static_cast<SCCOL>(rEntry.nField) - aRange.aStart.Col() );
946 if( nEntry > 0 )
947 bHasOr |= (rEntry.eConnect == SC_OR);
949 bConflict = (nEntry > 1) && bHasOr;
950 if( !bConflict )
951 bConflict = (nEntry == 1) && (rEntry.eConnect == SC_OR) &&
952 (nFirstField != rEntry.nField);
953 if( !bConflict )
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();
965 if( bConflict )
966 maFilterList.RemoveAllRecords();
968 if( !maFilterList.IsEmpty() )
969 pFilterMode = new XclExpFiltermode;
970 pFilterInfo = new XclExpAutofilterinfo( aRange.aStart, nColCnt );
972 if (maFilterList.IsEmpty () && !bConflict)
973 mbAutoFilter = true;
978 ExcAutoFilterRecs::~ExcAutoFilterRecs()
980 delete pFilterMode;
981 delete pFilterInfo;
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) )
1002 return true;
1003 return false;
1006 void ExcAutoFilterRecs::AddObjRecs()
1008 if( pFilterInfo )
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 );
1015 aAddr.IncCol();
1020 void ExcAutoFilterRecs::Save( XclExpStream& rStrm )
1022 if( pFilterMode )
1023 pFilterMode->Save( rStrm );
1024 if( pFilterInfo )
1025 pFilterInfo->Save( rStrm );
1026 maFilterList.Save( rStrm );
1029 void ExcAutoFilterRecs::SaveXml( XclExpXmlStream& rStrm )
1031 if( maFilterList.IsEmpty() && !mbAutoFilter )
1032 return;
1034 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1035 rWorksheet->startElement( XML_autoFilter,
1036 XML_ref, XclXmlUtils::ToOString( maRef ).getStr(),
1037 FSEND );
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 ) :
1050 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() )
1065 xRec = aIt->second;
1066 xRec->AddObjRecs();
1068 return xRec;
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();
1079 return false;
1082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */