Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / sc / source / filter / excel / xecontent.cxx
blob5a46ad52cd07e83937e7c093f6eb6197da9e2ba6
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 "xecontent.hxx"
22 #include <list>
23 #include <algorithm>
24 #include <com/sun/star/container/XIndexAccess.hpp>
25 #include <com/sun/star/frame/XModel.hpp>
26 #include <com/sun/star/sheet/XAreaLinks.hpp>
27 #include <com/sun/star/sheet/XAreaLink.hpp>
28 #include <comphelper/string.hxx>
29 #include <sfx2/objsh.hxx>
30 #include <tools/urlobj.hxx>
31 #include <svl/itemset.hxx>
32 #include <formula/grammar.hxx>
33 #include "scitems.hxx"
34 #include <editeng/eeitem.hxx>
35 #include <editeng/flditem.hxx>
36 #include "document.hxx"
37 #include "validat.hxx"
38 #include "unonames.hxx"
39 #include "convuno.hxx"
40 #include "rangenam.hxx"
41 #include "tokenarray.hxx"
42 #include "stlpool.hxx"
43 #include "patattr.hxx"
44 #include "fapihelper.hxx"
45 #include "xehelper.hxx"
46 #include "xestyle.hxx"
47 #include "xename.hxx"
48 #include <rtl/uuid.h>
50 using namespace ::oox;
52 using ::com::sun::star::uno::Reference;
53 using ::com::sun::star::uno::Any;
54 using ::com::sun::star::uno::UNO_QUERY;
55 using ::com::sun::star::beans::XPropertySet;
56 using ::com::sun::star::container::XIndexAccess;
57 using ::com::sun::star::frame::XModel;
58 using ::com::sun::star::table::CellRangeAddress;
59 using ::com::sun::star::sheet::XAreaLinks;
60 using ::com::sun::star::sheet::XAreaLink;
61 using ::rtl::OString;
62 using ::rtl::OUString;
63 using ::rtl::OUStringBuffer;
65 // Shared string table ========================================================
67 /** A single string entry in the hash table. */
68 struct XclExpHashEntry
70 const XclExpString* mpString; /// Pointer to the string (no ownership).
71 sal_uInt32 mnSstIndex; /// The SST index of this string.
72 inline explicit XclExpHashEntry( const XclExpString* pString = 0, sal_uInt32 nSstIndex = 0 ) :
73 mpString( pString ), mnSstIndex( nSstIndex ) {}
76 /** Function object for strict weak ordering. */
77 struct XclExpHashEntrySWO
79 inline bool operator()( const XclExpHashEntry& rLeft, const XclExpHashEntry& rRight ) const
80 { return *rLeft.mpString < *rRight.mpString; }
83 // ----------------------------------------------------------------------------
85 /** Implementation of the SST export.
86 @descr Stores all passed strings in a hash table and prevents repeated
87 insertion of equal strings. */
88 class XclExpSstImpl
90 public:
91 explicit XclExpSstImpl();
93 /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
94 sal_uInt32 Insert( XclExpStringRef xString );
96 /** Writes the complete SST and EXTSST records. */
97 void Save( XclExpStream& rStrm );
98 void SaveXml( XclExpXmlStream& rStrm );
100 private:
101 typedef ::std::list< XclExpStringRef > XclExpStringList;
102 typedef ::std::vector< XclExpHashEntry > XclExpHashVec;
103 typedef ::std::vector< XclExpHashVec > XclExpHashTab;
105 XclExpStringList maStringList; /// List of unique strings (in SST ID order).
106 XclExpHashTab maHashTab; /// Hashed table that manages string pointers.
107 sal_uInt32 mnTotal; /// Total count of strings (including doubles).
108 sal_uInt32 mnSize; /// Size of the SST (count of unique strings).
111 // ----------------------------------------------------------------------------
113 const sal_uInt32 EXC_SST_HASHTABLE_SIZE = 2048;
115 XclExpSstImpl::XclExpSstImpl() :
116 maHashTab( EXC_SST_HASHTABLE_SIZE ),
117 mnTotal( 0 ),
118 mnSize( 0 )
122 sal_uInt32 XclExpSstImpl::Insert( XclExpStringRef xString )
124 OSL_ENSURE( xString.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
125 if( !xString.get() )
126 xString.reset( new XclExpString );
128 ++mnTotal;
129 sal_uInt32 nSstIndex = 0;
131 // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
132 sal_uInt16 nHash = xString->GetHash();
133 (nHash ^= (nHash / EXC_SST_HASHTABLE_SIZE)) %= EXC_SST_HASHTABLE_SIZE;
135 XclExpHashVec& rVec = maHashTab[ nHash ];
136 XclExpHashEntry aEntry( xString.get(), mnSize );
137 XclExpHashVec::iterator aIt = ::std::lower_bound( rVec.begin(), rVec.end(), aEntry, XclExpHashEntrySWO() );
138 if( (aIt == rVec.end()) || (*aIt->mpString != *xString) )
140 nSstIndex = mnSize;
141 maStringList.push_back( xString );
142 rVec.insert( aIt, aEntry );
143 ++mnSize;
145 else
147 nSstIndex = aIt->mnSstIndex;
150 return nSstIndex;
153 void XclExpSstImpl::Save( XclExpStream& rStrm )
155 if( maStringList.empty() )
156 return;
158 SvMemoryStream aExtSst( 8192 );
160 sal_uInt32 nBucket = mnSize;
161 while( nBucket > 0x0100 )
162 nBucket /= 2;
164 sal_uInt16 nPerBucket = llimit_cast< sal_uInt16 >( nBucket, 8 );
165 sal_uInt16 nBucketIndex = 0;
167 // *** write the SST record ***
169 rStrm.StartRecord( EXC_ID_SST, 8 );
171 rStrm << mnTotal << mnSize;
172 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
174 if( !nBucketIndex )
176 // write bucket info before string to get correct record position
177 sal_uInt32 nStrmPos = static_cast< sal_uInt32 >( rStrm.GetSvStreamPos() );
178 sal_uInt16 nRecPos = rStrm.GetRawRecPos() + 4;
179 aExtSst << nStrmPos // stream position
180 << nRecPos // position from start of SST or CONTINUE
181 << sal_uInt16( 0 ); // reserved
184 rStrm << **aIt;
186 if( ++nBucketIndex == nPerBucket )
187 nBucketIndex = 0;
190 rStrm.EndRecord();
192 // *** write the EXTSST record ***
194 rStrm.StartRecord( EXC_ID_EXTSST, 0 );
196 rStrm << nPerBucket;
197 rStrm.SetSliceSize( 8 ); // size of one bucket info
198 aExtSst.Seek( STREAM_SEEK_TO_BEGIN );
199 rStrm.CopyFromStream( aExtSst );
201 rStrm.EndRecord();
204 void XclExpSstImpl::SaveXml( XclExpXmlStream& rStrm )
206 if( maStringList.empty() )
207 return;
209 sax_fastparser::FSHelperPtr pSst = rStrm.CreateOutputStream(
210 OUString(RTL_CONSTASCII_USTRINGPARAM( "xl/sharedStrings.xml") ),
211 OUString(RTL_CONSTASCII_USTRINGPARAM( "sharedStrings.xml" )),
212 rStrm.GetCurrentStream()->getOutputStream(),
213 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
214 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
215 rStrm.PushStream( pSst );
217 pSst->startElement( XML_sst,
218 XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
219 XML_count, OString::valueOf( (sal_Int32) mnTotal ).getStr(),
220 XML_uniqueCount, OString::valueOf( (sal_Int32) mnSize ).getStr(),
221 FSEND );
223 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
225 pSst->startElement( XML_si, FSEND );
226 (*aIt)->WriteXml( rStrm );
227 pSst->endElement( XML_si );
230 pSst->endElement( XML_sst );
232 rStrm.PopStream();
235 // ----------------------------------------------------------------------------
237 XclExpSst::XclExpSst() :
238 mxImpl( new XclExpSstImpl )
242 XclExpSst::~XclExpSst()
246 sal_uInt32 XclExpSst::Insert( XclExpStringRef xString )
248 return mxImpl->Insert( xString );
251 void XclExpSst::Save( XclExpStream& rStrm )
253 mxImpl->Save( rStrm );
256 void XclExpSst::SaveXml( XclExpXmlStream& rStrm )
258 mxImpl->SaveXml( rStrm );
261 // Merged cells ===============================================================
263 XclExpMergedcells::XclExpMergedcells( const XclExpRoot& rRoot ) :
264 XclExpRoot( rRoot )
268 void XclExpMergedcells::AppendRange( const ScRange& rRange, sal_uInt32 nBaseXFId )
270 if( GetBiff() == EXC_BIFF8 )
272 maMergedRanges.Append( rRange );
273 maBaseXFIds.push_back( nBaseXFId );
277 sal_uInt32 XclExpMergedcells::GetBaseXFId( const ScAddress& rPos ) const
279 OSL_ENSURE( maBaseXFIds.size() == maMergedRanges.size(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
280 ScfUInt32Vec::const_iterator aIt = maBaseXFIds.begin();
281 ScRangeList& rNCRanges = const_cast< ScRangeList& >( maMergedRanges );
282 for ( size_t i = 0, nRanges = rNCRanges.size(); i < nRanges; ++i, ++aIt )
284 const ScRange* pScRange = rNCRanges[ i ];
285 if( pScRange->In( rPos ) )
286 return *aIt;
288 return EXC_XFID_NOTFOUND;
291 void XclExpMergedcells::Save( XclExpStream& rStrm )
293 if( GetBiff() == EXC_BIFF8 )
295 XclRangeList aXclRanges;
296 GetAddressConverter().ConvertRangeList( aXclRanges, maMergedRanges, true );
297 size_t nFirstRange = 0;
298 size_t nRemainingRanges = aXclRanges.size();
299 while( nRemainingRanges > 0 )
301 size_t nRangeCount = ::std::min< size_t >( nRemainingRanges, EXC_MERGEDCELLS_MAXCOUNT );
302 rStrm.StartRecord( EXC_ID_MERGEDCELLS, 2 + 8 * nRangeCount );
303 aXclRanges.WriteSubList( rStrm, nFirstRange, nRangeCount );
304 rStrm.EndRecord();
305 nFirstRange += nRangeCount;
306 nRemainingRanges -= nRangeCount;
311 void XclExpMergedcells::SaveXml( XclExpXmlStream& rStrm )
313 size_t nCount = maMergedRanges.size();
314 if( !nCount )
315 return;
316 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
317 rWorksheet->startElement( XML_mergeCells,
318 XML_count, OString::valueOf( (sal_Int32) nCount ).getStr(),
319 FSEND );
320 for( size_t i = 0; i < nCount; ++i )
322 if( const ScRange* pRange = maMergedRanges[ i ] )
324 rWorksheet->singleElement( XML_mergeCell,
325 XML_ref, XclXmlUtils::ToOString( *pRange ).getStr(),
326 FSEND );
329 rWorksheet->endElement( XML_mergeCells );
332 // Hyperlinks =================================================================
334 XclExpHyperlink::XclExpHyperlink( const XclExpRoot& rRoot, const SvxURLField& rUrlField, const ScAddress& rScPos ) :
335 XclExpRecord( EXC_ID_HLINK ),
336 maScPos( rScPos ),
337 mxVarData( new SvMemoryStream ),
338 mnFlags( 0 )
340 const String& rUrl = rUrlField.GetURL();
341 const String& rRepr = rUrlField.GetRepresentation();
342 INetURLObject aUrlObj( rUrl );
343 const INetProtocol eProtocol = aUrlObj.GetProtocol();
344 bool bWithRepr = rRepr.Len() > 0;
345 XclExpStream aXclStrm( *mxVarData, rRoot ); // using in raw write mode.
347 // description
348 if( bWithRepr )
350 XclExpString aDescr( rRepr, EXC_STR_FORCEUNICODE, 255 );
351 aXclStrm << sal_uInt32( aDescr.Len() + 1 ); // string length + 1 trailing zero word
352 aDescr.WriteBuffer( aXclStrm ); // NO flags
353 aXclStrm << sal_uInt16( 0 );
355 mnFlags |= EXC_HLINK_DESCR;
356 mxRepr.reset( new String( rRepr ) );
359 // file link or URL
360 if( eProtocol == INET_PROT_FILE || eProtocol == INET_PROT_SMB )
362 sal_uInt16 nLevel;
363 bool bRel;
364 String aFileName( BuildFileName( nLevel, bRel, rUrl, rRoot ) );
366 if( eProtocol == INET_PROT_SMB )
368 // #n382718# (and #n261623#) Convert smb notation to '\\'
369 aFileName = aUrlObj.GetMainURL( INetURLObject::NO_DECODE );
370 aFileName = rtl::OUString( aFileName.GetBuffer() + 4 ); // skip the 'smb:' part
371 aFileName.SearchAndReplaceAll( '/', '\\' );
374 if( !bRel )
375 mnFlags |= EXC_HLINK_ABS;
376 mnFlags |= EXC_HLINK_BODY;
378 rtl::OString aAsciiLink(rtl::OUStringToOString(aFileName,
379 rRoot.GetTextEncoding()));
380 XclExpString aLink( aFileName, EXC_STR_FORCEUNICODE, 255 );
381 aXclStrm << XclTools::maGuidFileMoniker
382 << nLevel
383 << sal_uInt32( aAsciiLink.getLength() + 1 ); // string length + 1 trailing zero byte
384 aXclStrm.Write( aAsciiLink.getStr(), aAsciiLink.getLength() );
385 aXclStrm << sal_uInt8( 0 )
386 << sal_uInt32( 0xDEADFFFF );
387 aXclStrm.WriteZeroBytes( 20 );
388 aXclStrm << sal_uInt32( aLink.GetBufferSize() + 6 )
389 << sal_uInt32( aLink.GetBufferSize() ) // byte count, not string length
390 << sal_uInt16( 0x0003 );
391 aLink.WriteBuffer( aXclStrm ); // NO flags
393 if( !mxRepr.get() )
394 mxRepr.reset( new String( aFileName ) );
396 msTarget = XclXmlUtils::ToOUString( aLink );
398 else if( eProtocol != INET_PROT_NOT_VALID )
400 XclExpString aUrl( aUrlObj.GetURLNoMark(), EXC_STR_FORCEUNICODE, 255 );
401 aXclStrm << XclTools::maGuidUrlMoniker
402 << sal_uInt32( aUrl.GetBufferSize() + 2 ); // byte count + 1 trailing zero word
403 aUrl.WriteBuffer( aXclStrm ); // NO flags
404 aXclStrm << sal_uInt16( 0 );
406 mnFlags |= EXC_HLINK_BODY | EXC_HLINK_ABS;
407 if( !mxRepr.get() )
408 mxRepr.reset( new String( rUrl ) );
410 msTarget = XclXmlUtils::ToOUString( aUrl );
412 else if( rUrl.GetChar( 0 ) == '#' ) // hack for #89066#
414 String aTextMark( rUrl.Copy( 1 ) );
416 xub_StrLen nSepPos = aTextMark.SearchAndReplace( '.', '!' );
417 String aSheetName( aTextMark.Copy(0, nSepPos));
419 if ( aSheetName.Search(' ') != STRING_NOTFOUND && aSheetName.GetChar(0) != '\'')
421 aTextMark.Insert('\'', nSepPos);
422 aTextMark.Insert('\'', 0);
425 mxTextMark.reset( new XclExpString( aTextMark, EXC_STR_FORCEUNICODE, 255 ) );
428 // text mark
429 if( !mxTextMark.get() && aUrlObj.HasMark() )
430 mxTextMark.reset( new XclExpString( aUrlObj.GetMark(), EXC_STR_FORCEUNICODE, 255 ) );
432 if( mxTextMark.get() )
434 aXclStrm << sal_uInt32( mxTextMark->Len() + 1 ); // string length + 1 trailing zero word
435 mxTextMark->WriteBuffer( aXclStrm ); // NO flags
436 aXclStrm << sal_uInt16( 0 );
438 mnFlags |= EXC_HLINK_MARK;
441 SetRecSize( 32 + mxVarData->Tell() );
444 XclExpHyperlink::~XclExpHyperlink()
448 String XclExpHyperlink::BuildFileName(
449 sal_uInt16& rnLevel, bool& rbRel, const String& rUrl, const XclExpRoot& rRoot ) const
451 String aDosName( INetURLObject( rUrl ).getFSysPath( INetURLObject::FSYS_DOS ) );
452 rnLevel = 0;
453 rbRel = rRoot.IsRelUrl();
455 if( rbRel )
457 // try to convert to relative file name
458 String aTmpName( aDosName );
459 aDosName = INetURLObject::GetRelURL( rRoot.GetBasePath(), rUrl,
460 INetURLObject::WAS_ENCODED, INetURLObject::DECODE_WITH_CHARSET );
462 if( aDosName.SearchAscii( INET_FILE_SCHEME ) == 0 )
464 // not converted to rel -> back to old, return absolute flag
465 aDosName = aTmpName;
466 rbRel = false;
468 else if( aDosName.SearchAscii( "./" ) == 0 )
470 aDosName.Erase( 0, 2 );
472 else
474 while( aDosName.SearchAndReplaceAscii( "../", EMPTY_STRING ) == 0 )
475 ++rnLevel;
478 return aDosName;
481 void XclExpHyperlink::WriteBody( XclExpStream& rStrm )
483 sal_uInt16 nXclCol = static_cast< sal_uInt16 >( maScPos.Col() );
484 sal_uInt16 nXclRow = static_cast< sal_uInt16 >( maScPos.Row() );
485 rStrm << nXclRow << nXclRow << nXclCol << nXclCol;
486 WriteEmbeddedData( rStrm );
489 void XclExpHyperlink::WriteEmbeddedData( XclExpStream& rStrm )
491 rStrm << XclTools::maGuidStdLink
492 << sal_uInt32( 2 )
493 << mnFlags;
495 mxVarData->Seek( STREAM_SEEK_TO_BEGIN );
496 rStrm.CopyFromStream( *mxVarData );
499 void XclExpHyperlink::SaveXml( XclExpXmlStream& rStrm )
501 OUString sId = !msTarget.isEmpty() ? rStrm.addRelation( rStrm.GetCurrentStream()->getOutputStream(),
502 XclXmlUtils::ToOUString( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ),
503 msTarget, true ) : OUString();
504 rStrm.GetCurrentStream()->singleElement( XML_hyperlink,
505 XML_ref, XclXmlUtils::ToOString( maScPos ).getStr(),
506 FSNS( XML_r, XML_id ), !sId.isEmpty()
507 ? XclXmlUtils::ToOString( sId ).getStr()
508 : NULL,
509 XML_location, mxTextMark.get() != NULL
510 ? XclXmlUtils::ToOString( *mxTextMark ).getStr()
511 : NULL,
512 // OOXTODO: XML_tooltip, from record HLinkTooltip 800h wzTooltip
513 XML_display, XclXmlUtils::ToOString( *mxRepr ).getStr(),
514 FSEND );
517 // Label ranges ===============================================================
519 XclExpLabelranges::XclExpLabelranges( const XclExpRoot& rRoot ) :
520 XclExpRoot( rRoot )
522 SCTAB nScTab = GetCurrScTab();
523 // row label ranges
524 FillRangeList( maRowRanges, rRoot.GetDoc().GetRowNameRangesRef(), nScTab );
525 // row labels only over 1 column (restriction of Excel97/2000/XP)
526 for ( size_t i = 0, nRanges = maRowRanges.size(); i < nRanges; ++i )
528 ScRange* pScRange = maRowRanges[ i ];
529 if( pScRange->aStart.Col() != pScRange->aEnd.Col() )
530 pScRange->aEnd.SetCol( pScRange->aStart.Col() );
532 // col label ranges
533 FillRangeList( maColRanges, rRoot.GetDoc().GetColNameRangesRef(), nScTab );
536 void XclExpLabelranges::FillRangeList( ScRangeList& rScRanges,
537 ScRangePairListRef xLabelRangesRef, SCTAB nScTab )
539 for ( size_t i = 0, nPairs = xLabelRangesRef->size(); i < nPairs; ++i )
541 ScRangePair* pRangePair = (*xLabelRangesRef)[i];
542 const ScRange& rScRange = pRangePair->GetRange( 0 );
543 if( rScRange.aStart.Tab() == nScTab )
544 rScRanges.Append( rScRange );
548 void XclExpLabelranges::Save( XclExpStream& rStrm )
550 XclExpAddressConverter& rAddrConv = GetAddressConverter();
551 XclRangeList aRowXclRanges, aColXclRanges;
552 rAddrConv.ConvertRangeList( aRowXclRanges, maRowRanges, false );
553 rAddrConv.ConvertRangeList( aColXclRanges, maColRanges, false );
554 if( !aRowXclRanges.empty() || !aColXclRanges.empty() )
556 rStrm.StartRecord( EXC_ID_LABELRANGES, 4 + 8 * (aRowXclRanges.size() + aColXclRanges.size()) );
557 rStrm << aRowXclRanges << aColXclRanges;
558 rStrm.EndRecord();
562 // Conditional formatting ====================================================
564 /** Represents a CF record that contains one condition of a conditional format. */
565 class XclExpCFImpl : protected XclExpRoot
567 public:
568 explicit XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority = 0 );
570 /** Writes the body of the CF record. */
571 void WriteBody( XclExpStream& rStrm );
572 void SaveXml( XclExpXmlStream& rStrm );
574 private:
575 const ScCondFormatEntry& mrFormatEntry; /// Calc conditional format entry.
576 XclFontData maFontData; /// Font formatting attributes.
577 XclExpCellBorder maBorder; /// Border formatting attributes.
578 XclExpCellArea maArea; /// Pattern formatting attributes.
579 XclTokenArrayRef mxTokArr1; /// Formula for first condition.
580 XclTokenArrayRef mxTokArr2; /// Formula for second condition.
581 sal_uInt32 mnFontColorId; /// Font color ID.
582 sal_uInt8 mnType; /// Type of the condition (cell/formula).
583 sal_uInt8 mnOperator; /// Comparison operator for cell type.
584 sal_Int32 mnPriority; /// Priority of this entry; needed for oox export
585 bool mbFontUsed; /// true = Any font attribute used.
586 bool mbHeightUsed; /// true = Font height used.
587 bool mbWeightUsed; /// true = Font weight used.
588 bool mbColorUsed; /// true = Font color used.
589 bool mbUnderlUsed; /// true = Font underline type used.
590 bool mbItalicUsed; /// true = Font posture used.
591 bool mbStrikeUsed; /// true = Font strikeout used.
592 bool mbBorderUsed; /// true = Border attribute used.
593 bool mbPattUsed; /// true = Pattern attribute used.
596 // ----------------------------------------------------------------------------
598 XclExpCFImpl::XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority ) :
599 XclExpRoot( rRoot ),
600 mrFormatEntry( rFormatEntry ),
601 mnFontColorId( 0 ),
602 mnType( EXC_CF_TYPE_CELL ),
603 mnOperator( EXC_CF_CMP_NONE ),
604 mnPriority( nPriority ),
605 mbFontUsed( false ),
606 mbHeightUsed( false ),
607 mbWeightUsed( false ),
608 mbColorUsed( false ),
609 mbUnderlUsed( false ),
610 mbItalicUsed( false ),
611 mbStrikeUsed( false ),
612 mbBorderUsed( false ),
613 mbPattUsed( false )
615 /* Get formatting attributes here, and not in WriteBody(). This is needed to
616 correctly insert all colors into the palette. */
618 if( SfxStyleSheetBase* pStyleSheet = GetDoc().GetStyleSheetPool()->Find( mrFormatEntry.GetStyle(), SFX_STYLE_FAMILY_PARA ) )
620 const SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
622 // font
623 mbHeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_HEIGHT, true );
624 mbWeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_WEIGHT, true );
625 mbColorUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_COLOR, true );
626 mbUnderlUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_UNDERLINE, true );
627 mbItalicUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_POSTURE, true );
628 mbStrikeUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_CROSSEDOUT, true );
629 mbFontUsed = mbHeightUsed || mbWeightUsed || mbColorUsed || mbUnderlUsed || mbItalicUsed || mbStrikeUsed;
630 if( mbFontUsed )
632 Font aFont;
633 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW );
634 maFontData.FillFromVclFont( aFont );
635 mnFontColorId = GetPalette().InsertColor( maFontData.maColor, EXC_COLOR_CELLTEXT );
638 // border
639 mbBorderUsed = ScfTools::CheckItem( rItemSet, ATTR_BORDER, true );
640 if( mbBorderUsed )
641 maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
643 // pattern
644 mbPattUsed = ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true );
645 if( mbPattUsed )
646 maArea.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
649 // *** mode and comparison operator ***
651 bool bFmla2 = false;
652 switch( rFormatEntry.GetOperation() )
654 case SC_COND_NONE: mnType = EXC_CF_TYPE_NONE; break;
655 case SC_COND_BETWEEN: mnOperator = EXC_CF_CMP_BETWEEN; bFmla2 = true; break;
656 case SC_COND_NOTBETWEEN: mnOperator = EXC_CF_CMP_NOT_BETWEEN; bFmla2 = true; break;
657 case SC_COND_EQUAL: mnOperator = EXC_CF_CMP_EQUAL; break;
658 case SC_COND_NOTEQUAL: mnOperator = EXC_CF_CMP_NOT_EQUAL; break;
659 case SC_COND_GREATER: mnOperator = EXC_CF_CMP_GREATER; break;
660 case SC_COND_LESS: mnOperator = EXC_CF_CMP_LESS; break;
661 case SC_COND_EQGREATER: mnOperator = EXC_CF_CMP_GREATER_EQUAL; break;
662 case SC_COND_EQLESS: mnOperator = EXC_CF_CMP_LESS_EQUAL; break;
663 case SC_COND_DIRECT: mnType = EXC_CF_TYPE_FMLA; break;
664 default: mnType = EXC_CF_TYPE_NONE;
665 OSL_FAIL( "XclExpCF::WriteBody - unknown condition type" );
668 // *** formulas ***
670 XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
672 boost::scoped_ptr< ScTokenArray > xScTokArr( mrFormatEntry.CreateTokenArry( 0 ) );
673 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
675 if( bFmla2 )
677 xScTokArr.reset( mrFormatEntry.CreateTokenArry( 1 ) );
678 mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
682 void XclExpCFImpl::WriteBody( XclExpStream& rStrm )
684 // *** mode and comparison operator ***
686 rStrm << mnType << mnOperator;
688 // *** formula sizes ***
690 sal_uInt16 nFmlaSize1 = mxTokArr1.get() ? mxTokArr1->GetSize() : 0;
691 sal_uInt16 nFmlaSize2 = mxTokArr2.get() ? mxTokArr2->GetSize() : 0;
692 rStrm << nFmlaSize1 << nFmlaSize2;
694 // *** formatting blocks ***
696 if( mbFontUsed || mbBorderUsed || mbPattUsed )
698 sal_uInt32 nFlags = EXC_CF_ALLDEFAULT;
700 ::set_flag( nFlags, EXC_CF_BLOCK_FONT, mbFontUsed );
701 ::set_flag( nFlags, EXC_CF_BLOCK_BORDER, mbBorderUsed );
702 ::set_flag( nFlags, EXC_CF_BLOCK_AREA, mbPattUsed );
704 // attributes used -> set flags to 0.
705 ::set_flag( nFlags, EXC_CF_BORDER_ALL, !mbBorderUsed );
706 ::set_flag( nFlags, EXC_CF_AREA_ALL, !mbPattUsed );
708 rStrm << nFlags << sal_uInt16( 0 );
710 if( mbFontUsed )
712 // font height, 0xFFFFFFFF indicates unused
713 sal_uInt32 nHeight = mbHeightUsed ? maFontData.mnHeight : 0xFFFFFFFF;
714 // font style: italic and strikeout
715 sal_uInt32 nStyle = 0;
716 ::set_flag( nStyle, EXC_CF_FONT_STYLE, maFontData.mbItalic );
717 ::set_flag( nStyle, EXC_CF_FONT_STRIKEOUT, maFontData.mbStrikeout );
718 // font color, 0xFFFFFFFF indicates unused
719 sal_uInt32 nColor = mbColorUsed ? GetPalette().GetColorIndex( mnFontColorId ) : 0xFFFFFFFF;
720 // font used flags for italic, weight, and strikeout -> 0 = used, 1 = default
721 sal_uInt32 nFontFlags1 = EXC_CF_FONT_ALLDEFAULT;
722 ::set_flag( nFontFlags1, EXC_CF_FONT_STYLE, !(mbItalicUsed || mbWeightUsed) );
723 ::set_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT, !mbStrikeUsed );
724 // font used flag for underline -> 0 = used, 1 = default
725 sal_uInt32 nFontFlags3 = mbUnderlUsed ? 0 : EXC_CF_FONT_UNDERL;
727 rStrm.WriteZeroBytesToRecord( 64 );
728 rStrm << nHeight
729 << nStyle
730 << maFontData.mnWeight
731 << EXC_FONTESC_NONE
732 << maFontData.mnUnderline;
733 rStrm.WriteZeroBytesToRecord( 3 );
734 rStrm << nColor
735 << sal_uInt32( 0 )
736 << nFontFlags1
737 << EXC_CF_FONT_ESCAPEM // escapement never used -> set the flag
738 << nFontFlags3;
739 rStrm.WriteZeroBytesToRecord( 16 );
740 rStrm << sal_uInt16( 1 ); // must be 1
743 if( mbBorderUsed )
745 sal_uInt16 nLineStyle = 0;
746 sal_uInt32 nLineColor = 0;
747 maBorder.SetFinalColors( GetPalette() );
748 maBorder.FillToCF8( nLineStyle, nLineColor );
749 rStrm << nLineStyle << nLineColor << sal_uInt16( 0 );
752 if( mbPattUsed )
754 sal_uInt16 nPattern = 0, nColor = 0;
755 maArea.SetFinalColors( GetPalette() );
756 maArea.FillToCF8( nPattern, nColor );
757 rStrm << nPattern << nColor;
760 else
762 // no data blocks at all
763 rStrm << sal_uInt32( 0 ) << sal_uInt16( 0 );
766 // *** formulas ***
768 if( mxTokArr1.get() )
769 mxTokArr1->WriteArray( rStrm );
770 if( mxTokArr2.get() )
771 mxTokArr2->WriteArray( rStrm );
774 namespace {
776 const char* GetOperatorString(ScConditionMode eMode, bool& bFrmla2)
778 const char *pRet = NULL;
779 switch(eMode)
781 case SC_COND_EQUAL:
782 pRet = "equal";
783 break;
784 case SC_COND_LESS:
785 pRet = "lessThan";
786 break;
787 case SC_COND_GREATER:
788 pRet = "greaterThan";
789 break;
790 case SC_COND_EQLESS:
791 pRet = "lessThanOrEqual";
792 break;
793 case SC_COND_EQGREATER:
794 pRet = "greaterThanOrEqual";
795 break;
796 case SC_COND_NOTEQUAL:
797 pRet = "notEqual";
798 break;
799 case SC_COND_BETWEEN:
800 bFrmla2 = true;
801 pRet = "between";
802 break;
803 case SC_COND_NOTBETWEEN:
804 bFrmla2 = true;
805 pRet = "notBetween";
806 break;
807 case SC_COND_DUPLICATE:
808 pRet = "duplicateValues";
809 break;
810 case SC_COND_NOTDUPLICATE:
811 pRet = "uniqueValues";
812 break;
813 case SC_COND_DIRECT:
814 pRet = "expression";
815 break;
816 case SC_COND_NONE:
817 default:
818 break;
820 return pRet;
823 const char* GetTypeString(ScConditionMode eMode)
825 switch(eMode)
827 case SC_COND_DIRECT:
828 return "expression";
829 case SC_COND_TOP10:
830 case SC_COND_TOP_PERCENT:
831 case SC_COND_BOTTOM10:
832 case SC_COND_BOTTOM_PERCENT:
833 return "top10";
834 case SC_COND_ABOVE_AVERAGE:
835 case SC_COND_BELOW_AVERAGE:
836 return "aboveAverage";
837 case SC_COND_NOTDUPLICATE:
838 return "uniqueValues";
839 case SC_COND_DUPLICATE:
840 return "duplicateValues";
841 case SC_COND_ERROR:
842 return "containsErrors";
843 case SC_COND_NOERROR:
844 return "notContainsErrors";
845 case SC_COND_BEGINS_WITH:
846 return "beginsWith";
847 case SC_COND_ENDS_WITH:
848 return "endsWith";
849 case SC_COND_CONTAINS_TEXT:
850 return "containsText";
851 case SC_COND_NOT_CONTAINS_TEXT:
852 return "notContainsText";
853 default:
854 return "cellIs";
858 bool IsTopBottomRule(ScConditionMode eMode)
860 switch(eMode)
862 case SC_COND_TOP10:
863 case SC_COND_BOTTOM10:
864 case SC_COND_TOP_PERCENT:
865 case SC_COND_BOTTOM_PERCENT:
866 return true;
867 default:
868 break;
871 return false;
874 bool IsTextRule(ScConditionMode eMode)
876 switch(eMode)
878 case SC_COND_BEGINS_WITH:
879 case SC_COND_ENDS_WITH:
880 case SC_COND_CONTAINS_TEXT:
881 case SC_COND_NOT_CONTAINS_TEXT:
882 return true;
883 default:
884 break;
887 return false;
892 void XclExpCFImpl::SaveXml( XclExpXmlStream& rStrm )
894 bool bFmla2 = false;
895 ScConditionMode eOperation = mrFormatEntry.GetOperation();
896 sal_Int32 nAboveAverage = eOperation == SC_COND_ABOVE_AVERAGE;
897 sal_Int32 nBottom = eOperation == SC_COND_BOTTOM10
898 || eOperation == SC_COND_BOTTOM_PERCENT;
899 sal_Int32 nPercent = eOperation == SC_COND_TOP_PERCENT ||
900 eOperation == SC_COND_BOTTOM_PERCENT;
901 rtl::OString aRank("0");
902 if(IsTopBottomRule(eOperation))
904 // position and formula grammar are not important
905 // we only store a number there
906 aRank = XclXmlUtils::ToOString(mrFormatEntry.GetExpression(ScAddress(0,0,0), 0));
908 rtl::OString aText;
909 if(IsTextRule(eOperation))
911 // we need to write the text without quotes
912 // we have to actually get the string from
913 // the token array for that
914 ScTokenArray* pTokenArray = mrFormatEntry.CreateTokenArry(0);
915 if(pTokenArray->GetLen())
916 aText = XclXmlUtils::ToOString(pTokenArray->First()->GetString());
919 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
920 rWorksheet->startElement( XML_cfRule,
921 XML_type, GetTypeString( mrFormatEntry.GetOperation() ),
922 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
923 XML_operator, GetOperatorString( mrFormatEntry.GetOperation(), bFmla2 ),
924 XML_aboveAverage, OString::valueOf( nAboveAverage ).getStr(),
925 XML_bottom, OString::valueOf( nBottom ).getStr(),
926 XML_percent, OString::valueOf( nPercent ).getStr(),
927 XML_rank, aRank.getStr(),
928 XML_text, aText.getStr(),
929 XML_dxfId, OString::valueOf( GetDxfs().GetDxfId( mrFormatEntry.GetStyle() ) ).getStr(),
930 FSEND );
931 if(!IsTextRule(eOperation) && !IsTopBottomRule(eOperation))
933 rWorksheet->startElement( XML_formula, FSEND );
934 rWorksheet->write(XclXmlUtils::ToOUString( GetRoot().GetDoc(), mrFormatEntry.GetValidSrcPos(),
935 mrFormatEntry.CreateTokenArry( 0 ), GetRoot().GetOpCodeMap() ));
936 rWorksheet->endElement( XML_formula );
937 if (bFmla2)
939 rWorksheet->startElement( XML_formula, FSEND );
940 rWorksheet->write(XclXmlUtils::ToOUString( GetRoot().GetDoc(), mrFormatEntry.GetValidSrcPos(),
941 mrFormatEntry.CreateTokenArry( 1 ), GetRoot().GetOpCodeMap() ));
942 rWorksheet->endElement( XML_formula );
945 // OOXTODO: XML_extLst
946 rWorksheet->endElement( XML_cfRule );
949 // ----------------------------------------------------------------------------
951 XclExpCF::XclExpCF( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority = 0 ) :
952 XclExpRecord( EXC_ID_CF ),
953 XclExpRoot( rRoot ),
954 mxImpl( new XclExpCFImpl( rRoot, rFormatEntry, nPriority ) )
958 XclExpCF::~XclExpCF()
962 void XclExpCF::WriteBody( XclExpStream& rStrm )
964 mxImpl->WriteBody( rStrm );
967 void XclExpCF::SaveXml( XclExpXmlStream& rStrm )
969 mxImpl->SaveXml( rStrm );
972 XclExpDateFormat::XclExpDateFormat( const XclExpRoot& rRoot, const ScCondDateFormatEntry& rFormatEntry, sal_Int32 nPriority ):
973 XclExpRecord( EXC_ID_CF ),
974 XclExpRoot( rRoot ),
975 mrFormatEntry(rFormatEntry),
976 mnPriority(nPriority)
980 XclExpDateFormat::~XclExpDateFormat()
984 namespace {
986 const char* getTimePeriodString( condformat::ScCondFormatDateType eType )
988 switch(eType)
990 case condformat::TODAY:
991 return "today";
992 case condformat::YESTERDAY:
993 return "yesterday";
994 case condformat::TOMORROW:
995 return "yesterday";
996 case condformat::THISWEEK:
997 return "thisWeek";
998 case condformat::LASTWEEK:
999 return "lastWeek";
1000 case condformat::NEXTWEEK:
1001 return "nextWeek";
1002 case condformat::THISMONTH:
1003 return "thisMonth";
1004 case condformat::LASTMONTH:
1005 return "lastMonth";
1006 case condformat::NEXTMONTH:
1007 return "nextMonth";
1008 case condformat::LAST7DAYS:
1009 return "last7Days";
1010 default:
1011 break;
1013 return NULL;
1018 void XclExpDateFormat::SaveXml( XclExpXmlStream& rStrm )
1020 // only write the supported entries into OOXML
1021 const char* sTimePeriod = getTimePeriodString(mrFormatEntry.GetDateType());
1022 if(!sTimePeriod)
1023 return;
1025 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1026 rWorksheet->startElement( XML_cfRule,
1027 XML_type, "timePeriod",
1028 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1029 XML_timePeriod, sTimePeriod,
1030 XML_dxfId, OString::valueOf( GetDxfs().GetDxfId( mrFormatEntry.GetStyleName() ) ).getStr(),
1031 FSEND );
1032 rWorksheet->endElement( XML_cfRule);
1035 XclExpCfvo::XclExpCfvo(const XclExpRoot& rRoot, const ScColorScaleEntry& rEntry, const ScAddress& rAddr, bool bFirst):
1036 XclExpRecord(),
1037 XclExpRoot( rRoot ),
1038 mrEntry(rEntry),
1039 maSrcPos(rAddr),
1040 mbFirst(bFirst)
1044 namespace {
1046 rtl::OString getColorScaleType( const ScColorScaleEntry& rEntry, bool bFirst )
1048 switch(rEntry.GetType())
1050 case COLORSCALE_MIN:
1051 return "min";
1052 case COLORSCALE_MAX:
1053 return "max";
1054 case COLORSCALE_PERCENT:
1055 return "percent";
1056 case COLORSCALE_FORMULA:
1057 return "formula";
1058 case COLORSCALE_AUTO:
1059 if(bFirst)
1060 return "min";
1061 else
1062 return "max";
1063 case COLORSCALE_PERCENTILE:
1064 return "percentile";
1065 default:
1066 break;
1069 return "num";
1074 void XclExpCfvo::SaveXml( XclExpXmlStream& rStrm )
1076 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1078 rtl::OString aValue;
1079 if(mrEntry.GetType() == COLORSCALE_FORMULA)
1081 rtl::OUString aFormula = XclXmlUtils::ToOUString( GetRoot().GetDoc(), maSrcPos,
1082 mrEntry.GetFormula()->Clone(), GetRoot().GetOpCodeMap() );
1083 aValue = rtl::OUStringToOString(aFormula, RTL_TEXTENCODING_UTF8 );
1085 else
1087 aValue = OString::valueOf( mrEntry.GetValue() );
1090 rWorksheet->startElement( XML_cfvo,
1091 XML_type, getColorScaleType(mrEntry, mbFirst).getStr(),
1092 XML_val, aValue.getStr(),
1093 FSEND );
1095 rWorksheet->endElement( XML_cfvo );
1098 XclExpColScaleCol::XclExpColScaleCol( const XclExpRoot& rRoot, const Color& rColor ):
1099 XclExpRecord(),
1100 XclExpRoot( rRoot ),
1101 mrColor( rColor )
1105 XclExpColScaleCol::~XclExpColScaleCol()
1109 void XclExpColScaleCol::SaveXml( XclExpXmlStream& rStrm )
1111 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1113 rWorksheet->startElement( XML_color,
1114 XML_rgb, XclXmlUtils::ToOString( mrColor ).getStr(),
1115 FSEND );
1117 rWorksheet->endElement( XML_color );
1120 // ----------------------------------------------------------------------------
1122 XclExpCondfmt::XclExpCondfmt( const XclExpRoot& rRoot, const ScConditionalFormat& rCondFormat, XclExtLstRef xExtLst, sal_Int32& rIndex ) :
1123 XclExpRecord( EXC_ID_CONDFMT ),
1124 XclExpRoot( rRoot )
1126 const ScRangeList& aScRanges = rCondFormat.GetRange();
1127 GetAddressConverter().ConvertRangeList( maXclRanges, aScRanges, true );
1128 if( !maXclRanges.empty() )
1130 for( size_t nIndex = 0, nCount = rCondFormat.size(); nIndex < nCount; ++nIndex )
1131 if( const ScFormatEntry* pFormatEntry = rCondFormat.GetEntry( nIndex ) )
1133 if(pFormatEntry->GetType() == condformat::CONDITION)
1134 maCFList.AppendNewRecord( new XclExpCF( GetRoot(), static_cast<const ScCondFormatEntry&>(*pFormatEntry), ++rIndex ) );
1135 else if(pFormatEntry->GetType() == condformat::COLORSCALE)
1136 maCFList.AppendNewRecord( new XclExpColorScale( GetRoot(), static_cast<const ScColorScaleFormat&>(*pFormatEntry), ++rIndex ) );
1137 else if(pFormatEntry->GetType() == condformat::DATABAR)
1138 maCFList.AppendNewRecord( new XclExpDataBar( GetRoot(), static_cast<const ScDataBarFormat&>(*pFormatEntry), ++rIndex, xExtLst ) );
1139 else if(pFormatEntry->GetType() == condformat::ICONSET)
1140 maCFList.AppendNewRecord( new XclExpIconSet( GetRoot(), static_cast<const ScIconSetFormat&>(*pFormatEntry), ++rIndex ) );
1141 else if(pFormatEntry->GetType() == condformat::DATE)
1142 maCFList.AppendNewRecord( new XclExpDateFormat( GetRoot(), static_cast<const ScCondDateFormatEntry&>(*pFormatEntry), ++rIndex ) );
1144 aScRanges.Format( msSeqRef, SCA_VALID, NULL, formula::FormulaGrammar::CONV_XL_A1 );
1148 XclExpCondfmt::~XclExpCondfmt()
1152 bool XclExpCondfmt::IsValid() const
1154 return !maCFList.IsEmpty() && !maXclRanges.empty();
1157 void XclExpCondfmt::Save( XclExpStream& rStrm )
1159 if( IsValid() )
1161 XclExpRecord::Save( rStrm );
1162 maCFList.Save( rStrm );
1166 void XclExpCondfmt::WriteBody( XclExpStream& rStrm )
1168 OSL_ENSURE( !maCFList.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
1169 OSL_ENSURE( !maXclRanges.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
1171 rStrm << static_cast< sal_uInt16 >( maCFList.GetSize() )
1172 << sal_uInt16( 1 )
1173 << maXclRanges.GetEnclosingRange()
1174 << maXclRanges;
1177 void XclExpCondfmt::SaveXml( XclExpXmlStream& rStrm )
1179 if( !IsValid() )
1180 return;
1182 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1183 rWorksheet->startElement( XML_conditionalFormatting,
1184 XML_sqref, XclXmlUtils::ToOString( msSeqRef ).getStr(),
1185 // OOXTODO: XML_pivot,
1186 FSEND );
1188 maCFList.SaveXml( rStrm );
1190 rWorksheet->endElement( XML_conditionalFormatting );
1193 // ----------------------------------------------------------------------------
1195 XclExpColorScale::XclExpColorScale( const XclExpRoot& rRoot, const ScColorScaleFormat& rFormat, sal_Int32 nPriority ):
1196 XclExpRecord(),
1197 XclExpRoot( rRoot ),
1198 mnPriority( nPriority )
1200 const ScRange* pRange = rFormat.GetRange().front();
1201 ScAddress aAddr = pRange->aStart;
1202 for(ScColorScaleFormat::const_iterator itr = rFormat.begin();
1203 itr != rFormat.end(); ++itr)
1205 // exact position is not important, we allow only absolute refs
1207 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1208 maCfvoList.AppendRecord( xCfvo );
1209 XclExpColScaleColList::RecordRefType xClo( new XclExpColScaleCol( GetRoot(), itr->GetColor() ) );
1210 maColList.AppendRecord( xClo );
1214 void XclExpColorScale::SaveXml( XclExpXmlStream& rStrm )
1216 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1218 rWorksheet->startElement( XML_cfRule,
1219 XML_type, "colorScale",
1220 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1221 FSEND );
1223 rWorksheet->startElement( XML_colorScale, FSEND );
1225 maCfvoList.SaveXml(rStrm);
1226 maColList.SaveXml(rStrm);
1228 rWorksheet->endElement( XML_colorScale );
1230 rWorksheet->endElement( XML_cfRule );
1233 namespace {
1235 rtl::OString createHexStringFromDigit(sal_uInt8 nDigit)
1237 rtl::OString aString = rtl::OString::valueOf( static_cast<sal_Int32>(nDigit), 16 );
1238 if(aString.getLength() == 1)
1239 aString = aString + rtl::OString::valueOf(static_cast<sal_Int32>(0));
1240 return aString;
1243 rtl::OString createGuidStringFromInt(sal_uInt8 nGuid[16])
1245 rtl::OStringBuffer aBuffer;
1246 aBuffer.append('{');
1247 for(size_t i = 0; i < 16; ++i)
1249 aBuffer.append(createHexStringFromDigit(nGuid[i]));
1250 if(i == 3|| i == 5 || i == 7 || i == 9 )
1251 aBuffer.append('-');
1253 aBuffer.append('}');
1254 rtl::OString aString = aBuffer.makeStringAndClear();
1255 return aString.toAsciiUpperCase();
1260 XclExpDataBar::XclExpDataBar( const XclExpRoot& rRoot, const ScDataBarFormat& rFormat, sal_Int32 nPriority, XclExtLstRef xExtLst ):
1261 XclExpRecord(),
1262 XclExpRoot( rRoot ),
1263 mrFormat( rFormat ),
1264 mnPriority( nPriority )
1266 const ScRange* pRange = rFormat.GetRange().front();
1267 ScAddress aAddr = pRange->aStart;
1268 // exact position is not important, we allow only absolute refs
1269 mpCfvoLowerLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpLowerLimit.get(), aAddr, true ) );
1270 mpCfvoUpperLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpUpperLimit.get(), aAddr, false ) );
1272 mpCol.reset( new XclExpColScaleCol( GetRoot(), mrFormat.GetDataBarData()->maPositiveColor ) );
1273 if(xExtLst.get())
1275 XclExpExtRef pParent = xExtLst->GetItem( XclExpExtDataBarType );
1276 if( !pParent.get() )
1278 xExtLst->AddRecord( XclExpExtRef(new XclExpExtCondFormat( *xExtLst.get() )) );
1279 pParent = xExtLst->GetItem( XclExpExtDataBarType );
1281 sal_uInt8 nGuid[16];
1282 rtl_createUuid(nGuid, NULL, true);
1283 maGuid = createGuidStringFromInt(nGuid);
1284 static_cast<XclExpExtCondFormat*>(xExtLst->GetItem( XclExpExtDataBarType ).get())->AddRecord( XclExpExtConditionalFormattingRef(new XclExpExtConditionalFormatting( *pParent, rFormat, aAddr, maGuid) ));
1288 void XclExpDataBar::SaveXml( XclExpXmlStream& rStrm )
1290 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1292 rWorksheet->startElement( XML_cfRule,
1293 XML_type, "dataBar",
1294 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1295 FSEND );
1297 rWorksheet->startElement( XML_dataBar, FSEND );
1299 mpCfvoLowerLimit->SaveXml(rStrm);
1300 mpCfvoUpperLimit->SaveXml(rStrm);
1301 mpCol->SaveXml(rStrm);
1303 rWorksheet->endElement( XML_dataBar );
1305 // extLst entries for Excel 2010 and 2013
1306 rWorksheet->startElement( XML_extLst, FSEND );
1307 rWorksheet->startElement( XML_ext,
1308 FSNS( XML_xmlns, XML_x14 ), "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
1309 XML_uri, "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}",
1310 FSEND );
1312 rWorksheet->startElementNS( XML_x14, XML_id, FSEND );
1313 rWorksheet->write( maGuid.getStr() );
1314 rWorksheet->endElementNS( XML_x14, XML_id );
1316 rWorksheet->endElement( XML_ext );
1317 rWorksheet->endElement( XML_extLst );
1319 rWorksheet->endElement( XML_cfRule );
1322 XclExpIconSet::XclExpIconSet( const XclExpRoot& rRoot, const ScIconSetFormat& rFormat, sal_Int32 nPriority ):
1323 XclExpRecord(),
1324 XclExpRoot( rRoot ),
1325 mrFormat( rFormat ),
1326 mnPriority( nPriority )
1328 const ScRange* pRange = rFormat.GetRange().front();
1329 ScAddress aAddr = pRange->aStart;
1330 for(ScIconSetFormat::const_iterator itr = rFormat.begin();
1331 itr != rFormat.end(); ++itr)
1333 // exact position is not important, we allow only absolute refs
1335 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1336 maCfvoList.AppendRecord( xCfvo );
1340 namespace {
1342 const char* getIconSetName( ScIconSetType eType )
1344 ScIconSetMap* pMap = ScIconSetFormat::getIconSetMap();
1345 for(; pMap->pName; ++pMap)
1347 if(pMap->eType == eType)
1348 return pMap->pName;
1351 return "";
1356 void XclExpIconSet::SaveXml( XclExpXmlStream& rStrm )
1358 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1360 rWorksheet->startElement( XML_cfRule,
1361 XML_type, "iconSet",
1362 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1363 FSEND );
1365 const char* pIconSetName = getIconSetName(mrFormat.GetIconSetData()->eIconSetType);
1366 rWorksheet->startElement( XML_iconSet,
1367 XML_iconSet, pIconSetName,
1368 FSEND );
1370 maCfvoList.SaveXml( rStrm );
1372 rWorksheet->endElement( XML_iconSet );
1373 rWorksheet->endElement( XML_cfRule );
1376 // ----------------------------------------------------------------------------
1378 XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot& rRoot, XclExtLstRef xExtLst ) :
1379 XclExpRoot( rRoot )
1381 if( const ScConditionalFormatList* pCondFmtList = GetDoc().GetCondFormList(GetCurrScTab()) )
1383 sal_Int32 nIndex = 0;
1384 for( ScConditionalFormatList::const_iterator itr = pCondFmtList->begin();
1385 itr != pCondFmtList->end(); ++itr)
1387 XclExpCondfmtList::RecordRefType xCondfmtRec( new XclExpCondfmt( GetRoot(), *itr, xExtLst, nIndex ));
1388 if( xCondfmtRec->IsValid() )
1389 maCondfmtList.AppendRecord( xCondfmtRec );
1394 void XclExpCondFormatBuffer::Save( XclExpStream& rStrm )
1396 maCondfmtList.Save( rStrm );
1399 void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream& rStrm )
1401 maCondfmtList.SaveXml( rStrm );
1404 // Validation =================================================================
1406 namespace {
1408 /** Writes a formula for the DV record. */
1409 void lclWriteDvFormula( XclExpStream& rStrm, const XclTokenArray* pXclTokArr )
1411 sal_uInt16 nFmlaSize = pXclTokArr ? pXclTokArr->GetSize() : 0;
1412 rStrm << nFmlaSize << sal_uInt16( 0 );
1413 if( pXclTokArr )
1414 pXclTokArr->WriteArray( rStrm );
1417 /** Writes a formula for the DV record, based on a single string. */
1418 void lclWriteDvFormula( XclExpStream& rStrm, const XclExpString& rString )
1420 // fake a formula with a single tStr token
1421 rStrm << static_cast< sal_uInt16 >( rString.GetSize() + 1 )
1422 << sal_uInt16( 0 )
1423 << EXC_TOKID_STR
1424 << rString;
1427 const char* lcl_GetValidationType( sal_uInt32 nFlags )
1429 switch( nFlags & EXC_DV_MODE_MASK )
1431 case EXC_DV_MODE_ANY: return "none";
1432 case EXC_DV_MODE_WHOLE: return "whole";
1433 case EXC_DV_MODE_DECIMAL: return "decimal";
1434 case EXC_DV_MODE_LIST: return "list";
1435 case EXC_DV_MODE_DATE: return "date";
1436 case EXC_DV_MODE_TIME: return "time";
1437 case EXC_DV_MODE_TEXTLEN: return "textLength";
1438 case EXC_DV_MODE_CUSTOM: return "custom";
1440 return NULL;
1443 const char* lcl_GetOperatorType( sal_uInt32 nFlags )
1445 switch( nFlags & EXC_DV_COND_MASK )
1447 case EXC_DV_COND_BETWEEN: return "between";
1448 case EXC_DV_COND_NOTBETWEEN: return "notBetween";
1449 case EXC_DV_COND_EQUAL: return "equal";
1450 case EXC_DV_COND_NOTEQUAL: return "notEqual";
1451 case EXC_DV_COND_GREATER: return "greaterThan";
1452 case EXC_DV_COND_LESS: return "lessThan";
1453 case EXC_DV_COND_EQGREATER: return "greaterThanOrEqual";
1454 case EXC_DV_COND_EQLESS: return "lessThanOrEqual";
1456 return NULL;
1459 } // namespace
1461 // ----------------------------------------------------------------------------
1463 XclExpDV::XclExpDV( const XclExpRoot& rRoot, sal_uLong nScHandle ) :
1464 XclExpRecord( EXC_ID_DV ),
1465 XclExpRoot( rRoot ),
1466 mnFlags( 0 ),
1467 mnScHandle( nScHandle )
1469 if( const ScValidationData* pValData = GetDoc().GetValidationEntry( mnScHandle ) )
1471 // prompt box - empty string represented by single NUL character
1472 String aTitle, aText;
1473 bool bShowPrompt = (pValData->GetInput( aTitle, aText ) == sal_True);
1474 if( aTitle.Len() )
1475 maPromptTitle.Assign( aTitle );
1476 else
1477 maPromptTitle.Assign( '\0' );
1478 if( aText.Len() )
1479 maPromptText.Assign( aText );
1480 else
1481 maPromptText.Assign( '\0' );
1483 // error box - empty string represented by single NUL character
1484 ScValidErrorStyle eScErrorStyle;
1485 bool bShowError = (pValData->GetErrMsg( aTitle, aText, eScErrorStyle ) == sal_True);
1486 if( aTitle.Len() )
1487 maErrorTitle.Assign( aTitle );
1488 else
1489 maErrorTitle.Assign( '\0' );
1490 if( aText.Len() )
1491 maErrorText.Assign( aText );
1492 else
1493 maErrorText.Assign( '\0' );
1495 // flags
1496 switch( pValData->GetDataMode() )
1498 case SC_VALID_ANY: mnFlags |= EXC_DV_MODE_ANY; break;
1499 case SC_VALID_WHOLE: mnFlags |= EXC_DV_MODE_WHOLE; break;
1500 case SC_VALID_DECIMAL: mnFlags |= EXC_DV_MODE_DECIMAL; break;
1501 case SC_VALID_LIST: mnFlags |= EXC_DV_MODE_LIST; break;
1502 case SC_VALID_DATE: mnFlags |= EXC_DV_MODE_DATE; break;
1503 case SC_VALID_TIME: mnFlags |= EXC_DV_MODE_TIME; break;
1504 case SC_VALID_TEXTLEN: mnFlags |= EXC_DV_MODE_TEXTLEN; break;
1505 case SC_VALID_CUSTOM: mnFlags |= EXC_DV_MODE_CUSTOM; break;
1506 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown mode" );
1509 switch( pValData->GetOperation() )
1511 case SC_COND_NONE:
1512 case SC_COND_EQUAL: mnFlags |= EXC_DV_COND_EQUAL; break;
1513 case SC_COND_LESS: mnFlags |= EXC_DV_COND_LESS; break;
1514 case SC_COND_GREATER: mnFlags |= EXC_DV_COND_GREATER; break;
1515 case SC_COND_EQLESS: mnFlags |= EXC_DV_COND_EQLESS; break;
1516 case SC_COND_EQGREATER: mnFlags |= EXC_DV_COND_EQGREATER; break;
1517 case SC_COND_NOTEQUAL: mnFlags |= EXC_DV_COND_NOTEQUAL; break;
1518 case SC_COND_BETWEEN: mnFlags |= EXC_DV_COND_BETWEEN; break;
1519 case SC_COND_NOTBETWEEN: mnFlags |= EXC_DV_COND_NOTBETWEEN; break;
1520 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown condition" );
1522 switch( eScErrorStyle )
1524 case SC_VALERR_STOP: mnFlags |= EXC_DV_ERROR_STOP; break;
1525 case SC_VALERR_WARNING: mnFlags |= EXC_DV_ERROR_WARNING; break;
1526 case SC_VALERR_INFO: mnFlags |= EXC_DV_ERROR_INFO; break;
1527 case SC_VALERR_MACRO:
1528 // set INFO for validity with macro call, delete title
1529 mnFlags |= EXC_DV_ERROR_INFO;
1530 maErrorTitle.Assign( '\0' ); // contains macro name
1531 break;
1532 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown error style" );
1534 ::set_flag( mnFlags, EXC_DV_IGNOREBLANK, pValData->IsIgnoreBlank() );
1535 ::set_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN, pValData->GetListType() == ValidListType::INVISIBLE );
1536 ::set_flag( mnFlags, EXC_DV_SHOWPROMPT, bShowPrompt );
1537 ::set_flag( mnFlags, EXC_DV_SHOWERROR, bShowError );
1539 // formulas
1540 XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
1541 boost::scoped_ptr< ScTokenArray > xScTokArr;
1543 // first formula
1544 xScTokArr.reset( pValData->CreateTokenArry( 0 ) );
1545 if( xScTokArr.get() )
1547 if( pValData->GetDataMode() == SC_VALID_LIST )
1549 String aString;
1550 if( XclTokenArrayHelper::GetStringList( aString, *xScTokArr, '\n' ) )
1552 OUStringBuffer sFormulaBuf;
1553 sFormulaBuf.append( (sal_Unicode) '"' );
1554 /* Formula is a list of string tokens -> build the Excel string.
1555 Data validity is BIFF8 only (important for the XclExpString object).
1556 Excel uses the NUL character as string list separator. */
1557 mxString1.reset( new XclExpString( EXC_STR_8BITLENGTH ) );
1558 xub_StrLen nTokenCnt = comphelper::string::getTokenCount(aString, '\n');
1559 xub_StrLen nStringIx = 0;
1560 for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
1562 String aToken( aString.GetToken( 0, '\n', nStringIx ) );
1563 if( nToken > 0 )
1565 mxString1->Append(rtl::OUString(static_cast<sal_Unicode>('\0')));
1566 sFormulaBuf.append( (sal_Unicode) ',' );
1568 mxString1->Append( aToken );
1569 sFormulaBuf.append( XclXmlUtils::ToOUString( aToken ) );
1571 ::set_flag( mnFlags, EXC_DV_STRINGLIST );
1573 sFormulaBuf.append( (sal_Unicode) '"' );
1574 msFormula1 = sFormulaBuf.makeStringAndClear();
1576 else
1578 /* All other formulas in validation are stored like conditional
1579 formatting formulas (with tRefN/tAreaN tokens as value or
1580 array class). But NOT the cell references and defined names
1581 in list validation - they are stored as reference class
1582 tokens... Example:
1583 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
1584 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
1585 Formula compiler supports this by offering two different functions
1586 CreateDataValFormula() and CreateListValFormula(). */
1587 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_LISTVAL, *xScTokArr );
1588 msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1589 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1592 else
1594 // no list validation -> convert the formula
1595 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1596 msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1597 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1601 // second formula
1602 xScTokArr.reset( pValData->CreateTokenArry( 1 ) );
1603 if( xScTokArr.get() )
1605 mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1606 msFormula2 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1607 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1610 else
1612 OSL_FAIL( "XclExpDV::XclExpDV - missing core data" );
1613 mnScHandle = ULONG_MAX;
1617 XclExpDV::~XclExpDV()
1621 void XclExpDV::InsertCellRange( const ScRange& rRange )
1623 maScRanges.Join( rRange );
1626 bool XclExpDV::Finalize()
1628 GetAddressConverter().ConvertRangeList( maXclRanges, maScRanges, true );
1629 return (mnScHandle != ULONG_MAX) && !maXclRanges.empty();
1632 void XclExpDV::WriteBody( XclExpStream& rStrm )
1634 // flags and strings
1635 rStrm << mnFlags << maPromptTitle << maErrorTitle << maPromptText << maErrorText;
1636 // condition formulas
1637 if( mxString1.get() )
1638 lclWriteDvFormula( rStrm, *mxString1 );
1639 else
1640 lclWriteDvFormula( rStrm, mxTokArr1.get() );
1641 lclWriteDvFormula( rStrm, mxTokArr2.get() );
1642 // cell ranges
1643 rStrm << maXclRanges;
1646 void XclExpDV::SaveXml( XclExpXmlStream& rStrm )
1648 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1649 rWorksheet->startElement( XML_dataValidation,
1650 XML_allowBlank, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_IGNOREBLANK ) ),
1651 XML_error, XESTRING_TO_PSZ( maErrorText ),
1652 // OOXTODO: XML_errorStyle,
1653 XML_errorTitle, XESTRING_TO_PSZ( maErrorTitle ),
1654 // OOXTODO: XML_imeMode,
1655 XML_operator, lcl_GetOperatorType( mnFlags ),
1656 XML_prompt, XESTRING_TO_PSZ( maPromptText ),
1657 XML_promptTitle, XESTRING_TO_PSZ( maPromptTitle ),
1658 // showDropDown should have been showNoDropDown - check oox/xlsx import for details
1659 XML_showDropDown, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN ) ),
1660 XML_showErrorMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWERROR ) ),
1661 XML_showInputMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWPROMPT ) ),
1662 XML_sqref, XclXmlUtils::ToOString( maScRanges ).getStr(),
1663 XML_type, lcl_GetValidationType( mnFlags ),
1664 FSEND );
1665 if( !msFormula1.isEmpty() )
1667 rWorksheet->startElement( XML_formula1, FSEND );
1668 rWorksheet->writeEscaped( msFormula1 );
1669 rWorksheet->endElement( XML_formula1 );
1671 if( !msFormula2.isEmpty() )
1673 rWorksheet->startElement( XML_formula2, FSEND );
1674 rWorksheet->writeEscaped( msFormula2 );
1675 rWorksheet->endElement( XML_formula2 );
1677 rWorksheet->endElement( XML_dataValidation );
1680 // ----------------------------------------------------------------------------
1682 XclExpDval::XclExpDval( const XclExpRoot& rRoot ) :
1683 XclExpRecord( EXC_ID_DVAL, 18 ),
1684 XclExpRoot( rRoot )
1688 XclExpDval::~XclExpDval()
1692 void XclExpDval::InsertCellRange( const ScRange& rRange, sal_uLong nScHandle )
1694 if( GetBiff() == EXC_BIFF8 )
1696 XclExpDV& rDVRec = SearchOrCreateDv( nScHandle );
1697 rDVRec.InsertCellRange( rRange );
1701 void XclExpDval::Save( XclExpStream& rStrm )
1703 // check all records
1704 size_t nPos = maDVList.GetSize();
1705 while( nPos )
1707 --nPos; // backwards to keep nPos valid
1708 XclExpDVRef xDVRec = maDVList.GetRecord( nPos );
1709 if( !xDVRec->Finalize() )
1710 maDVList.RemoveRecord( nPos );
1713 // write the DVAL and the DV's
1714 if( !maDVList.IsEmpty() )
1716 XclExpRecord::Save( rStrm );
1717 maDVList.Save( rStrm );
1721 void XclExpDval::SaveXml( XclExpXmlStream& rStrm )
1723 if( maDVList.IsEmpty() )
1724 return;
1726 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1727 rWorksheet->startElement( XML_dataValidations,
1728 XML_count, OString::valueOf( (sal_Int32) maDVList.GetSize() ).getStr(),
1729 // OOXTODO: XML_disablePrompts,
1730 // OOXTODO: XML_xWindow,
1731 // OOXTODO: XML_yWindow,
1732 FSEND );
1733 maDVList.SaveXml( rStrm );
1734 rWorksheet->endElement( XML_dataValidations );
1737 XclExpDV& XclExpDval::SearchOrCreateDv( sal_uLong nScHandle )
1739 // test last found record
1740 if( mxLastFoundDV.get() && (mxLastFoundDV->GetScHandle() == nScHandle) )
1741 return *mxLastFoundDV;
1743 // binary search
1744 size_t nCurrPos = 0;
1745 if( !maDVList.IsEmpty() )
1747 size_t nFirstPos = 0;
1748 size_t nLastPos = maDVList.GetSize() - 1;
1749 bool bLoop = true;
1750 sal_uLong nCurrScHandle = ::std::numeric_limits< sal_uLong >::max();
1751 while( (nFirstPos <= nLastPos) && bLoop )
1753 nCurrPos = (nFirstPos + nLastPos) / 2;
1754 mxLastFoundDV = maDVList.GetRecord( nCurrPos );
1755 nCurrScHandle = mxLastFoundDV->GetScHandle();
1756 if( nCurrScHandle == nScHandle )
1757 bLoop = false;
1758 else if( nCurrScHandle < nScHandle )
1759 nFirstPos = nCurrPos + 1;
1760 else if( nCurrPos )
1761 nLastPos = nCurrPos - 1;
1762 else // special case for nLastPos = -1
1763 bLoop = false;
1765 if( nCurrScHandle == nScHandle )
1766 return *mxLastFoundDV;
1767 else if( nCurrScHandle < nScHandle )
1768 ++nCurrPos;
1771 // create new DV record
1772 mxLastFoundDV.reset( new XclExpDV( *this, nScHandle ) );
1773 maDVList.InsertRecord( mxLastFoundDV, nCurrPos );
1774 return *mxLastFoundDV;
1777 void XclExpDval::WriteBody( XclExpStream& rStrm )
1779 rStrm.WriteZeroBytes( 10 );
1780 rStrm << EXC_DVAL_NOOBJ << static_cast< sal_uInt32 >( maDVList.GetSize() );
1783 // Web Queries ================================================================
1785 XclExpWebQuery::XclExpWebQuery(
1786 const String& rRangeName,
1787 const String& rUrl,
1788 const String& rSource,
1789 sal_Int32 nRefrSecs ) :
1790 maDestRange( rRangeName ),
1791 maUrl( rUrl ),
1792 // refresh delay time: seconds -> minutes
1793 mnRefresh( ulimit_cast< sal_Int16 >( (nRefrSecs + 59L) / 60L ) ),
1794 mbEntireDoc( false )
1796 // comma separated list of HTML table names or indexes
1797 xub_StrLen nTokenCnt = comphelper::string::getTokenCount(rSource, ';');
1798 String aNewTables, aAppendTable;
1799 xub_StrLen nStringIx = 0;
1800 bool bExitLoop = false;
1801 for( xub_StrLen nToken = 0; (nToken < nTokenCnt) && !bExitLoop; ++nToken )
1803 String aToken( rSource.GetToken( 0, ';', nStringIx ) );
1804 mbEntireDoc = ScfTools::IsHTMLDocName( aToken );
1805 bExitLoop = mbEntireDoc || ScfTools::IsHTMLTablesName( aToken );
1806 if( !bExitLoop && ScfTools::GetHTMLNameFromName( aToken, aAppendTable ) )
1807 aNewTables = ScGlobal::addToken( aNewTables, aAppendTable, ',' );
1810 if( !bExitLoop ) // neither HTML_all nor HTML_tables found
1812 if( aNewTables.Len() )
1813 mxQryTables.reset( new XclExpString( aNewTables ) );
1814 else
1815 mbEntireDoc = true;
1819 XclExpWebQuery::~XclExpWebQuery()
1823 void XclExpWebQuery::Save( XclExpStream& rStrm )
1825 OSL_ENSURE( !mbEntireDoc || !mxQryTables.get(), "XclExpWebQuery::Save - illegal mode" );
1826 sal_uInt16 nFlags;
1828 // QSI record
1829 rStrm.StartRecord( EXC_ID_QSI, 10 + maDestRange.GetSize() );
1830 rStrm << EXC_QSI_DEFAULTFLAGS
1831 << sal_uInt16( 0x0010 )
1832 << sal_uInt16( 0x0012 )
1833 << sal_uInt32( 0x00000000 )
1834 << maDestRange;
1835 rStrm.EndRecord();
1837 // PARAMQRY record
1838 nFlags = 0;
1839 ::insert_value( nFlags, EXC_PQRYTYPE_WEBQUERY, 0, 3 );
1840 ::set_flag( nFlags, EXC_PQRY_WEBQUERY );
1841 ::set_flag( nFlags, EXC_PQRY_TABLES, !mbEntireDoc );
1842 rStrm.StartRecord( EXC_ID_PQRY, 12 );
1843 rStrm << nFlags
1844 << sal_uInt16( 0x0000 )
1845 << sal_uInt16( 0x0001 );
1846 rStrm.WriteZeroBytes( 6 );
1847 rStrm.EndRecord();
1849 // WQSTRING record
1850 rStrm.StartRecord( EXC_ID_WQSTRING, maUrl.GetSize() );
1851 rStrm << maUrl;
1852 rStrm.EndRecord();
1854 // unknown record 0x0802
1855 rStrm.StartRecord( EXC_ID_0802, 16 + maDestRange.GetSize() );
1856 rStrm << EXC_ID_0802; // repeated record id ?!?
1857 rStrm.WriteZeroBytes( 6 );
1858 rStrm << sal_uInt16( 0x0003 )
1859 << sal_uInt32( 0x00000000 )
1860 << sal_uInt16( 0x0010 )
1861 << maDestRange;
1862 rStrm.EndRecord();
1864 // WEBQRYSETTINGS record
1865 nFlags = mxQryTables.get() ? EXC_WQSETT_SPECTABLES : EXC_WQSETT_ALL;
1866 rStrm.StartRecord( EXC_ID_WQSETT, 28 );
1867 rStrm << EXC_ID_WQSETT // repeated record id ?!?
1868 << sal_uInt16( 0x0000 )
1869 << sal_uInt16( 0x0004 )
1870 << sal_uInt16( 0x0000 )
1871 << EXC_WQSETT_DEFAULTFLAGS
1872 << nFlags;
1873 rStrm.WriteZeroBytes( 10 );
1874 rStrm << mnRefresh // refresh delay in minutes
1875 << EXC_WQSETT_FORMATFULL
1876 << sal_uInt16( 0x0000 );
1877 rStrm.EndRecord();
1879 // WEBQRYTABLES record
1880 if( mxQryTables.get() )
1882 rStrm.StartRecord( EXC_ID_WQTABLES, 4 + mxQryTables->GetSize() );
1883 rStrm << EXC_ID_WQTABLES // repeated record id ?!?
1884 << sal_uInt16( 0x0000 )
1885 << *mxQryTables; // comma separated list of source tables
1886 rStrm.EndRecord();
1890 // ----------------------------------------------------------------------------
1892 XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot& rRoot )
1894 SCTAB nScTab = rRoot.GetCurrScTab();
1895 SfxObjectShell* pShell = rRoot.GetDocShell();
1896 if( !pShell ) return;
1897 ScfPropertySet aModelProp( pShell->GetModel() );
1898 if( !aModelProp.Is() ) return;
1900 Reference< XAreaLinks > xAreaLinks;
1901 aModelProp.GetProperty( xAreaLinks, SC_UNO_AREALINKS );
1902 Reference< XIndexAccess > xLinksIA( xAreaLinks, UNO_QUERY );
1903 if( !xLinksIA.is() ) return;
1905 for( sal_Int32 nIndex = 0, nCount = xLinksIA->getCount(); nIndex < nCount; ++nIndex )
1907 Reference< XAreaLink > xAreaLink( xLinksIA->getByIndex( nIndex ), UNO_QUERY );
1908 if( xAreaLink.is() )
1910 CellRangeAddress aDestRange( xAreaLink->getDestArea() );
1911 if( static_cast< SCTAB >( aDestRange.Sheet ) == nScTab )
1913 ScfPropertySet aLinkProp( xAreaLink );
1914 OUString aFilter;
1915 if( aLinkProp.GetProperty( aFilter, SC_UNONAME_FILTER ) &&
1916 (aFilter == EXC_WEBQRY_FILTER) )
1918 // get properties
1919 OUString /*aFilterOpt,*/ aUrl;
1920 sal_Int32 nRefresh = 0;
1922 // aLinkProp.GetProperty( aFilterOpt, SC_UNONAME_FILTOPT );
1923 aLinkProp.GetProperty( aUrl, SC_UNONAME_LINKURL );
1924 aLinkProp.GetProperty( nRefresh, SC_UNONAME_REFDELAY );
1926 String aAbsDoc( ScGlobal::GetAbsDocName( aUrl, pShell ) );
1927 INetURLObject aUrlObj( aAbsDoc );
1928 String aWebQueryUrl( aUrlObj.getFSysPath( INetURLObject::FSYS_DOS ) );
1929 if( !aWebQueryUrl.Len() )
1930 aWebQueryUrl = aAbsDoc;
1932 // find range or create a new range
1933 String aRangeName;
1934 ScRange aScDestRange;
1935 ScUnoConversion::FillScRange( aScDestRange, aDestRange );
1936 if( const ScRangeData* pRangeData = rRoot.GetNamedRanges().findByRange( aScDestRange ) )
1938 aRangeName = pRangeData->GetName();
1940 else
1942 XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
1943 XclExpNameManager& rNameMgr = rRoot.GetNameManager();
1945 // create a new unique defined name containing the range
1946 XclTokenArrayRef xTokArr = rFmlaComp.CreateFormula( EXC_FMLATYPE_WQUERY, aScDestRange );
1947 sal_uInt16 nNameIdx = rNameMgr.InsertUniqueName( aUrlObj.getBase(), xTokArr, nScTab );
1948 aRangeName = rNameMgr.GetOrigName( nNameIdx );
1951 // create and store the web query record
1952 if( aRangeName.Len() )
1953 AppendNewRecord( new XclExpWebQuery(
1954 aRangeName, aWebQueryUrl, xAreaLink->getSourceArea(), nRefresh ) );
1961 // ============================================================================
1963 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */