fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / excrecds.cxx
blob9b316c477d249626089b60429bade5cdf98ff689
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 ) ) : NULL,
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()? NULL : sHash.getStr(),
484 XML_objects, pTabProtect->isOptionEnabled( ScTableProtection::OBJECTS ) ? NULL : XclXmlUtils::ToPsz( true ),
485 XML_scenarios, pTabProtect->isOptionEnabled( ScTableProtection::SCENARIOS ) ? NULL : XclXmlUtils::ToPsz( true ),
486 XML_formatCells, pTabProtect->isOptionEnabled( ScTableProtection::FORMAT_CELLS ) ? XclXmlUtils::ToPsz( false ) : NULL,
487 XML_formatColumns, pTabProtect->isOptionEnabled( ScTableProtection::FORMAT_COLUMNS ) ? XclXmlUtils::ToPsz( false ) : NULL,
488 XML_formatRows, pTabProtect->isOptionEnabled( ScTableProtection::FORMAT_ROWS ) ? XclXmlUtils::ToPsz( false ) : NULL,
489 XML_insertColumns, pTabProtect->isOptionEnabled( ScTableProtection::INSERT_COLUMNS ) ? XclXmlUtils::ToPsz( false ) : NULL,
490 XML_insertRows, pTabProtect->isOptionEnabled( ScTableProtection::INSERT_ROWS ) ? XclXmlUtils::ToPsz( false ) : NULL,
491 XML_insertHyperlinks, pTabProtect->isOptionEnabled( ScTableProtection::INSERT_HYPERLINKS ) ? XclXmlUtils::ToPsz( false ) : NULL,
492 XML_deleteColumns, pTabProtect->isOptionEnabled( ScTableProtection::DELETE_COLUMNS ) ? XclXmlUtils::ToPsz( false ) : NULL,
493 XML_deleteRows, pTabProtect->isOptionEnabled( ScTableProtection::DELETE_ROWS ) ? XclXmlUtils::ToPsz( false ) : NULL,
494 XML_selectLockedCells, pTabProtect->isOptionEnabled( ScTableProtection::SELECT_LOCKED_CELLS ) ? NULL : XclXmlUtils::ToPsz( true ),
495 XML_sort, pTabProtect->isOptionEnabled( ScTableProtection::SORT ) ? XclXmlUtils::ToPsz( false ) : NULL,
496 XML_autoFilter, pTabProtect->isOptionEnabled( ScTableProtection::AUTOFILTER ) ? XclXmlUtils::ToPsz( false ) : NULL,
497 XML_pivotTables, pTabProtect->isOptionEnabled( ScTableProtection::PIVOT_TABLES ) ? XclXmlUtils::ToPsz( false ) : NULL,
498 XML_selectUnlockedCells, pTabProtect->isOptionEnabled( ScTableProtection::SELECT_UNLOCKED_CELLS ) ? NULL : 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() ? NULL : XclXmlUtils::ToOString( (*it).maTitle).getStr(),
512 XML_securityDescriptor, (*it).maSecurityDescriptorXML.isEmpty() ? NULL : 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() : NULL,
518 XML_algorithmName, (*it).maAlgorithmName.isEmpty() ? NULL : XclXmlUtils::ToOString( (*it).maAlgorithmName).getStr(),
519 XML_hashValue, (*it).maHashValue.isEmpty() ? NULL : XclXmlUtils::ToOString( (*it).maHashValue).getStr(),
520 XML_saltValue, (*it).maSaltValue.isEmpty() ? NULL : XclXmlUtils::ToOString( (*it).maSaltValue).getStr(),
521 XML_spinCount, (*it).mnSpinCount ? OString::number( (*it).mnSpinCount).getStr() : NULL,
522 XML_sqref, (*it).maRangeList.Is() ? XclXmlUtils::ToOString( *(*it).maRangeList).getStr() : NULL,
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( NULL )
569 ExcFilterCondition::~ExcFilterCondition()
571 if( pText )
572 delete pText;
575 sal_Size ExcFilterCondition::GetTextBytes() const
577 return pText ? (1 + pText->GetBufferSize()) : 0;
580 void ExcFilterCondition::SetCondition( sal_uInt8 nTp, sal_uInt8 nOp, double fV, OUString* pT )
582 nType = nTp;
583 nOper = nOp;
584 fVal = fV;
586 delete pText;
587 (pT) ? pText = new XclExpString( *pT, EXC_STR_8BITLENGTH ) : pText = NULL;
590 void ExcFilterCondition::Save( XclExpStream& rStrm )
592 rStrm << nType << nOper;
593 switch( nType )
595 case EXC_AFTYPE_DOUBLE:
596 rStrm << fVal;
597 break;
598 case EXC_AFTYPE_STRING:
599 OSL_ENSURE( pText, "ExcFilterCondition::Save() -- pText is NULL!" );
600 rStrm << (sal_uInt32)0 << (sal_uInt8) pText->Len() << (sal_uInt16)0 << (sal_uInt8)0;
601 break;
602 case EXC_AFTYPE_BOOLERR:
603 rStrm << (sal_uInt8)0 << (sal_uInt8)((fVal != 0) ? 1 : 0) << (sal_uInt32)0 << (sal_uInt16)0;
604 break;
605 default:
606 rStrm << (sal_uInt32)0 << (sal_uInt32)0;
610 static const char* lcl_GetOperator( sal_uInt8 nOper )
612 switch( nOper )
614 case EXC_AFOPER_EQUAL: return "equal";
615 case EXC_AFOPER_GREATER: return "greaterThan";
616 case EXC_AFOPER_GREATEREQUAL: return "greaterThanOrEqual";
617 case EXC_AFOPER_LESS: return "lessThan";
618 case EXC_AFOPER_LESSEQUAL: return "lessThanOrEqual";
619 case EXC_AFOPER_NOTEQUAL: return "notEqual";
620 case EXC_AFOPER_NONE:
621 default: return "**none**";
625 static OString lcl_GetValue( sal_uInt8 nType, double fVal, XclExpString* pStr )
627 switch( nType )
629 case EXC_AFTYPE_STRING: return XclXmlUtils::ToOString( *pStr );
630 case EXC_AFTYPE_DOUBLE: return OString::number( fVal );
631 case EXC_AFTYPE_BOOLERR: return OString::number( ( fVal != 0 ? 1 : 0 ) );
632 default: return OString();
636 void ExcFilterCondition::SaveXml( XclExpXmlStream& rStrm )
638 if( IsEmpty() )
639 return;
641 rStrm.GetCurrentStream()->singleElement( XML_customFilter,
642 XML_operator, lcl_GetOperator( nOper ),
643 XML_val, lcl_GetValue( nType, fVal, pText ).getStr(),
644 FSEND );
647 void ExcFilterCondition::SaveText( XclExpStream& rStrm )
649 if( nType == EXC_AFTYPE_STRING )
651 OSL_ENSURE( pText, "ExcFilterCondition::SaveText() -- pText is NULL!" );
652 pText->WriteFlagField( rStrm );
653 pText->WriteBuffer( rStrm );
657 XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC ) :
658 XclExpRecord( EXC_ID_AUTOFILTER, 24 ),
659 XclExpRoot( rRoot ),
660 meType(FilterCondition),
661 nCol( nC ),
662 nFlags( 0 )
666 bool XclExpAutofilter::AddCondition( ScQueryConnect eConn, sal_uInt8 nType, sal_uInt8 nOp,
667 double fVal, OUString* pText, bool bSimple )
669 if( !aCond[ 1 ].IsEmpty() )
670 return false;
672 sal_uInt16 nInd = aCond[ 0 ].IsEmpty() ? 0 : 1;
674 if( nInd == 1 )
675 nFlags |= (eConn == SC_OR) ? EXC_AFFLAG_OR : EXC_AFFLAG_AND;
676 if( bSimple )
677 nFlags |= (nInd == 0) ? EXC_AFFLAG_SIMPLE1 : EXC_AFFLAG_SIMPLE2;
679 aCond[ nInd ].SetCondition( nType, nOp, fVal, pText );
681 AddRecSize( aCond[ nInd ].GetTextBytes() );
683 return true;
686 bool XclExpAutofilter::HasCondition() const
688 return !aCond[0].IsEmpty();
691 bool XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry )
693 const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
694 if (rItems.empty())
695 return true;
697 if (GetOutput() != EXC_OUTPUT_BINARY && rItems.size() > 1)
698 return AddMultiValueEntry(rEntry);
700 bool bConflict = false;
701 OUString sText;
702 const ScQueryEntry::Item& rItem = rItems[0];
703 if (!rItem.maString.isEmpty())
705 sText = rItem.maString.getString();
706 switch( rEntry.eOp )
708 case SC_CONTAINS:
709 case SC_DOES_NOT_CONTAIN:
711 sText = "*" + sText + "*";
713 break;
714 case SC_BEGINS_WITH:
715 case SC_DOES_NOT_BEGIN_WITH:
716 sText += "*";
717 break;
718 case SC_ENDS_WITH:
719 case SC_DOES_NOT_END_WITH:
720 sText = "*" + sText;
721 break;
722 default:
724 //nothing
729 bool bLen = sText.getLength() > 0;
731 // empty/nonempty fields
732 if (rEntry.IsQueryByEmpty())
733 bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_EMPTY, EXC_AFOPER_NONE, 0.0, NULL, true );
734 else if(rEntry.IsQueryByNonEmpty())
735 bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_NOTEMPTY, EXC_AFOPER_NONE, 0.0, NULL, true );
736 // other conditions
737 else
739 double fVal = 0.0;
740 sal_uInt32 nIndex = 0;
741 bool bIsNum = !bLen || GetFormatter().IsNumberFormat( sText, nIndex, fVal );
742 OUString* pText;
743 (bIsNum) ? pText = NULL : pText = &sText;
745 // top10 flags
746 sal_uInt16 nNewFlags = 0x0000;
747 switch( rEntry.eOp )
749 case SC_TOPVAL:
750 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP);
751 break;
752 case SC_BOTVAL:
753 nNewFlags = EXC_AFFLAG_TOP10;
754 break;
755 case SC_TOPPERC:
756 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP | EXC_AFFLAG_TOP10PERC);
757 break;
758 case SC_BOTPERC:
759 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10PERC);
760 break;
761 default:;
763 bool bNewTop10 = ::get_flag( nNewFlags, EXC_AFFLAG_TOP10 );
765 bConflict = HasTop10() && bNewTop10;
766 if( !bConflict )
768 if( bNewTop10 )
770 if( fVal < 0 ) fVal = 0;
771 if( fVal >= 501 ) fVal = 500;
772 nFlags |= (nNewFlags | (sal_uInt16)(fVal) << 7);
774 // normal condition
775 else
777 sal_uInt8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING;
778 sal_uInt8 nOper = EXC_AFOPER_NONE;
780 switch( rEntry.eOp )
782 case SC_EQUAL: nOper = EXC_AFOPER_EQUAL; break;
783 case SC_LESS: nOper = EXC_AFOPER_LESS; break;
784 case SC_GREATER: nOper = EXC_AFOPER_GREATER; break;
785 case SC_LESS_EQUAL: nOper = EXC_AFOPER_LESSEQUAL; break;
786 case SC_GREATER_EQUAL: nOper = EXC_AFOPER_GREATEREQUAL; break;
787 case SC_NOT_EQUAL: nOper = EXC_AFOPER_NOTEQUAL; break;
788 case SC_CONTAINS:
789 case SC_BEGINS_WITH:
790 case SC_ENDS_WITH:
791 nOper = EXC_AFOPER_EQUAL; break;
792 case SC_DOES_NOT_CONTAIN:
793 case SC_DOES_NOT_BEGIN_WITH:
794 case SC_DOES_NOT_END_WITH:
795 nOper = EXC_AFOPER_NOTEQUAL; break;
796 default:;
798 bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText );
802 return bConflict;
805 bool XclExpAutofilter::AddMultiValueEntry( const ScQueryEntry& rEntry )
807 meType = MultiValue;
808 const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
809 ScQueryEntry::QueryItemsType::const_iterator itr = rItems.begin(), itrEnd = rItems.end();
810 for (; itr != itrEnd; ++itr)
811 maMultiValues.push_back(itr->maString.getString());
813 return false;
816 void XclExpAutofilter::WriteBody( XclExpStream& rStrm )
818 rStrm << nCol << nFlags;
819 aCond[ 0 ].Save( rStrm );
820 aCond[ 1 ].Save( rStrm );
821 aCond[ 0 ].SaveText( rStrm );
822 aCond[ 1 ].SaveText( rStrm );
825 void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm )
827 if (meType == FilterCondition && !HasCondition())
828 return;
830 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
832 rWorksheet->startElement( XML_filterColumn,
833 XML_colId, OString::number( nCol ).getStr(),
834 // OOXTODO: XML_hiddenButton, AutoFilter12 fHideArrow?
835 // OOXTODO: XML_showButton,
836 FSEND );
838 switch (meType)
840 case FilterCondition:
842 if( HasTop10() )
844 rWorksheet->singleElement( XML_top10,
845 XML_top, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10TOP ) ),
846 XML_percent, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10PERC ) ),
847 XML_val, OString::number( (nFlags >> 7 ) ).getStr(),
848 // OOXTODO: XML_filterVal,
849 FSEND );
852 rWorksheet->startElement( XML_customFilters,
853 XML_and, XclXmlUtils::ToPsz( (nFlags & EXC_AFFLAG_ANDORMASK) == EXC_AFFLAG_AND ),
854 FSEND );
855 aCond[ 0 ].SaveXml( rStrm );
856 aCond[ 1 ].SaveXml( rStrm );
857 rWorksheet->endElement( XML_customFilters );
858 // OOXTODO: XLM_colorFilter, XML_dynamicFilter,
859 // XML_extLst, XML_filters, XML_iconFilter, XML_top10
861 break;
862 case MultiValue:
864 rWorksheet->startElement(XML_filters, FSEND);
865 std::vector<OUString>::const_iterator itr = maMultiValues.begin(), itrEnd = maMultiValues.end();
866 for (; itr != itrEnd; ++itr)
868 OString aStr = OUStringToOString(*itr, RTL_TEXTENCODING_UTF8);
869 const char* pz = aStr.getStr();
870 rWorksheet->singleElement(XML_filter, XML_val, pz, FSEND);
872 rWorksheet->endElement(XML_filters);
874 break;
876 rWorksheet->endElement( XML_filterColumn );
879 ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab ) :
880 XclExpRoot( rRoot ),
881 pFilterMode( NULL ),
882 pFilterInfo( NULL )
883 , mbAutoFilter (false)
885 XclExpNameManager& rNameMgr = GetNameManager();
887 bool bFound = false;
888 bool bAdvanced = false;
889 ScDBData* pData = rRoot.GetDoc().GetAnonymousDBData(nTab);
890 ScRange aAdvRange;
891 if (pData)
893 bAdvanced = pData->GetAdvancedQuerySource( aAdvRange );
894 bFound = (pData->HasQueryParam() || pData->HasAutoFilter() || bAdvanced);
896 if( bFound )
898 ScQueryParam aParam;
899 pData->GetQueryParam( aParam );
901 ScRange aRange( aParam.nCol1, aParam.nRow1, aParam.nTab,
902 aParam.nCol2, aParam.nRow2, aParam.nTab );
903 SCCOL nColCnt = aParam.nCol2 - aParam.nCol1 + 1;
905 maRef = aRange;
907 // #i2394# built-in defined names must be sorted by containing sheet name
908 rNameMgr.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE, aRange );
910 // advanced filter
911 if( bAdvanced )
913 // filter criteria, excel allows only same table
914 if( 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( 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( 1 );
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 != NULL;
1049 XclExpFilterManager::XclExpFilterManager( const XclExpRoot& rRoot ) :
1050 XclExpRoot( rRoot )
1054 void XclExpFilterManager::InitTabFilter( SCTAB nScTab )
1056 maFilterMap[ nScTab ].reset( new ExcAutoFilterRecs( GetRoot(), nScTab ) );
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: */