xref: /trunk/main/sc/source/filter/excel/excrecds.cxx (revision b77af630)
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_scfilt.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