xref: /AOO41X/main/sc/source/filter/excel/excrecds.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 //------------------------------------------------------------------------
30 
31 #include "excrecds.hxx"
32 
33 #include <map>
34 #include <filter/msfilter/countryid.hxx>
35 
36 #include "scitems.hxx"
37 #include <editeng/eeitem.hxx>
38 
39 #include <sfx2/objsh.hxx>
40 
41 #include <editeng/editdata.hxx>
42 #include <editeng/editeng.hxx>
43 #include <editeng/editobj.hxx>
44 #include <editeng/editstat.hxx>
45 
46 #include <editeng/flditem.hxx>
47 #include <editeng/flstitem.hxx>
48 
49 #include <svx/algitem.hxx>
50 #include <editeng/boxitem.hxx>
51 #include <editeng/brshitem.hxx>
52 #include <svx/pageitem.hxx>
53 #include <editeng/paperinf.hxx>
54 #include <editeng/sizeitem.hxx>
55 #include <editeng/ulspitem.hxx>
56 #include <editeng/fhgtitem.hxx>
57 #include <editeng/escpitem.hxx>
58 #include <svl/intitem.hxx>
59 #include <svl/zforlist.hxx>
60 #include <svl/zformat.hxx>
61 #include <svtools/ctrltool.hxx>
62 
63 #define _SVSTDARR_USHORTS
64 #include <svl/svstdarr.hxx>
65 
66 #include <string.h>
67 
68 #include "global.hxx"
69 #include "globstr.hrc"
70 #include "docpool.hxx"
71 #include "patattr.hxx"
72 #include "cell.hxx"
73 #include "document.hxx"
74 #include "scextopt.hxx"
75 #include "patattr.hxx"
76 #include "attrib.hxx"
77 #include "progress.hxx"
78 #include "dociter.hxx"
79 #include "rangenam.hxx"
80 #include "dbcolect.hxx"
81 #include "stlsheet.hxx"
82 #include "stlpool.hxx"
83 #include "editutil.hxx"
84 #include "formula/errorcodes.hxx"
85 
86 #include "excdoc.hxx"
87 #include "xeescher.hxx"
88 #include "xeformula.hxx"
89 #include "xelink.hxx"
90 #include "xename.hxx"
91 #include "xecontent.hxx"
92 
93 #include "xcl97rec.hxx"
94 
95 using namespace ::oox;
96 
97 using ::com::sun::star::uno::Sequence;
98 using ::rtl::OString;
99 
100 //--------------------------------------------------------- class ExcDummy_00 -
101 const sal_uInt8     ExcDummy_00::pMyData[] = {
102     0x5c, 0x00, 0x20, 0x00, 0x04, 'C',  'a',  'l',  'c',    // WRITEACCESS
103     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
104     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
105     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
106 };
107 const sal_Size ExcDummy_00::nMyLen = sizeof( ExcDummy_00::pMyData );
108 
109 //-------------------------------------------------------- class ExcDummy_04x -
110 const sal_uInt8     ExcDummy_040::pMyData[] = {
111     0x40, 0x00, 0x02, 0x00, 0x00, 0x00,                     // BACKUP
112     0x8d, 0x00, 0x02, 0x00, 0x00, 0x00,                     // HIDEOBJ
113 };
114 const sal_Size ExcDummy_040::nMyLen = sizeof( ExcDummy_040::pMyData );
115 
116 const sal_uInt8     ExcDummy_041::pMyData[] = {
117     0x0e, 0x00, 0x02, 0x00, 0x01, 0x00,                     // PRECISION
118     0xda, 0x00, 0x02, 0x00, 0x00, 0x00                      // BOOKBOOL
119 };
120 const sal_Size ExcDummy_041::nMyLen = sizeof( ExcDummy_041::pMyData );
121 
122 //-------------------------------------------------------- class ExcDummy_02a -
123 const sal_uInt8      ExcDummy_02a::pMyData[] = {
124     0x0d, 0x00, 0x02, 0x00, 0x01, 0x00,                     // CALCMODE
125     0x0c, 0x00, 0x02, 0x00, 0x64, 0x00,                     // CALCCOUNT
126     0x0f, 0x00, 0x02, 0x00, 0x01, 0x00,                     // REFMODE
127     0x11, 0x00, 0x02, 0x00, 0x00, 0x00,                     // ITERATION
128     0x10, 0x00, 0x08, 0x00, 0xfc, 0xa9, 0xf1, 0xd2, 0x4d,   // DELTA
129     0x62, 0x50, 0x3f,
130     0x5f, 0x00, 0x02, 0x00, 0x01, 0x00                      // SAVERECALC
131 };
132 const sal_Size ExcDummy_02a::nMyLen = sizeof( ExcDummy_02a::pMyData );
133 
134 //----------------------------------------------------------- class ExcRecord -
135 
Save(XclExpStream & rStrm)136 void ExcRecord::Save( XclExpStream& rStrm )
137 {
138     SetRecHeader( GetNum(), GetLen() );
139     XclExpRecord::Save( rStrm );
140 }
141 
SaveCont(XclExpStream &)142 void ExcRecord::SaveCont( XclExpStream& /*rStrm*/ )
143 {
144 }
145 
WriteBody(XclExpStream & rStrm)146 void ExcRecord::WriteBody( XclExpStream& rStrm )
147 {
148     SaveCont( rStrm );
149 }
150 
151 
152 //--------------------------------------------------------- class ExcEmptyRec -
153 
Save(XclExpStream &)154 void ExcEmptyRec::Save( XclExpStream& /*rStrm*/ )
155 {
156 }
157 
158 
GetNum() const159 sal_uInt16 ExcEmptyRec::GetNum() const
160 {
161     return 0;
162 }
163 
164 
GetLen() const165 sal_Size ExcEmptyRec::GetLen() const
166 {
167     return 0;
168 }
169 
170 
171 
172 //------------------------------------------------------- class ExcRecordList -
173 
~ExcRecordList()174 ExcRecordList::~ExcRecordList()
175 {
176     for( ExcRecord* pRec = First(); pRec; pRec = Next() )
177         delete pRec;
178 }
179 
180 
Save(XclExpStream & rStrm)181 void ExcRecordList::Save( XclExpStream& rStrm )
182 {
183     for( ExcRecord* pRec = First(); pRec; pRec = Next() )
184         pRec->Save( rStrm );
185 }
186 
187 
188 
189 //--------------------------------------------------------- class ExcDummyRec -
190 
Save(XclExpStream & rStrm)191 void ExcDummyRec::Save( XclExpStream& rStrm )
192 {
193     rStrm.Write( GetData(), GetLen() );        // raw write mode
194 }
195 
196 
GetNum(void) const197 sal_uInt16 ExcDummyRec::GetNum( void ) const
198 {
199     return 0x0000;
200 }
201 
202 
203 
204 //------------------------------------------------------- class ExcBoolRecord -
205 
SaveCont(XclExpStream & rStrm)206 void ExcBoolRecord::SaveCont( XclExpStream& rStrm )
207 {
208     rStrm << (sal_uInt16)(bVal ? 0x0001 : 0x0000);
209 }
210 
211 
GetLen(void) const212 sal_Size ExcBoolRecord::GetLen( void ) const
213 {
214     return 2;
215 }
216 
217 
218 
219 
220 //--------------------------------------------------------- class ExcBof_Base -
221 
ExcBof_Base()222 ExcBof_Base::ExcBof_Base() :
223     nRupBuild( 0x096C ),    // copied from Excel
224     nRupYear( 0x07C9 )      // copied from Excel
225 {
226 }
227 
228 
229 
230 //-------------------------------------------------------------- class ExcBof -
231 
ExcBof(void)232 ExcBof::ExcBof( void )
233 {
234     nDocType = 0x0010;
235     nVers = 0x0500;
236 }
237 
238 
SaveCont(XclExpStream & rStrm)239 void ExcBof::SaveCont( XclExpStream& rStrm )
240 {
241     rStrm << nVers << nDocType << nRupBuild << nRupYear;
242 }
243 
244 
GetNum(void) const245 sal_uInt16 ExcBof::GetNum( void ) const
246 {
247     return 0x0809;
248 }
249 
250 
GetLen(void) const251 sal_Size ExcBof::GetLen( void ) const
252 {
253     return 8;
254 }
255 
256 
257 
258 //------------------------------------------------------------- class ExcBofW -
259 
ExcBofW(void)260 ExcBofW::ExcBofW( void )
261 {
262     nDocType = 0x0005;
263     nVers = 0x0500;
264 }
265 
266 
SaveCont(XclExpStream & rStrm)267 void ExcBofW::SaveCont( XclExpStream& rStrm )
268 {
269     rStrm << nVers << nDocType << nRupBuild << nRupYear;
270 }
271 
272 
273 
GetNum(void) const274 sal_uInt16 ExcBofW::GetNum( void ) const
275 {
276     return 0x0809;
277 }
278 
279 
280 
GetLen(void) const281 sal_Size ExcBofW::GetLen( void ) const
282 {
283     return 8;
284 }
285 
286 
287 
288 //-------------------------------------------------------------- class ExcEof -
289 
GetNum(void) const290 sal_uInt16 ExcEof::GetNum( void ) const
291 {
292     return 0x000A;
293 }
294 
295 
GetLen(void) const296 sal_Size ExcEof::GetLen( void ) const
297 {
298     return 0;
299 }
300 
301 
302 
303 //--------------------------------------------------------- class ExcDummy_00 -
304 
GetLen(void) const305 sal_Size ExcDummy_00::GetLen( void ) const
306 {
307     return nMyLen;
308 }
309 
310 
GetData(void) const311 const sal_uInt8* ExcDummy_00::GetData( void ) const
312 {
313     return pMyData;
314 }
315 
316 
317 
318 //-------------------------------------------------------- class ExcDummy_04x -
319 
GetLen(void) const320 sal_Size ExcDummy_040::GetLen( void ) const
321 {
322     return nMyLen;
323 }
324 
325 
GetData(void) const326 const sal_uInt8* ExcDummy_040::GetData( void ) const
327 {
328     return pMyData;
329 }
330 
331 
332 
333 
GetLen(void) const334 sal_Size ExcDummy_041::GetLen( void ) const
335 {
336     return nMyLen;
337 }
338 
339 
GetData(void) const340 const sal_uInt8* ExcDummy_041::GetData( void ) const
341 {
342     return pMyData;
343 }
344 
345 
346 
347 //------------------------------------------------------------- class Exc1904 -
348 
Exc1904(ScDocument & rDoc)349 Exc1904::Exc1904( ScDocument& rDoc )
350 {
351     Date* pDate = rDoc.GetFormatTable()->GetNullDate();
352     bVal = pDate ? (*pDate == Date( 1, 1, 1904 )) : sal_False;
353 }
354 
355 
GetNum(void) const356 sal_uInt16 Exc1904::GetNum( void ) const
357 {
358     return 0x0022;
359 }
360 
361 
SaveXml(XclExpXmlStream & rStrm)362 void Exc1904::SaveXml( XclExpXmlStream& rStrm )
363 {
364     rStrm.WriteAttributes(
365             XML_date1904, XclXmlUtils::ToPsz( bVal ),
366             FSEND );
367 }
368 
369 
370 
371 //------------------------------------------------------ class ExcBundlesheet -
372 
ExcBundlesheetBase(RootData & rRootData,SCTAB nTabNum)373 ExcBundlesheetBase::ExcBundlesheetBase( RootData& rRootData, SCTAB nTabNum ) :
374     nStrPos( STREAM_SEEK_TO_END ),
375     nOwnPos( STREAM_SEEK_TO_END ),
376     nGrbit( rRootData.pER->GetTabInfo().IsVisibleTab( nTabNum ) ? 0x0000 : 0x0001 ),
377     nTab( nTabNum )
378 {
379 }
380 
381 
ExcBundlesheetBase()382 ExcBundlesheetBase::ExcBundlesheetBase() :
383     nStrPos( STREAM_SEEK_TO_END ),
384     nOwnPos( STREAM_SEEK_TO_END ),
385     nGrbit( 0x0000 ),
386     nTab( SCTAB_GLOBAL )
387 {
388 }
389 
390 
UpdateStreamPos(XclExpStream & rStrm)391 void ExcBundlesheetBase::UpdateStreamPos( XclExpStream& rStrm )
392 {
393     rStrm.SetSvStreamPos( nOwnPos );
394     rStrm.DisableEncryption();
395     rStrm << static_cast<sal_uInt32>(nStrPos);
396     rStrm.EnableEncryption();
397 }
398 
399 
GetNum(void) const400 sal_uInt16 ExcBundlesheetBase::GetNum( void ) const
401 {
402     return 0x0085;
403 }
404 
405 
406 
407 
ExcBundlesheet(RootData & rRootData,SCTAB _nTab)408 ExcBundlesheet::ExcBundlesheet( RootData& rRootData, SCTAB _nTab ) :
409     ExcBundlesheetBase( rRootData, _nTab )
410 {
411     String sTabName = rRootData.pER->GetTabInfo().GetScTabName( _nTab );
412     DBG_ASSERT( sTabName.Len() < 256, "ExcBundlesheet::ExcBundlesheet - table name too long" );
413     aName = ByteString( sTabName, rRootData.pER->GetTextEncoding() );
414 }
415 
416 
SaveCont(XclExpStream & rStrm)417 void ExcBundlesheet::SaveCont( XclExpStream& rStrm )
418 {
419     nOwnPos = rStrm.GetSvStreamPos();
420     rStrm   << (sal_uInt32) 0x00000000              // dummy (stream position of the sheet)
421             << nGrbit;
422     rStrm.WriteByteString( aName );             // 8 bit length, max 255 chars
423 }
424 
425 
GetLen() const426 sal_Size ExcBundlesheet::GetLen() const
427 {
428     return 7 + Min( aName.Len(), (xub_StrLen) 255 );
429 }
430 
431 
432 //--------------------------------------------------------- class ExcDummy_02 -
433 
GetLen(void) const434 sal_Size ExcDummy_02a::GetLen( void ) const
435 {
436     return nMyLen;
437 }
438 
GetData(void) const439 const sal_uInt8* ExcDummy_02a::GetData( void ) const
440 {
441     return pMyData;
442 }
443 //--------------------------------------------------------- class ExcDummy_02 -
444 
XclExpCountry(const XclExpRoot & rRoot)445 XclExpCountry::XclExpCountry( const XclExpRoot& rRoot ) :
446     XclExpRecord( EXC_ID_COUNTRY, 4 )
447 {
448     /*  #i31530# set document country as UI country too -
449         needed for correct behaviour of number formats. */
450     mnUICountry = mnDocCountry = static_cast< sal_uInt16 >(
451         ::msfilter::ConvertLanguageToCountry( rRoot.GetDocLanguage() ) );
452 }
453 
WriteBody(XclExpStream & rStrm)454 void XclExpCountry::WriteBody( XclExpStream& rStrm )
455 {
456     rStrm << mnUICountry << mnDocCountry;
457 }
458 
459 // XclExpWsbool ===============================================================
460 
XclExpWsbool(bool bFitToPages,SCTAB nScTab,XclExpFilterManager * pManager)461 XclExpWsbool::XclExpWsbool( bool bFitToPages, SCTAB nScTab, XclExpFilterManager* pManager )
462     : XclExpUInt16Record( EXC_ID_WSBOOL, EXC_WSBOOL_DEFAULTFLAGS )
463     , mnScTab( nScTab )
464     , mpManager( pManager )
465 {
466     if( bFitToPages )
467         SetValue( GetValue() | EXC_WSBOOL_FITTOPAGE );
468 }
469 
SaveXml(XclExpXmlStream & rStrm)470 void XclExpWsbool::SaveXml( XclExpXmlStream& rStrm )
471 {
472     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
473     rWorksheet->startElement( XML_sheetPr,
474             // OOXTODO: XML_syncHorizontal,
475             // OOXTODO: XML_syncVertical,
476             // OOXTODO: XML_syncRef,
477             // OOXTODO: XML_transitionEvaluation,
478             // OOXTODO: XML_transitionEntry,
479             // OOXTODO: XML_published,
480             // OOXTODO: XML_codeName,
481             XML_filterMode, mpManager ? XclXmlUtils::ToPsz( mpManager->HasFilterMode( mnScTab ) ) : NULL,
482             // OOXTODO: XML_enableFormatConditionsCalculation,
483             FSEND );
484     // OOXTODO: elements XML_tabColor, XML_outlinePr
485     rWorksheet->singleElement( XML_pageSetUpPr,
486             // OOXTODO: XML_autoPageBreaks,
487             XML_fitToPage,  XclXmlUtils::ToPsz( GetValue() & EXC_WSBOOL_FITTOPAGE ),
488             FSEND );
489     rWorksheet->endElement( XML_sheetPr );
490 }
491 
492 
493 // XclExpWindowProtection ===============================================================
494 
XclExpWindowProtection(bool bValue)495 XclExpWindowProtection::XclExpWindowProtection(bool bValue) :
496     XclExpBoolRecord(EXC_ID_WINDOWPROTECT, bValue)
497 {
498 }
499 
SaveXml(XclExpXmlStream & rStrm)500 void XclExpWindowProtection::SaveXml( XclExpXmlStream& rStrm )
501 {
502     rStrm.WriteAttributes(
503             XML_lockWindows, XclXmlUtils::ToPsz( GetBool() ),
504             FSEND );
505 }
506 
507 // XclExpDocProtection ===============================================================
508 
XclExpProtection(bool bValue)509 XclExpProtection::XclExpProtection(bool bValue) :
510     XclExpBoolRecord(EXC_ID_PROTECT, bValue)
511 {
512 }
513 
514 // ============================================================================
515 
XclExpPassHash(const Sequence<sal_Int8> & aHash)516 XclExpPassHash::XclExpPassHash(const Sequence<sal_Int8>& aHash) :
517     XclExpRecord(EXC_ID_PASSWORD, 2),
518     mnHash(0x0000)
519 {
520     if (aHash.getLength() >= 2)
521     {
522         mnHash  = ((aHash[0] << 8) & 0xFFFF);
523         mnHash |= (aHash[1] & 0xFF);
524     }
525 }
526 
~XclExpPassHash()527 XclExpPassHash::~XclExpPassHash()
528 {
529 }
530 
WriteBody(XclExpStream & rStrm)531 void XclExpPassHash::WriteBody(XclExpStream& rStrm)
532 {
533     rStrm << mnHash;
534 }
535 
536 // ============================================================================
537 
XclExpFiltermode()538 XclExpFiltermode::XclExpFiltermode() :
539     XclExpEmptyRecord( EXC_ID_FILTERMODE )
540 {
541 }
542 
543 // ----------------------------------------------------------------------------
544 
XclExpAutofilterinfo(const ScAddress & rStartPos,SCCOL nScCol)545 XclExpAutofilterinfo::XclExpAutofilterinfo( const ScAddress& rStartPos, SCCOL nScCol ) :
546     XclExpUInt16Record( EXC_ID_AUTOFILTERINFO, static_cast< sal_uInt16 >( nScCol ) ),
547     maStartPos( rStartPos )
548 {
549 }
550 
551 // ----------------------------------------------------------------------------
552 
ExcFilterCondition()553 ExcFilterCondition::ExcFilterCondition() :
554         nType( EXC_AFTYPE_NOTUSED ),
555         nOper( EXC_AFOPER_EQUAL ),
556         fVal( 0.0 ),
557         pText( NULL )
558 {
559 }
560 
~ExcFilterCondition()561 ExcFilterCondition::~ExcFilterCondition()
562 {
563     if( pText )
564         delete pText;
565 }
566 
GetTextBytes() const567 sal_Size ExcFilterCondition::GetTextBytes() const
568 {
569     return pText ? (1 + pText->GetBufferSize()) : 0;
570 }
571 
SetCondition(sal_uInt8 nTp,sal_uInt8 nOp,double fV,String * pT)572 void ExcFilterCondition::SetCondition( sal_uInt8 nTp, sal_uInt8 nOp, double fV, String* pT )
573 {
574     nType = nTp;
575     nOper = nOp;
576     fVal = fV;
577 
578     delete pText;
579     pText = pT ? new XclExpString( *pT, EXC_STR_8BITLENGTH ) : NULL;
580 }
581 
Save(XclExpStream & rStrm)582 void ExcFilterCondition::Save( XclExpStream& rStrm )
583 {
584     rStrm << nType << nOper;
585     switch( nType )
586     {
587         case EXC_AFTYPE_DOUBLE:
588             rStrm << fVal;
589         break;
590         case EXC_AFTYPE_STRING:
591             DBG_ASSERT( pText, "ExcFilterCondition::Save() -- pText is NULL!" );
592             rStrm << (sal_uInt32)0 << (sal_uInt8) pText->Len() << (sal_uInt16)0 << (sal_uInt8)0;
593         break;
594         case EXC_AFTYPE_BOOLERR:
595             rStrm << (sal_uInt8)0 << (sal_uInt8)((fVal != 0) ? 1 : 0) << (sal_uInt32)0 << (sal_uInt16)0;
596         break;
597         default:
598             rStrm << (sal_uInt32)0 << (sal_uInt32)0;
599     }
600 }
601 
lcl_GetOperator(sal_uInt8 nOper)602 static const char* lcl_GetOperator( sal_uInt8 nOper )
603 {
604     switch( nOper )
605     {
606         case EXC_AFOPER_EQUAL:          return "equal";
607         case EXC_AFOPER_GREATER:        return "greaterThan";
608         case EXC_AFOPER_GREATEREQUAL:   return "greaterThanOrEqual";
609         case EXC_AFOPER_LESS:           return "lessThan";
610         case EXC_AFOPER_LESSEQUAL:      return "lessThanOrEqual";
611         case EXC_AFOPER_NOTEQUAL:       return "notEqual";
612         case EXC_AFOPER_NONE:
613         default:                        return "**none**";
614     }
615 }
616 
lcl_GetValue(sal_uInt8 nType,double fVal,XclExpString * pStr)617 static OString lcl_GetValue( sal_uInt8 nType, double fVal, XclExpString* pStr )
618 {
619     switch( nType )
620     {
621         case EXC_AFTYPE_STRING:     return XclXmlUtils::ToOString( *pStr );
622         case EXC_AFTYPE_DOUBLE:     return OString::valueOf( fVal );
623         case EXC_AFTYPE_BOOLERR:    return OString::valueOf( (sal_Int32) ( fVal != 0 ? 1 : 0 ) );
624         default:                    return OString();
625     }
626 }
627 
SaveXml(XclExpXmlStream & rStrm)628 void ExcFilterCondition::SaveXml( XclExpXmlStream& rStrm )
629 {
630     if( IsEmpty() )
631         return;
632 
633     rStrm.GetCurrentStream()->singleElement( XML_customFilter,
634             XML_operator,   lcl_GetOperator( nOper ),
635             XML_val,        lcl_GetValue( nType, fVal, pText ).getStr(),
636             FSEND );
637 }
638 
SaveText(XclExpStream & rStrm)639 void ExcFilterCondition::SaveText( XclExpStream& rStrm )
640 {
641     if( nType == EXC_AFTYPE_STRING )
642     {
643         DBG_ASSERT( pText, "ExcFilterCondition::SaveText() -- pText is NULL!" );
644         pText->WriteFlagField( rStrm );
645         pText->WriteBuffer( rStrm );
646     }
647 }
648 
649 // ----------------------------------------------------------------------------
650 
XclExpAutofilter(const XclExpRoot & rRoot,sal_uInt16 nC)651 XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC ) :
652     XclExpRecord( EXC_ID_AUTOFILTER, 24 ),
653     XclExpRoot( rRoot ),
654     nCol( nC ),
655     nFlags( 0 )
656 {
657 }
658 
AddCondition(ScQueryConnect eConn,sal_uInt8 nType,sal_uInt8 nOp,double fVal,String * pText,sal_Bool bSimple)659 sal_Bool XclExpAutofilter::AddCondition( ScQueryConnect eConn, sal_uInt8 nType, sal_uInt8 nOp,
660                                     double fVal, String* pText, sal_Bool bSimple )
661 {
662     if( !aCond[ 1 ].IsEmpty() )
663         return sal_False;
664 
665     sal_uInt16 nInd = aCond[ 0 ].IsEmpty() ? 0 : 1;
666 
667     if( nInd == 1 )
668         nFlags |= (eConn == SC_OR) ? EXC_AFFLAG_OR : EXC_AFFLAG_AND;
669     if( bSimple )
670         nFlags |= (nInd == 0) ? EXC_AFFLAG_SIMPLE1 : EXC_AFFLAG_SIMPLE2;
671 
672     aCond[ nInd ].SetCondition( nType, nOp, fVal, pText );
673 
674     AddRecSize( aCond[ nInd ].GetTextBytes() );
675 
676     return sal_True;
677 }
678 
AddEntry(const ScQueryEntry & rEntry)679 sal_Bool XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry )
680 {
681     sal_Bool    bConflict = sal_False;
682     String  sText;
683 
684     if( rEntry.pStr )
685     {
686         sText.Assign( *rEntry.pStr );
687         switch( rEntry.eOp )
688         {
689             case SC_CONTAINS:
690             case SC_DOES_NOT_CONTAIN:
691             {
692                 sText.InsertAscii( "*" , 0 );
693                 sText.AppendAscii( "*" );
694             }
695             break;
696             case SC_BEGINS_WITH:
697             case SC_DOES_NOT_BEGIN_WITH:
698                 sText.AppendAscii( "*" );
699             break;
700             case SC_ENDS_WITH:
701             case SC_DOES_NOT_END_WITH:
702                 sText.InsertAscii( "*" , 0 );
703             break;
704             default:
705             {
706                 //nothing
707             }
708         }
709     }
710 
711     sal_Bool bLen = sText.Len() > 0;
712 
713     // empty/nonempty fields
714     if( !bLen && (rEntry.nVal == SC_EMPTYFIELDS) )
715         bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_EMPTY, EXC_AFOPER_NONE, 0.0, NULL, sal_True );
716     else if( !bLen && (rEntry.nVal == SC_NONEMPTYFIELDS) )
717         bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_NOTEMPTY, EXC_AFOPER_NONE, 0.0, NULL, sal_True );
718     // other conditions
719     else
720     {
721         double  fVal    = 0.0;
722         sal_uInt32  nIndex  = 0;
723         sal_Bool    bIsNum  = bLen ? GetFormatter().IsNumberFormat( sText, nIndex, fVal ) : sal_True;
724         String* pText   = bIsNum ? NULL : &sText;
725 
726         // top10 flags
727         sal_uInt16 nNewFlags = 0x0000;
728         switch( rEntry.eOp )
729         {
730             case SC_TOPVAL:
731                 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP);
732             break;
733             case SC_BOTVAL:
734                 nNewFlags = EXC_AFFLAG_TOP10;
735             break;
736             case SC_TOPPERC:
737                 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP | EXC_AFFLAG_TOP10PERC);
738             break;
739             case SC_BOTPERC:
740                 nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10PERC);
741             break;
742             default:;
743         }
744         sal_Bool bNewTop10 = ::get_flag( nNewFlags, EXC_AFFLAG_TOP10 );
745 
746         bConflict = HasTop10() && bNewTop10;
747         if( !bConflict )
748         {
749             if( bNewTop10 )
750             {
751                 if( fVal < 0 )      fVal = 0;
752                 if( fVal >= 501 )   fVal = 500;
753                 nFlags |= (nNewFlags | (sal_uInt16)(fVal) << 7);
754             }
755             // normal condition
756             else
757             {
758                 sal_uInt8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING;
759                 sal_uInt8 nOper = EXC_AFOPER_NONE;
760 
761                 switch( rEntry.eOp )
762                 {
763                     case SC_EQUAL:          nOper = EXC_AFOPER_EQUAL;           break;
764                     case SC_LESS:           nOper = EXC_AFOPER_LESS;            break;
765                     case SC_GREATER:        nOper = EXC_AFOPER_GREATER;         break;
766                     case SC_LESS_EQUAL:     nOper = EXC_AFOPER_LESSEQUAL;       break;
767                     case SC_GREATER_EQUAL:  nOper = EXC_AFOPER_GREATEREQUAL;    break;
768                     case SC_NOT_EQUAL:      nOper = EXC_AFOPER_NOTEQUAL;        break;
769                     case SC_CONTAINS:
770                     case SC_BEGINS_WITH:
771                     case SC_ENDS_WITH:
772                                             nOper = EXC_AFOPER_EQUAL;           break;
773                     case SC_DOES_NOT_CONTAIN:
774                     case SC_DOES_NOT_BEGIN_WITH:
775                     case SC_DOES_NOT_END_WITH:
776                                             nOper = EXC_AFOPER_NOTEQUAL;        break;
777                     default:;
778                 }
779                 bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText );
780             }
781         }
782     }
783     return bConflict;
784 }
785 
WriteBody(XclExpStream & rStrm)786 void XclExpAutofilter::WriteBody( XclExpStream& rStrm )
787 {
788     rStrm << nCol << nFlags;
789     aCond[ 0 ].Save( rStrm );
790     aCond[ 1 ].Save( rStrm );
791     aCond[ 0 ].SaveText( rStrm );
792     aCond[ 1 ].SaveText( rStrm );
793 }
794 
SaveXml(XclExpXmlStream & rStrm)795 void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm )
796 {
797     if( !HasCondition() )
798         return;
799 
800     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
801 
802     rWorksheet->startElement( XML_filterColumn,
803             XML_colId,          OString::valueOf( (sal_Int32) nCol ).getStr(),
804             // OOXTODO: XML_hiddenButton,   AutoFilter12 fHideArrow?
805             // OOXTODO: XML_showButton,
806             FSEND );
807 
808     if( HasTop10() )
809     {
810         rWorksheet->singleElement( XML_top10,
811                 XML_top,        XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10TOP ) ),
812                 XML_percent,    XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10PERC ) ),
813                 XML_val,        OString::valueOf( (sal_Int32) (nFlags >> 7 ) ).getStr(),
814                 // OOXTODO: XML_filterVal,
815                 FSEND );
816     }
817 
818     rWorksheet->startElement( XML_customFilters,
819             XML_and,    XclXmlUtils::ToPsz( (nFlags & EXC_AFFLAG_ANDORMASK) == EXC_AFFLAG_AND ),
820             FSEND );
821     aCond[ 0 ].SaveXml( rStrm );
822     aCond[ 1 ].SaveXml( rStrm );
823     rWorksheet->endElement( XML_customFilters );
824     // OOXTODO: XLM_colorFilter, XML_dynamicFilter,
825     // XML_extLst, XML_filters, XML_iconFilter, XML_top10
826     rWorksheet->endElement( XML_filterColumn );
827 }
828 
829 // ----------------------------------------------------------------------------
830 
ExcAutoFilterRecs(const XclExpRoot & rRoot,SCTAB nTab)831 ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab ) :
832     XclExpRoot( rRoot ),
833     pFilterMode( NULL ),
834     pFilterInfo( NULL )
835 {
836     ScDBCollection& rDBColl = GetDatabaseRanges();
837     XclExpNameManager& rNameMgr = GetNameManager();
838 
839     // search for first DB-range with filter
840     sal_uInt16      nIndex  = 0;
841     sal_Bool        bFound  = sal_False;
842     sal_Bool        bAdvanced = sal_False;
843     ScDBData*   pData   = NULL;
844     ScRange     aAdvRange;
845     while( (nIndex < rDBColl.GetCount()) && !bFound )
846     {
847         pData = rDBColl[ nIndex ];
848         if( pData )
849         {
850             ScRange aRange;
851             pData->GetArea( aRange );
852             bAdvanced = pData->GetAdvancedQuerySource( aAdvRange );
853             bFound = (aRange.aStart.Tab() == nTab) &&
854                 (pData->HasQueryParam() || pData->HasAutoFilter() || bAdvanced);
855         }
856         if( !bFound )
857             nIndex++;
858     }
859 
860     if( pData && bFound )
861     {
862         ScQueryParam    aParam;
863         pData->GetQueryParam( aParam );
864 
865         ScRange aRange( aParam.nCol1, aParam.nRow1, aParam.nTab,
866                         aParam.nCol2, aParam.nRow2, aParam.nTab );
867         SCCOL   nColCnt = aParam.nCol2 - aParam.nCol1 + 1;
868 
869         maRef = aRange;
870 
871         // #i2394# #100489# built-in defined names must be sorted by containing sheet name
872         rNameMgr.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE, aRange );
873 
874         // advanced filter
875         if( bAdvanced )
876         {
877             // filter criteria, excel allows only same table
878             if( aAdvRange.aStart.Tab() == nTab )
879                 rNameMgr.InsertBuiltInName( EXC_BUILTIN_CRITERIA, aAdvRange );
880 
881             // filter destination range, excel allows only same table
882             if( !aParam.bInplace )
883             {
884                 ScRange aDestRange( aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
885                 aDestRange.aEnd.IncCol( nColCnt - 1 );
886                 if( aDestRange.aStart.Tab() == nTab )
887                     rNameMgr.InsertBuiltInName( EXC_BUILTIN_EXTRACT, aDestRange );
888             }
889 
890             pFilterMode = new XclExpFiltermode;
891         }
892         // AutoFilter
893         else
894         {
895             sal_Bool    bConflict   = sal_False;
896             sal_Bool    bContLoop   = sal_True;
897             sal_Bool    bHasOr      = sal_False;
898             SCCOLROW nFirstField = aParam.GetEntry( 0 ).nField;
899 
900             // create AUTOFILTER records for filtered columns
901             for( SCSIZE nEntry = 0; !bConflict && bContLoop && (nEntry < aParam.GetEntryCount()); nEntry++ )
902             {
903                 const ScQueryEntry& rEntry  = aParam.GetEntry( nEntry );
904 
905                 bContLoop = rEntry.bDoQuery;
906                 if( bContLoop )
907                 {
908                     XclExpAutofilter* pFilter = GetByCol( static_cast<SCCOL>(rEntry.nField) - aRange.aStart.Col() );
909 
910                     if( nEntry > 0 )
911                         bHasOr |= (rEntry.eConnect == SC_OR);
912 
913                     bConflict = (nEntry > 1) && bHasOr;
914                     if( !bConflict )
915                         bConflict = (nEntry == 1) && (rEntry.eConnect == SC_OR) &&
916                                     (nFirstField != rEntry.nField);
917                     if( !bConflict )
918                         bConflict = pFilter->AddEntry( rEntry );
919                 }
920             }
921 
922             // additional tests for conflicts
923             for( size_t nPos = 0, nSize = maFilterList.GetSize(); !bConflict && (nPos < nSize); ++nPos )
924             {
925                 XclExpAutofilterRef xFilter = maFilterList.GetRecord( nPos );
926                 bConflict = xFilter->HasCondition() && xFilter->HasTop10();
927             }
928 
929             if( bConflict )
930                 maFilterList.RemoveAllRecords();
931 
932             if( !maFilterList.IsEmpty() )
933                 pFilterMode = new XclExpFiltermode;
934             pFilterInfo = new XclExpAutofilterinfo( aRange.aStart, nColCnt );
935         }
936     }
937 }
938 
~ExcAutoFilterRecs()939 ExcAutoFilterRecs::~ExcAutoFilterRecs()
940 {
941     delete pFilterMode;
942     delete pFilterInfo;
943 }
944 
GetByCol(SCCOL nCol)945 XclExpAutofilter* ExcAutoFilterRecs::GetByCol( SCCOL nCol )
946 {
947     XclExpAutofilterRef xFilter;
948     for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos )
949     {
950         xFilter = maFilterList.GetRecord( nPos );
951         if( xFilter->GetCol() == static_cast<sal_uInt16>(nCol) )
952             return xFilter.get();
953     }
954     xFilter.reset( new XclExpAutofilter( GetRoot(), static_cast<sal_uInt16>(nCol) ) );
955     maFilterList.AppendRecord( xFilter );
956     return xFilter.get();
957 }
958 
IsFiltered(SCCOL nCol)959 sal_Bool ExcAutoFilterRecs::IsFiltered( SCCOL nCol )
960 {
961     for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos )
962         if( maFilterList.GetRecord( nPos )->GetCol() == static_cast<sal_uInt16>(nCol) )
963             return sal_True;
964     return sal_False;
965 }
966 
AddObjRecs()967 void ExcAutoFilterRecs::AddObjRecs()
968 {
969     if( pFilterInfo )
970     {
971         ScAddress aAddr( pFilterInfo->GetStartPos() );
972         for( SCCOL nObj = 0, nCount = pFilterInfo->GetColCount(); nObj < nCount; nObj++ )
973         {
974             XclObj* pObjRec = new XclObjDropDown( GetObjectManager(), aAddr, IsFiltered( nObj ) );
975             GetObjectManager().AddObj( pObjRec );
976             aAddr.IncCol( 1 );
977         }
978     }
979 }
980 
Save(XclExpStream & rStrm)981 void ExcAutoFilterRecs::Save( XclExpStream& rStrm )
982 {
983     if( pFilterMode )
984         pFilterMode->Save( rStrm );
985     if( pFilterInfo )
986         pFilterInfo->Save( rStrm );
987     maFilterList.Save( rStrm );
988 }
989 
SaveXml(XclExpXmlStream & rStrm)990 void ExcAutoFilterRecs::SaveXml( XclExpXmlStream& rStrm )
991 {
992     if( maFilterList.IsEmpty() )
993         return;
994 
995     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
996     rWorksheet->startElement( XML_autoFilter,
997             XML_ref,    XclXmlUtils::ToOString( maRef ).getStr(),
998             FSEND );
999     // OOXTODO: XML_extLst, XML_sortState
1000     maFilterList.SaveXml( rStrm );
1001     rWorksheet->endElement( XML_autoFilter );
1002 }
1003 
HasFilterMode() const1004 bool ExcAutoFilterRecs::HasFilterMode() const
1005 {
1006     return pFilterMode != NULL;
1007 }
1008 
1009 // ----------------------------------------------------------------------------
1010 
XclExpFilterManager(const XclExpRoot & rRoot)1011 XclExpFilterManager::XclExpFilterManager( const XclExpRoot& rRoot ) :
1012     XclExpRoot( rRoot )
1013 {
1014 }
1015 
InitTabFilter(SCTAB nScTab)1016 void XclExpFilterManager::InitTabFilter( SCTAB nScTab )
1017 {
1018     maFilterMap[ nScTab ].reset( new ExcAutoFilterRecs( GetRoot(), nScTab ) );
1019 }
1020 
CreateRecord(SCTAB nScTab)1021 XclExpRecordRef XclExpFilterManager::CreateRecord( SCTAB nScTab )
1022 {
1023     XclExpTabFilterRef xRec;
1024     XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab );
1025     if( aIt != maFilterMap.end() )
1026     {
1027         xRec = aIt->second;
1028         xRec->AddObjRecs();
1029     }
1030     return xRec;
1031 }
1032 
HasFilterMode(SCTAB nScTab)1033 bool XclExpFilterManager::HasFilterMode( SCTAB nScTab )
1034 {
1035     XclExpTabFilterRef xRec;
1036     XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab );
1037     if( aIt != maFilterMap.end() )
1038     {
1039         return aIt->second->HasFilterMode();
1040     }
1041     return false;
1042 }
1043 
1044 // ============================================================================
1045 
1046