bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xecontent.cxx
blob7287fe7af9834a3eed16e028647eb37eec32d7cc
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;
62 // Shared string table ========================================================
64 /** A single string entry in the hash table. */
65 struct XclExpHashEntry
67 const XclExpString* mpString; /// Pointer to the string (no ownership).
68 sal_uInt32 mnSstIndex; /// The SST index of this string.
69 inline explicit XclExpHashEntry( const XclExpString* pString = 0, sal_uInt32 nSstIndex = 0 ) :
70 mpString( pString ), mnSstIndex( nSstIndex ) {}
73 /** Function object for strict weak ordering. */
74 struct XclExpHashEntrySWO
76 inline bool operator()( const XclExpHashEntry& rLeft, const XclExpHashEntry& rRight ) const
77 { return *rLeft.mpString < *rRight.mpString; }
80 // ----------------------------------------------------------------------------
82 /** Implementation of the SST export.
83 @descr Stores all passed strings in a hash table and prevents repeated
84 insertion of equal strings. */
85 class XclExpSstImpl
87 public:
88 explicit XclExpSstImpl();
90 /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
91 sal_uInt32 Insert( XclExpStringRef xString );
93 /** Writes the complete SST and EXTSST records. */
94 void Save( XclExpStream& rStrm );
95 void SaveXml( XclExpXmlStream& rStrm );
97 private:
98 typedef ::std::list< XclExpStringRef > XclExpStringList;
99 typedef ::std::vector< XclExpHashEntry > XclExpHashVec;
100 typedef ::std::vector< XclExpHashVec > XclExpHashTab;
102 XclExpStringList maStringList; /// List of unique strings (in SST ID order).
103 XclExpHashTab maHashTab; /// Hashed table that manages string pointers.
104 sal_uInt32 mnTotal; /// Total count of strings (including doubles).
105 sal_uInt32 mnSize; /// Size of the SST (count of unique strings).
108 // ----------------------------------------------------------------------------
110 const sal_uInt32 EXC_SST_HASHTABLE_SIZE = 2048;
112 XclExpSstImpl::XclExpSstImpl() :
113 maHashTab( EXC_SST_HASHTABLE_SIZE ),
114 mnTotal( 0 ),
115 mnSize( 0 )
119 sal_uInt32 XclExpSstImpl::Insert( XclExpStringRef xString )
121 OSL_ENSURE( xString.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
122 if( !xString.get() )
123 xString.reset( new XclExpString );
125 ++mnTotal;
126 sal_uInt32 nSstIndex = 0;
128 // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
129 sal_uInt16 nHash = xString->GetHash();
130 (nHash ^= (nHash / EXC_SST_HASHTABLE_SIZE)) %= EXC_SST_HASHTABLE_SIZE;
132 XclExpHashVec& rVec = maHashTab[ nHash ];
133 XclExpHashEntry aEntry( xString.get(), mnSize );
134 XclExpHashVec::iterator aIt = ::std::lower_bound( rVec.begin(), rVec.end(), aEntry, XclExpHashEntrySWO() );
135 if( (aIt == rVec.end()) || (*aIt->mpString != *xString) )
137 nSstIndex = mnSize;
138 maStringList.push_back( xString );
139 rVec.insert( aIt, aEntry );
140 ++mnSize;
142 else
144 nSstIndex = aIt->mnSstIndex;
147 return nSstIndex;
150 void XclExpSstImpl::Save( XclExpStream& rStrm )
152 if( maStringList.empty() )
153 return;
155 SvMemoryStream aExtSst( 8192 );
157 sal_uInt32 nBucket = mnSize;
158 while( nBucket > 0x0100 )
159 nBucket /= 2;
161 sal_uInt16 nPerBucket = llimit_cast< sal_uInt16 >( nBucket, 8 );
162 sal_uInt16 nBucketIndex = 0;
164 // *** write the SST record ***
166 rStrm.StartRecord( EXC_ID_SST, 8 );
168 rStrm << mnTotal << mnSize;
169 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
171 if( !nBucketIndex )
173 // write bucket info before string to get correct record position
174 sal_uInt32 nStrmPos = static_cast< sal_uInt32 >( rStrm.GetSvStreamPos() );
175 sal_uInt16 nRecPos = rStrm.GetRawRecPos() + 4;
176 aExtSst << nStrmPos // stream position
177 << nRecPos // position from start of SST or CONTINUE
178 << sal_uInt16( 0 ); // reserved
181 rStrm << **aIt;
183 if( ++nBucketIndex == nPerBucket )
184 nBucketIndex = 0;
187 rStrm.EndRecord();
189 // *** write the EXTSST record ***
191 rStrm.StartRecord( EXC_ID_EXTSST, 0 );
193 rStrm << nPerBucket;
194 rStrm.SetSliceSize( 8 ); // size of one bucket info
195 aExtSst.Seek( STREAM_SEEK_TO_BEGIN );
196 rStrm.CopyFromStream( aExtSst );
198 rStrm.EndRecord();
201 void XclExpSstImpl::SaveXml( XclExpXmlStream& rStrm )
203 if( maStringList.empty() )
204 return;
206 sax_fastparser::FSHelperPtr pSst = rStrm.CreateOutputStream(
207 OUString( "xl/sharedStrings.xml"),
208 OUString( "sharedStrings.xml" ),
209 rStrm.GetCurrentStream()->getOutputStream(),
210 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
211 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
212 rStrm.PushStream( pSst );
214 pSst->startElement( XML_sst,
215 XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
216 XML_count, OString::valueOf( (sal_Int32) mnTotal ).getStr(),
217 XML_uniqueCount, OString::valueOf( (sal_Int32) mnSize ).getStr(),
218 FSEND );
220 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
222 pSst->startElement( XML_si, FSEND );
223 (*aIt)->WriteXml( rStrm );
224 pSst->endElement( XML_si );
227 pSst->endElement( XML_sst );
229 rStrm.PopStream();
232 // ----------------------------------------------------------------------------
234 XclExpSst::XclExpSst() :
235 mxImpl( new XclExpSstImpl )
239 XclExpSst::~XclExpSst()
243 sal_uInt32 XclExpSst::Insert( XclExpStringRef xString )
245 return mxImpl->Insert( xString );
248 void XclExpSst::Save( XclExpStream& rStrm )
250 mxImpl->Save( rStrm );
253 void XclExpSst::SaveXml( XclExpXmlStream& rStrm )
255 mxImpl->SaveXml( rStrm );
258 // Merged cells ===============================================================
260 XclExpMergedcells::XclExpMergedcells( const XclExpRoot& rRoot ) :
261 XclExpRoot( rRoot )
265 void XclExpMergedcells::AppendRange( const ScRange& rRange, sal_uInt32 nBaseXFId )
267 if( GetBiff() == EXC_BIFF8 )
269 maMergedRanges.Append( rRange );
270 maBaseXFIds.push_back( nBaseXFId );
274 sal_uInt32 XclExpMergedcells::GetBaseXFId( const ScAddress& rPos ) const
276 OSL_ENSURE( maBaseXFIds.size() == maMergedRanges.size(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
277 ScfUInt32Vec::const_iterator aIt = maBaseXFIds.begin();
278 ScRangeList& rNCRanges = const_cast< ScRangeList& >( maMergedRanges );
279 for ( size_t i = 0, nRanges = rNCRanges.size(); i < nRanges; ++i, ++aIt )
281 const ScRange* pScRange = rNCRanges[ i ];
282 if( pScRange->In( rPos ) )
283 return *aIt;
285 return EXC_XFID_NOTFOUND;
288 void XclExpMergedcells::Save( XclExpStream& rStrm )
290 if( GetBiff() == EXC_BIFF8 )
292 XclRangeList aXclRanges;
293 GetAddressConverter().ConvertRangeList( aXclRanges, maMergedRanges, true );
294 size_t nFirstRange = 0;
295 size_t nRemainingRanges = aXclRanges.size();
296 while( nRemainingRanges > 0 )
298 size_t nRangeCount = ::std::min< size_t >( nRemainingRanges, EXC_MERGEDCELLS_MAXCOUNT );
299 rStrm.StartRecord( EXC_ID_MERGEDCELLS, 2 + 8 * nRangeCount );
300 aXclRanges.WriteSubList( rStrm, nFirstRange, nRangeCount );
301 rStrm.EndRecord();
302 nFirstRange += nRangeCount;
303 nRemainingRanges -= nRangeCount;
308 void XclExpMergedcells::SaveXml( XclExpXmlStream& rStrm )
310 size_t nCount = maMergedRanges.size();
311 if( !nCount )
312 return;
313 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
314 rWorksheet->startElement( XML_mergeCells,
315 XML_count, OString::valueOf( (sal_Int32) nCount ).getStr(),
316 FSEND );
317 for( size_t i = 0; i < nCount; ++i )
319 if( const ScRange* pRange = maMergedRanges[ i ] )
321 rWorksheet->singleElement( XML_mergeCell,
322 XML_ref, XclXmlUtils::ToOString( *pRange ).getStr(),
323 FSEND );
326 rWorksheet->endElement( XML_mergeCells );
329 // Hyperlinks =================================================================
331 XclExpHyperlink::XclExpHyperlink( const XclExpRoot& rRoot, const SvxURLField& rUrlField, const ScAddress& rScPos ) :
332 XclExpRecord( EXC_ID_HLINK ),
333 maScPos( rScPos ),
334 mxVarData( new SvMemoryStream ),
335 mnFlags( 0 )
337 const String& rUrl = rUrlField.GetURL();
338 const String& rRepr = rUrlField.GetRepresentation();
339 INetURLObject aUrlObj( rUrl );
340 const INetProtocol eProtocol = aUrlObj.GetProtocol();
341 bool bWithRepr = rRepr.Len() > 0;
342 XclExpStream aXclStrm( *mxVarData, rRoot ); // using in raw write mode.
344 // description
345 if( bWithRepr )
347 XclExpString aDescr( rRepr, EXC_STR_FORCEUNICODE, 255 );
348 aXclStrm << sal_uInt32( aDescr.Len() + 1 ); // string length + 1 trailing zero word
349 aDescr.WriteBuffer( aXclStrm ); // NO flags
350 aXclStrm << sal_uInt16( 0 );
352 mnFlags |= EXC_HLINK_DESCR;
353 mxRepr.reset( new String( rRepr ) );
356 // file link or URL
357 if( eProtocol == INET_PROT_FILE || eProtocol == INET_PROT_SMB )
359 sal_uInt16 nLevel;
360 bool bRel;
361 String aFileName( BuildFileName( nLevel, bRel, rUrl, rRoot ) );
363 if( eProtocol == INET_PROT_SMB )
365 // #n382718# (and #n261623#) Convert smb notation to '\\'
366 aFileName = aUrlObj.GetMainURL( INetURLObject::NO_DECODE );
367 aFileName = OUString( aFileName.GetBuffer() + 4 ); // skip the 'smb:' part
368 aFileName.SearchAndReplaceAll( '/', '\\' );
371 if( !bRel )
372 mnFlags |= EXC_HLINK_ABS;
373 mnFlags |= EXC_HLINK_BODY;
375 OString aAsciiLink(OUStringToOString(aFileName,
376 rRoot.GetTextEncoding()));
377 XclExpString aLink( aFileName, EXC_STR_FORCEUNICODE, 255 );
378 aXclStrm << XclTools::maGuidFileMoniker
379 << nLevel
380 << sal_uInt32( aAsciiLink.getLength() + 1 ); // string length + 1 trailing zero byte
381 aXclStrm.Write( aAsciiLink.getStr(), aAsciiLink.getLength() );
382 aXclStrm << sal_uInt8( 0 )
383 << sal_uInt32( 0xDEADFFFF );
384 aXclStrm.WriteZeroBytes( 20 );
385 aXclStrm << sal_uInt32( aLink.GetBufferSize() + 6 )
386 << sal_uInt32( aLink.GetBufferSize() ) // byte count, not string length
387 << sal_uInt16( 0x0003 );
388 aLink.WriteBuffer( aXclStrm ); // NO flags
390 if( !mxRepr.get() )
391 mxRepr.reset( new String( aFileName ) );
393 msTarget = XclXmlUtils::ToOUString( aLink );
394 // ooxml expects the file:/// part appended ( or at least
395 // ms2007 does, ms2010 is more tolerant )
396 msTarget = "file:///" + msTarget;
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 case SC_COND_ABOVE_EQUAL_AVERAGE:
837 case SC_COND_BELOW_EQUAL_AVERAGE:
838 return "aboveAverage";
839 case SC_COND_NOTDUPLICATE:
840 return "uniqueValues";
841 case SC_COND_DUPLICATE:
842 return "duplicateValues";
843 case SC_COND_ERROR:
844 return "containsErrors";
845 case SC_COND_NOERROR:
846 return "notContainsErrors";
847 case SC_COND_BEGINS_WITH:
848 return "beginsWith";
849 case SC_COND_ENDS_WITH:
850 return "endsWith";
851 case SC_COND_CONTAINS_TEXT:
852 return "containsText";
853 case SC_COND_NOT_CONTAINS_TEXT:
854 return "notContainsText";
855 default:
856 return "cellIs";
860 bool IsTopBottomRule(ScConditionMode eMode)
862 switch(eMode)
864 case SC_COND_TOP10:
865 case SC_COND_BOTTOM10:
866 case SC_COND_TOP_PERCENT:
867 case SC_COND_BOTTOM_PERCENT:
868 return true;
869 default:
870 break;
873 return false;
876 bool IsTextRule(ScConditionMode eMode)
878 switch(eMode)
880 case SC_COND_BEGINS_WITH:
881 case SC_COND_ENDS_WITH:
882 case SC_COND_CONTAINS_TEXT:
883 case SC_COND_NOT_CONTAINS_TEXT:
884 return true;
885 default:
886 break;
889 return false;
894 void XclExpCFImpl::SaveXml( XclExpXmlStream& rStrm )
896 bool bFmla2 = false;
897 ScConditionMode eOperation = mrFormatEntry.GetOperation();
898 sal_Int32 nAboveAverage = eOperation == SC_COND_ABOVE_AVERAGE ||
899 eOperation == SC_COND_ABOVE_EQUAL_AVERAGE;
900 sal_Int32 nEqualAverage = eOperation == SC_COND_ABOVE_EQUAL_AVERAGE ||
901 eOperation == SC_COND_BELOW_EQUAL_AVERAGE;
902 sal_Int32 nBottom = eOperation == SC_COND_BOTTOM10
903 || eOperation == SC_COND_BOTTOM_PERCENT;
904 sal_Int32 nPercent = eOperation == SC_COND_TOP_PERCENT ||
905 eOperation == SC_COND_BOTTOM_PERCENT;
906 OString aRank("0");
907 if(IsTopBottomRule(eOperation))
909 // position and formula grammar are not important
910 // we only store a number there
911 aRank = XclXmlUtils::ToOString(mrFormatEntry.GetExpression(ScAddress(0,0,0), 0));
913 OString aText;
914 if(IsTextRule(eOperation))
916 // we need to write the text without quotes
917 // we have to actually get the string from
918 // the token array for that
919 boost::scoped_ptr<ScTokenArray> pTokenArray(mrFormatEntry.CreateTokenArry(0));
920 if(pTokenArray->GetLen())
921 aText = XclXmlUtils::ToOString(pTokenArray->First()->GetString());
924 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
925 rWorksheet->startElement( XML_cfRule,
926 XML_type, GetTypeString( mrFormatEntry.GetOperation() ),
927 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
928 XML_operator, GetOperatorString( mrFormatEntry.GetOperation(), bFmla2 ),
929 XML_aboveAverage, OString::valueOf( nAboveAverage ).getStr(),
930 XML_equalAverage, OString::valueOf( nEqualAverage ).getStr(),
931 XML_bottom, OString::valueOf( nBottom ).getStr(),
932 XML_percent, OString::valueOf( nPercent ).getStr(),
933 XML_rank, aRank.getStr(),
934 XML_text, aText.getStr(),
935 XML_dxfId, OString::valueOf( GetDxfs().GetDxfId( mrFormatEntry.GetStyle() ) ).getStr(),
936 FSEND );
937 if(!IsTextRule(eOperation) && !IsTopBottomRule(eOperation))
939 rWorksheet->startElement( XML_formula, FSEND );
940 rWorksheet->write(XclXmlUtils::ToOUString( GetRoot().GetDoc(), mrFormatEntry.GetValidSrcPos(),
941 mrFormatEntry.CreateTokenArry( 0 ), GetRoot().GetOpCodeMap() ));
942 rWorksheet->endElement( XML_formula );
943 if (bFmla2)
945 rWorksheet->startElement( XML_formula, FSEND );
946 rWorksheet->write(XclXmlUtils::ToOUString( GetRoot().GetDoc(), mrFormatEntry.GetValidSrcPos(),
947 mrFormatEntry.CreateTokenArry( 1 ), GetRoot().GetOpCodeMap() ));
948 rWorksheet->endElement( XML_formula );
951 // OOXTODO: XML_extLst
952 rWorksheet->endElement( XML_cfRule );
955 // ----------------------------------------------------------------------------
957 XclExpCF::XclExpCF( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority = 0 ) :
958 XclExpRecord( EXC_ID_CF ),
959 XclExpRoot( rRoot ),
960 mxImpl( new XclExpCFImpl( rRoot, rFormatEntry, nPriority ) )
964 XclExpCF::~XclExpCF()
968 void XclExpCF::WriteBody( XclExpStream& rStrm )
970 mxImpl->WriteBody( rStrm );
973 void XclExpCF::SaveXml( XclExpXmlStream& rStrm )
975 mxImpl->SaveXml( rStrm );
978 XclExpDateFormat::XclExpDateFormat( const XclExpRoot& rRoot, const ScCondDateFormatEntry& rFormatEntry, sal_Int32 nPriority ):
979 XclExpRecord( EXC_ID_CF ),
980 XclExpRoot( rRoot ),
981 mrFormatEntry(rFormatEntry),
982 mnPriority(nPriority)
986 XclExpDateFormat::~XclExpDateFormat()
990 namespace {
992 const char* getTimePeriodString( condformat::ScCondFormatDateType eType )
994 switch(eType)
996 case condformat::TODAY:
997 return "today";
998 case condformat::YESTERDAY:
999 return "yesterday";
1000 case condformat::TOMORROW:
1001 return "yesterday";
1002 case condformat::THISWEEK:
1003 return "thisWeek";
1004 case condformat::LASTWEEK:
1005 return "lastWeek";
1006 case condformat::NEXTWEEK:
1007 return "nextWeek";
1008 case condformat::THISMONTH:
1009 return "thisMonth";
1010 case condformat::LASTMONTH:
1011 return "lastMonth";
1012 case condformat::NEXTMONTH:
1013 return "nextMonth";
1014 case condformat::LAST7DAYS:
1015 return "last7Days";
1016 default:
1017 break;
1019 return NULL;
1024 void XclExpDateFormat::SaveXml( XclExpXmlStream& rStrm )
1026 // only write the supported entries into OOXML
1027 const char* sTimePeriod = getTimePeriodString(mrFormatEntry.GetDateType());
1028 if(!sTimePeriod)
1029 return;
1031 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1032 rWorksheet->startElement( XML_cfRule,
1033 XML_type, "timePeriod",
1034 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1035 XML_timePeriod, sTimePeriod,
1036 XML_dxfId, OString::valueOf( GetDxfs().GetDxfId( mrFormatEntry.GetStyleName() ) ).getStr(),
1037 FSEND );
1038 rWorksheet->endElement( XML_cfRule);
1041 XclExpCfvo::XclExpCfvo(const XclExpRoot& rRoot, const ScColorScaleEntry& rEntry, const ScAddress& rAddr, bool bFirst):
1042 XclExpRecord(),
1043 XclExpRoot( rRoot ),
1044 mrEntry(rEntry),
1045 maSrcPos(rAddr),
1046 mbFirst(bFirst)
1050 namespace {
1052 OString getColorScaleType( const ScColorScaleEntry& rEntry, bool bFirst )
1054 switch(rEntry.GetType())
1056 case COLORSCALE_MIN:
1057 return "min";
1058 case COLORSCALE_MAX:
1059 return "max";
1060 case COLORSCALE_PERCENT:
1061 return "percent";
1062 case COLORSCALE_FORMULA:
1063 return "formula";
1064 case COLORSCALE_AUTO:
1065 if(bFirst)
1066 return "min";
1067 else
1068 return "max";
1069 case COLORSCALE_PERCENTILE:
1070 return "percentile";
1071 default:
1072 break;
1075 return "num";
1080 void XclExpCfvo::SaveXml( XclExpXmlStream& rStrm )
1082 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1084 OString aValue;
1085 if(mrEntry.GetType() == COLORSCALE_FORMULA)
1087 OUString aFormula = XclXmlUtils::ToOUString( GetRoot().GetDoc(), maSrcPos,
1088 mrEntry.GetFormula()->Clone(), GetRoot().GetOpCodeMap() );
1089 aValue = OUStringToOString(aFormula, RTL_TEXTENCODING_UTF8 );
1091 else
1093 aValue = OString::valueOf( mrEntry.GetValue() );
1096 rWorksheet->startElement( XML_cfvo,
1097 XML_type, getColorScaleType(mrEntry, mbFirst).getStr(),
1098 XML_val, aValue.getStr(),
1099 FSEND );
1101 rWorksheet->endElement( XML_cfvo );
1104 XclExpColScaleCol::XclExpColScaleCol( const XclExpRoot& rRoot, const Color& rColor ):
1105 XclExpRecord(),
1106 XclExpRoot( rRoot ),
1107 mrColor( rColor )
1111 XclExpColScaleCol::~XclExpColScaleCol()
1115 void XclExpColScaleCol::SaveXml( XclExpXmlStream& rStrm )
1117 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1119 rWorksheet->startElement( XML_color,
1120 XML_rgb, XclXmlUtils::ToOString( mrColor ).getStr(),
1121 FSEND );
1123 rWorksheet->endElement( XML_color );
1126 // ----------------------------------------------------------------------------
1128 XclExpCondfmt::XclExpCondfmt( const XclExpRoot& rRoot, const ScConditionalFormat& rCondFormat, XclExtLstRef xExtLst, sal_Int32& rIndex ) :
1129 XclExpRecord( EXC_ID_CONDFMT ),
1130 XclExpRoot( rRoot )
1132 const ScRangeList& aScRanges = rCondFormat.GetRange();
1133 GetAddressConverter().ConvertRangeList( maXclRanges, aScRanges, true );
1134 if( !maXclRanges.empty() )
1136 for( size_t nIndex = 0, nCount = rCondFormat.size(); nIndex < nCount; ++nIndex )
1137 if( const ScFormatEntry* pFormatEntry = rCondFormat.GetEntry( nIndex ) )
1139 if(pFormatEntry->GetType() == condformat::CONDITION)
1140 maCFList.AppendNewRecord( new XclExpCF( GetRoot(), static_cast<const ScCondFormatEntry&>(*pFormatEntry), ++rIndex ) );
1141 else if(pFormatEntry->GetType() == condformat::COLORSCALE)
1142 maCFList.AppendNewRecord( new XclExpColorScale( GetRoot(), static_cast<const ScColorScaleFormat&>(*pFormatEntry), ++rIndex ) );
1143 else if(pFormatEntry->GetType() == condformat::DATABAR)
1144 maCFList.AppendNewRecord( new XclExpDataBar( GetRoot(), static_cast<const ScDataBarFormat&>(*pFormatEntry), ++rIndex, xExtLst ) );
1145 else if(pFormatEntry->GetType() == condformat::ICONSET)
1146 maCFList.AppendNewRecord( new XclExpIconSet( GetRoot(), static_cast<const ScIconSetFormat&>(*pFormatEntry), ++rIndex ) );
1147 else if(pFormatEntry->GetType() == condformat::DATE)
1148 maCFList.AppendNewRecord( new XclExpDateFormat( GetRoot(), static_cast<const ScCondDateFormatEntry&>(*pFormatEntry), ++rIndex ) );
1150 aScRanges.Format( msSeqRef, SCA_VALID, NULL, formula::FormulaGrammar::CONV_XL_A1 );
1154 XclExpCondfmt::~XclExpCondfmt()
1158 bool XclExpCondfmt::IsValid() const
1160 return !maCFList.IsEmpty() && !maXclRanges.empty();
1163 void XclExpCondfmt::Save( XclExpStream& rStrm )
1165 if( IsValid() )
1167 XclExpRecord::Save( rStrm );
1168 maCFList.Save( rStrm );
1172 void XclExpCondfmt::WriteBody( XclExpStream& rStrm )
1174 OSL_ENSURE( !maCFList.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
1175 OSL_ENSURE( !maXclRanges.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
1177 rStrm << static_cast< sal_uInt16 >( maCFList.GetSize() )
1178 << sal_uInt16( 1 )
1179 << maXclRanges.GetEnclosingRange()
1180 << maXclRanges;
1183 void XclExpCondfmt::SaveXml( XclExpXmlStream& rStrm )
1185 if( !IsValid() )
1186 return;
1188 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1189 rWorksheet->startElement( XML_conditionalFormatting,
1190 XML_sqref, XclXmlUtils::ToOString( msSeqRef ).getStr(),
1191 // OOXTODO: XML_pivot,
1192 FSEND );
1194 maCFList.SaveXml( rStrm );
1196 rWorksheet->endElement( XML_conditionalFormatting );
1199 // ----------------------------------------------------------------------------
1201 XclExpColorScale::XclExpColorScale( const XclExpRoot& rRoot, const ScColorScaleFormat& rFormat, sal_Int32 nPriority ):
1202 XclExpRecord(),
1203 XclExpRoot( rRoot ),
1204 mnPriority( nPriority )
1206 const ScRange* pRange = rFormat.GetRange().front();
1207 ScAddress aAddr = pRange->aStart;
1208 for(ScColorScaleFormat::const_iterator itr = rFormat.begin();
1209 itr != rFormat.end(); ++itr)
1211 // exact position is not important, we allow only absolute refs
1213 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1214 maCfvoList.AppendRecord( xCfvo );
1215 XclExpColScaleColList::RecordRefType xClo( new XclExpColScaleCol( GetRoot(), itr->GetColor() ) );
1216 maColList.AppendRecord( xClo );
1220 void XclExpColorScale::SaveXml( XclExpXmlStream& rStrm )
1222 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1224 rWorksheet->startElement( XML_cfRule,
1225 XML_type, "colorScale",
1226 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1227 FSEND );
1229 rWorksheet->startElement( XML_colorScale, FSEND );
1231 maCfvoList.SaveXml(rStrm);
1232 maColList.SaveXml(rStrm);
1234 rWorksheet->endElement( XML_colorScale );
1236 rWorksheet->endElement( XML_cfRule );
1239 namespace {
1241 OString createHexStringFromDigit(sal_uInt8 nDigit)
1243 OString aString = OString::valueOf( static_cast<sal_Int32>(nDigit), 16 );
1244 if(aString.getLength() == 1)
1245 aString = aString + OString::number(0);
1246 return aString;
1249 OString createGuidStringFromInt(sal_uInt8 nGuid[16])
1251 OStringBuffer aBuffer;
1252 aBuffer.append('{');
1253 for(size_t i = 0; i < 16; ++i)
1255 aBuffer.append(createHexStringFromDigit(nGuid[i]));
1256 if(i == 3|| i == 5 || i == 7 || i == 9 )
1257 aBuffer.append('-');
1259 aBuffer.append('}');
1260 OString aString = aBuffer.makeStringAndClear();
1261 return aString.toAsciiUpperCase();
1266 XclExpDataBar::XclExpDataBar( const XclExpRoot& rRoot, const ScDataBarFormat& rFormat, sal_Int32 nPriority, XclExtLstRef xExtLst ):
1267 XclExpRecord(),
1268 XclExpRoot( rRoot ),
1269 mrFormat( rFormat ),
1270 mnPriority( nPriority )
1272 const ScRange* pRange = rFormat.GetRange().front();
1273 ScAddress aAddr = pRange->aStart;
1274 // exact position is not important, we allow only absolute refs
1275 mpCfvoLowerLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpLowerLimit.get(), aAddr, true ) );
1276 mpCfvoUpperLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpUpperLimit.get(), aAddr, false ) );
1278 mpCol.reset( new XclExpColScaleCol( GetRoot(), mrFormat.GetDataBarData()->maPositiveColor ) );
1279 if(xExtLst.get())
1281 XclExpExtRef pParent = xExtLst->GetItem( XclExpExtDataBarType );
1282 if( !pParent.get() )
1284 xExtLst->AddRecord( XclExpExtRef(new XclExpExtCondFormat( *xExtLst.get() )) );
1285 pParent = xExtLst->GetItem( XclExpExtDataBarType );
1287 sal_uInt8 nGuid[16];
1288 rtl_createUuid(nGuid, NULL, true);
1289 maGuid = createGuidStringFromInt(nGuid);
1290 static_cast<XclExpExtCondFormat*>(xExtLst->GetItem( XclExpExtDataBarType ).get())->AddRecord( XclExpExtConditionalFormattingRef(new XclExpExtConditionalFormatting( *pParent, rFormat, aAddr, maGuid) ));
1294 void XclExpDataBar::SaveXml( XclExpXmlStream& rStrm )
1296 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1298 rWorksheet->startElement( XML_cfRule,
1299 XML_type, "dataBar",
1300 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1301 FSEND );
1303 rWorksheet->startElement( XML_dataBar, FSEND );
1305 mpCfvoLowerLimit->SaveXml(rStrm);
1306 mpCfvoUpperLimit->SaveXml(rStrm);
1307 mpCol->SaveXml(rStrm);
1309 rWorksheet->endElement( XML_dataBar );
1311 // extLst entries for Excel 2010 and 2013
1312 rWorksheet->startElement( XML_extLst, FSEND );
1313 rWorksheet->startElement( XML_ext,
1314 FSNS( XML_xmlns, XML_x14 ), "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
1315 XML_uri, "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}",
1316 FSEND );
1318 rWorksheet->startElementNS( XML_x14, XML_id, FSEND );
1319 rWorksheet->write( maGuid.getStr() );
1320 rWorksheet->endElementNS( XML_x14, XML_id );
1322 rWorksheet->endElement( XML_ext );
1323 rWorksheet->endElement( XML_extLst );
1325 rWorksheet->endElement( XML_cfRule );
1328 XclExpIconSet::XclExpIconSet( const XclExpRoot& rRoot, const ScIconSetFormat& rFormat, sal_Int32 nPriority ):
1329 XclExpRecord(),
1330 XclExpRoot( rRoot ),
1331 mrFormat( rFormat ),
1332 mnPriority( nPriority )
1334 const ScRange* pRange = rFormat.GetRange().front();
1335 ScAddress aAddr = pRange->aStart;
1336 for(ScIconSetFormat::const_iterator itr = rFormat.begin();
1337 itr != rFormat.end(); ++itr)
1339 // exact position is not important, we allow only absolute refs
1341 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1342 maCfvoList.AppendRecord( xCfvo );
1346 namespace {
1348 const char* getIconSetName( ScIconSetType eType )
1350 ScIconSetMap* pMap = ScIconSetFormat::getIconSetMap();
1351 for(; pMap->pName; ++pMap)
1353 if(pMap->eType == eType)
1354 return pMap->pName;
1357 return "";
1362 void XclExpIconSet::SaveXml( XclExpXmlStream& rStrm )
1364 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1366 rWorksheet->startElement( XML_cfRule,
1367 XML_type, "iconSet",
1368 XML_priority, OString::valueOf( mnPriority + 1 ).getStr(),
1369 FSEND );
1371 const char* pIconSetName = getIconSetName(mrFormat.GetIconSetData()->eIconSetType);
1372 rWorksheet->startElement( XML_iconSet,
1373 XML_iconSet, pIconSetName,
1374 XML_showValue, mrFormat.GetIconSetData()->mbShowValue ? NULL : "0",
1375 XML_reverse, mrFormat.GetIconSetData()->mbReverse ? "1" : NULL,
1376 FSEND );
1378 maCfvoList.SaveXml( rStrm );
1380 rWorksheet->endElement( XML_iconSet );
1381 rWorksheet->endElement( XML_cfRule );
1384 // ----------------------------------------------------------------------------
1386 XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot& rRoot, XclExtLstRef xExtLst ) :
1387 XclExpRoot( rRoot )
1389 if( const ScConditionalFormatList* pCondFmtList = GetDoc().GetCondFormList(GetCurrScTab()) )
1391 sal_Int32 nIndex = 0;
1392 for( ScConditionalFormatList::const_iterator itr = pCondFmtList->begin();
1393 itr != pCondFmtList->end(); ++itr)
1395 XclExpCondfmtList::RecordRefType xCondfmtRec( new XclExpCondfmt( GetRoot(), *itr, xExtLst, nIndex ));
1396 if( xCondfmtRec->IsValid() )
1397 maCondfmtList.AppendRecord( xCondfmtRec );
1402 void XclExpCondFormatBuffer::Save( XclExpStream& rStrm )
1404 maCondfmtList.Save( rStrm );
1407 void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream& rStrm )
1409 maCondfmtList.SaveXml( rStrm );
1412 // Validation =================================================================
1414 namespace {
1416 /** Writes a formula for the DV record. */
1417 void lclWriteDvFormula( XclExpStream& rStrm, const XclTokenArray* pXclTokArr )
1419 sal_uInt16 nFmlaSize = pXclTokArr ? pXclTokArr->GetSize() : 0;
1420 rStrm << nFmlaSize << sal_uInt16( 0 );
1421 if( pXclTokArr )
1422 pXclTokArr->WriteArray( rStrm );
1425 /** Writes a formula for the DV record, based on a single string. */
1426 void lclWriteDvFormula( XclExpStream& rStrm, const XclExpString& rString )
1428 // fake a formula with a single tStr token
1429 rStrm << static_cast< sal_uInt16 >( rString.GetSize() + 1 )
1430 << sal_uInt16( 0 )
1431 << EXC_TOKID_STR
1432 << rString;
1435 const char* lcl_GetValidationType( sal_uInt32 nFlags )
1437 switch( nFlags & EXC_DV_MODE_MASK )
1439 case EXC_DV_MODE_ANY: return "none";
1440 case EXC_DV_MODE_WHOLE: return "whole";
1441 case EXC_DV_MODE_DECIMAL: return "decimal";
1442 case EXC_DV_MODE_LIST: return "list";
1443 case EXC_DV_MODE_DATE: return "date";
1444 case EXC_DV_MODE_TIME: return "time";
1445 case EXC_DV_MODE_TEXTLEN: return "textLength";
1446 case EXC_DV_MODE_CUSTOM: return "custom";
1448 return NULL;
1451 const char* lcl_GetOperatorType( sal_uInt32 nFlags )
1453 switch( nFlags & EXC_DV_COND_MASK )
1455 case EXC_DV_COND_BETWEEN: return "between";
1456 case EXC_DV_COND_NOTBETWEEN: return "notBetween";
1457 case EXC_DV_COND_EQUAL: return "equal";
1458 case EXC_DV_COND_NOTEQUAL: return "notEqual";
1459 case EXC_DV_COND_GREATER: return "greaterThan";
1460 case EXC_DV_COND_LESS: return "lessThan";
1461 case EXC_DV_COND_EQGREATER: return "greaterThanOrEqual";
1462 case EXC_DV_COND_EQLESS: return "lessThanOrEqual";
1464 return NULL;
1467 } // namespace
1469 // ----------------------------------------------------------------------------
1471 XclExpDV::XclExpDV( const XclExpRoot& rRoot, sal_uLong nScHandle ) :
1472 XclExpRecord( EXC_ID_DV ),
1473 XclExpRoot( rRoot ),
1474 mnFlags( 0 ),
1475 mnScHandle( nScHandle )
1477 if( const ScValidationData* pValData = GetDoc().GetValidationEntry( mnScHandle ) )
1479 // prompt box - empty string represented by single NUL character
1480 String aTitle, aText;
1481 bool bShowPrompt = (pValData->GetInput( aTitle, aText ) == sal_True);
1482 if( aTitle.Len() )
1483 maPromptTitle.Assign( aTitle );
1484 else
1485 maPromptTitle.Assign( '\0' );
1486 if( aText.Len() )
1487 maPromptText.Assign( aText );
1488 else
1489 maPromptText.Assign( '\0' );
1491 // error box - empty string represented by single NUL character
1492 ScValidErrorStyle eScErrorStyle;
1493 bool bShowError = (pValData->GetErrMsg( aTitle, aText, eScErrorStyle ) == sal_True);
1494 if( aTitle.Len() )
1495 maErrorTitle.Assign( aTitle );
1496 else
1497 maErrorTitle.Assign( '\0' );
1498 if( aText.Len() )
1499 maErrorText.Assign( aText );
1500 else
1501 maErrorText.Assign( '\0' );
1503 // flags
1504 switch( pValData->GetDataMode() )
1506 case SC_VALID_ANY: mnFlags |= EXC_DV_MODE_ANY; break;
1507 case SC_VALID_WHOLE: mnFlags |= EXC_DV_MODE_WHOLE; break;
1508 case SC_VALID_DECIMAL: mnFlags |= EXC_DV_MODE_DECIMAL; break;
1509 case SC_VALID_LIST: mnFlags |= EXC_DV_MODE_LIST; break;
1510 case SC_VALID_DATE: mnFlags |= EXC_DV_MODE_DATE; break;
1511 case SC_VALID_TIME: mnFlags |= EXC_DV_MODE_TIME; break;
1512 case SC_VALID_TEXTLEN: mnFlags |= EXC_DV_MODE_TEXTLEN; break;
1513 case SC_VALID_CUSTOM: mnFlags |= EXC_DV_MODE_CUSTOM; break;
1514 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown mode" );
1517 switch( pValData->GetOperation() )
1519 case SC_COND_NONE:
1520 case SC_COND_EQUAL: mnFlags |= EXC_DV_COND_EQUAL; break;
1521 case SC_COND_LESS: mnFlags |= EXC_DV_COND_LESS; break;
1522 case SC_COND_GREATER: mnFlags |= EXC_DV_COND_GREATER; break;
1523 case SC_COND_EQLESS: mnFlags |= EXC_DV_COND_EQLESS; break;
1524 case SC_COND_EQGREATER: mnFlags |= EXC_DV_COND_EQGREATER; break;
1525 case SC_COND_NOTEQUAL: mnFlags |= EXC_DV_COND_NOTEQUAL; break;
1526 case SC_COND_BETWEEN: mnFlags |= EXC_DV_COND_BETWEEN; break;
1527 case SC_COND_NOTBETWEEN: mnFlags |= EXC_DV_COND_NOTBETWEEN; break;
1528 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown condition" );
1530 switch( eScErrorStyle )
1532 case SC_VALERR_STOP: mnFlags |= EXC_DV_ERROR_STOP; break;
1533 case SC_VALERR_WARNING: mnFlags |= EXC_DV_ERROR_WARNING; break;
1534 case SC_VALERR_INFO: mnFlags |= EXC_DV_ERROR_INFO; break;
1535 case SC_VALERR_MACRO:
1536 // set INFO for validity with macro call, delete title
1537 mnFlags |= EXC_DV_ERROR_INFO;
1538 maErrorTitle.Assign( '\0' ); // contains macro name
1539 break;
1540 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown error style" );
1542 ::set_flag( mnFlags, EXC_DV_IGNOREBLANK, pValData->IsIgnoreBlank() );
1543 ::set_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN, pValData->GetListType() == ValidListType::INVISIBLE );
1544 ::set_flag( mnFlags, EXC_DV_SHOWPROMPT, bShowPrompt );
1545 ::set_flag( mnFlags, EXC_DV_SHOWERROR, bShowError );
1547 // formulas
1548 XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
1549 boost::scoped_ptr< ScTokenArray > xScTokArr;
1551 // first formula
1552 xScTokArr.reset( pValData->CreateTokenArry( 0 ) );
1553 if( xScTokArr.get() )
1555 if( pValData->GetDataMode() == SC_VALID_LIST )
1557 String aString;
1558 if( XclTokenArrayHelper::GetStringList( aString, *xScTokArr, '\n' ) )
1560 OUStringBuffer sFormulaBuf;
1561 sFormulaBuf.append( (sal_Unicode) '"' );
1562 /* Formula is a list of string tokens -> build the Excel string.
1563 Data validity is BIFF8 only (important for the XclExpString object).
1564 Excel uses the NUL character as string list separator. */
1565 mxString1.reset( new XclExpString( EXC_STR_8BITLENGTH ) );
1566 xub_StrLen nTokenCnt = comphelper::string::getTokenCount(aString, '\n');
1567 sal_Int32 nStringIx = 0;
1568 for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
1570 String aToken( aString.GetToken( 0, '\n', nStringIx ) );
1571 if( nToken > 0 )
1573 mxString1->Append(OUString(static_cast<sal_Unicode>('\0')));
1574 sFormulaBuf.append( (sal_Unicode) ',' );
1576 mxString1->Append( aToken );
1577 sFormulaBuf.append( XclXmlUtils::ToOUString( aToken ) );
1579 ::set_flag( mnFlags, EXC_DV_STRINGLIST );
1581 sFormulaBuf.append( (sal_Unicode) '"' );
1582 msFormula1 = sFormulaBuf.makeStringAndClear();
1584 else
1586 /* All other formulas in validation are stored like conditional
1587 formatting formulas (with tRefN/tAreaN tokens as value or
1588 array class). But NOT the cell references and defined names
1589 in list validation - they are stored as reference class
1590 tokens... Example:
1591 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
1592 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
1593 Formula compiler supports this by offering two different functions
1594 CreateDataValFormula() and CreateListValFormula(). */
1595 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_LISTVAL, *xScTokArr );
1596 msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1597 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1600 else
1602 // no list validation -> convert the formula
1603 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1604 msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1605 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1609 // second formula
1610 xScTokArr.reset( pValData->CreateTokenArry( 1 ) );
1611 if( xScTokArr.get() )
1613 mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1614 msFormula2 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(),
1615 xScTokArr.get(), GetRoot().GetOpCodeMap() );
1618 else
1620 OSL_FAIL( "XclExpDV::XclExpDV - missing core data" );
1621 mnScHandle = ULONG_MAX;
1625 XclExpDV::~XclExpDV()
1629 void XclExpDV::InsertCellRange( const ScRange& rRange )
1631 maScRanges.Join( rRange );
1634 bool XclExpDV::Finalize()
1636 GetAddressConverter().ConvertRangeList( maXclRanges, maScRanges, true );
1637 return (mnScHandle != ULONG_MAX) && !maXclRanges.empty();
1640 void XclExpDV::WriteBody( XclExpStream& rStrm )
1642 // flags and strings
1643 rStrm << mnFlags << maPromptTitle << maErrorTitle << maPromptText << maErrorText;
1644 // condition formulas
1645 if( mxString1.get() )
1646 lclWriteDvFormula( rStrm, *mxString1 );
1647 else
1648 lclWriteDvFormula( rStrm, mxTokArr1.get() );
1649 lclWriteDvFormula( rStrm, mxTokArr2.get() );
1650 // cell ranges
1651 rStrm << maXclRanges;
1654 void XclExpDV::SaveXml( XclExpXmlStream& rStrm )
1656 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1657 rWorksheet->startElement( XML_dataValidation,
1658 XML_allowBlank, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_IGNOREBLANK ) ),
1659 XML_error, XESTRING_TO_PSZ( maErrorText ),
1660 // OOXTODO: XML_errorStyle,
1661 XML_errorTitle, XESTRING_TO_PSZ( maErrorTitle ),
1662 // OOXTODO: XML_imeMode,
1663 XML_operator, lcl_GetOperatorType( mnFlags ),
1664 XML_prompt, XESTRING_TO_PSZ( maPromptText ),
1665 XML_promptTitle, XESTRING_TO_PSZ( maPromptTitle ),
1666 // showDropDown should have been showNoDropDown - check oox/xlsx import for details
1667 XML_showDropDown, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN ) ),
1668 XML_showErrorMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWERROR ) ),
1669 XML_showInputMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWPROMPT ) ),
1670 XML_sqref, XclXmlUtils::ToOString( maScRanges ).getStr(),
1671 XML_type, lcl_GetValidationType( mnFlags ),
1672 FSEND );
1673 if( !msFormula1.isEmpty() )
1675 rWorksheet->startElement( XML_formula1, FSEND );
1676 rWorksheet->writeEscaped( msFormula1 );
1677 rWorksheet->endElement( XML_formula1 );
1679 if( !msFormula2.isEmpty() )
1681 rWorksheet->startElement( XML_formula2, FSEND );
1682 rWorksheet->writeEscaped( msFormula2 );
1683 rWorksheet->endElement( XML_formula2 );
1685 rWorksheet->endElement( XML_dataValidation );
1688 // ----------------------------------------------------------------------------
1690 XclExpDval::XclExpDval( const XclExpRoot& rRoot ) :
1691 XclExpRecord( EXC_ID_DVAL, 18 ),
1692 XclExpRoot( rRoot )
1696 XclExpDval::~XclExpDval()
1700 void XclExpDval::InsertCellRange( const ScRange& rRange, sal_uLong nScHandle )
1702 if( GetBiff() == EXC_BIFF8 )
1704 XclExpDV& rDVRec = SearchOrCreateDv( nScHandle );
1705 rDVRec.InsertCellRange( rRange );
1709 void XclExpDval::Save( XclExpStream& rStrm )
1711 // check all records
1712 size_t nPos = maDVList.GetSize();
1713 while( nPos )
1715 --nPos; // backwards to keep nPos valid
1716 XclExpDVRef xDVRec = maDVList.GetRecord( nPos );
1717 if( !xDVRec->Finalize() )
1718 maDVList.RemoveRecord( nPos );
1721 // write the DVAL and the DV's
1722 if( !maDVList.IsEmpty() )
1724 XclExpRecord::Save( rStrm );
1725 maDVList.Save( rStrm );
1729 void XclExpDval::SaveXml( XclExpXmlStream& rStrm )
1731 if( maDVList.IsEmpty() )
1732 return;
1734 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1735 rWorksheet->startElement( XML_dataValidations,
1736 XML_count, OString::valueOf( (sal_Int32) maDVList.GetSize() ).getStr(),
1737 // OOXTODO: XML_disablePrompts,
1738 // OOXTODO: XML_xWindow,
1739 // OOXTODO: XML_yWindow,
1740 FSEND );
1741 maDVList.SaveXml( rStrm );
1742 rWorksheet->endElement( XML_dataValidations );
1745 XclExpDV& XclExpDval::SearchOrCreateDv( sal_uLong nScHandle )
1747 // test last found record
1748 if( mxLastFoundDV.get() && (mxLastFoundDV->GetScHandle() == nScHandle) )
1749 return *mxLastFoundDV;
1751 // binary search
1752 size_t nCurrPos = 0;
1753 if( !maDVList.IsEmpty() )
1755 size_t nFirstPos = 0;
1756 size_t nLastPos = maDVList.GetSize() - 1;
1757 bool bLoop = true;
1758 sal_uLong nCurrScHandle = ::std::numeric_limits< sal_uLong >::max();
1759 while( (nFirstPos <= nLastPos) && bLoop )
1761 nCurrPos = (nFirstPos + nLastPos) / 2;
1762 mxLastFoundDV = maDVList.GetRecord( nCurrPos );
1763 nCurrScHandle = mxLastFoundDV->GetScHandle();
1764 if( nCurrScHandle == nScHandle )
1765 bLoop = false;
1766 else if( nCurrScHandle < nScHandle )
1767 nFirstPos = nCurrPos + 1;
1768 else if( nCurrPos )
1769 nLastPos = nCurrPos - 1;
1770 else // special case for nLastPos = -1
1771 bLoop = false;
1773 if( nCurrScHandle == nScHandle )
1774 return *mxLastFoundDV;
1775 else if( nCurrScHandle < nScHandle )
1776 ++nCurrPos;
1779 // create new DV record
1780 mxLastFoundDV.reset( new XclExpDV( *this, nScHandle ) );
1781 maDVList.InsertRecord( mxLastFoundDV, nCurrPos );
1782 return *mxLastFoundDV;
1785 void XclExpDval::WriteBody( XclExpStream& rStrm )
1787 rStrm.WriteZeroBytes( 10 );
1788 rStrm << EXC_DVAL_NOOBJ << static_cast< sal_uInt32 >( maDVList.GetSize() );
1791 // Web Queries ================================================================
1793 XclExpWebQuery::XclExpWebQuery(
1794 const String& rRangeName,
1795 const String& rUrl,
1796 const String& rSource,
1797 sal_Int32 nRefrSecs ) :
1798 maDestRange( rRangeName ),
1799 maUrl( rUrl ),
1800 // refresh delay time: seconds -> minutes
1801 mnRefresh( ulimit_cast< sal_Int16 >( (nRefrSecs + 59L) / 60L ) ),
1802 mbEntireDoc( false )
1804 // comma separated list of HTML table names or indexes
1805 xub_StrLen nTokenCnt = comphelper::string::getTokenCount(rSource, ';');
1806 String aNewTables;
1807 OUString aAppendTable;
1808 sal_Int32 nStringIx = 0;
1809 bool bExitLoop = false;
1810 for( xub_StrLen nToken = 0; (nToken < nTokenCnt) && !bExitLoop; ++nToken )
1812 OUString aToken( rSource.GetToken( 0, ';', nStringIx ) );
1813 mbEntireDoc = ScfTools::IsHTMLDocName( aToken );
1814 bExitLoop = mbEntireDoc || ScfTools::IsHTMLTablesName( aToken );
1815 if( !bExitLoop && ScfTools::GetHTMLNameFromName( aToken, aAppendTable ) )
1816 aNewTables = ScGlobal::addToken( aNewTables, aAppendTable, ',' );
1819 if( !bExitLoop ) // neither HTML_all nor HTML_tables found
1821 if( aNewTables.Len() )
1822 mxQryTables.reset( new XclExpString( aNewTables ) );
1823 else
1824 mbEntireDoc = true;
1828 XclExpWebQuery::~XclExpWebQuery()
1832 void XclExpWebQuery::Save( XclExpStream& rStrm )
1834 OSL_ENSURE( !mbEntireDoc || !mxQryTables.get(), "XclExpWebQuery::Save - illegal mode" );
1835 sal_uInt16 nFlags;
1837 // QSI record
1838 rStrm.StartRecord( EXC_ID_QSI, 10 + maDestRange.GetSize() );
1839 rStrm << EXC_QSI_DEFAULTFLAGS
1840 << sal_uInt16( 0x0010 )
1841 << sal_uInt16( 0x0012 )
1842 << sal_uInt32( 0x00000000 )
1843 << maDestRange;
1844 rStrm.EndRecord();
1846 // PARAMQRY record
1847 nFlags = 0;
1848 ::insert_value( nFlags, EXC_PQRYTYPE_WEBQUERY, 0, 3 );
1849 ::set_flag( nFlags, EXC_PQRY_WEBQUERY );
1850 ::set_flag( nFlags, EXC_PQRY_TABLES, !mbEntireDoc );
1851 rStrm.StartRecord( EXC_ID_PQRY, 12 );
1852 rStrm << nFlags
1853 << sal_uInt16( 0x0000 )
1854 << sal_uInt16( 0x0001 );
1855 rStrm.WriteZeroBytes( 6 );
1856 rStrm.EndRecord();
1858 // WQSTRING record
1859 rStrm.StartRecord( EXC_ID_WQSTRING, maUrl.GetSize() );
1860 rStrm << maUrl;
1861 rStrm.EndRecord();
1863 // unknown record 0x0802
1864 rStrm.StartRecord( EXC_ID_0802, 16 + maDestRange.GetSize() );
1865 rStrm << EXC_ID_0802; // repeated record id ?!?
1866 rStrm.WriteZeroBytes( 6 );
1867 rStrm << sal_uInt16( 0x0003 )
1868 << sal_uInt32( 0x00000000 )
1869 << sal_uInt16( 0x0010 )
1870 << maDestRange;
1871 rStrm.EndRecord();
1873 // WEBQRYSETTINGS record
1874 nFlags = mxQryTables.get() ? EXC_WQSETT_SPECTABLES : EXC_WQSETT_ALL;
1875 rStrm.StartRecord( EXC_ID_WQSETT, 28 );
1876 rStrm << EXC_ID_WQSETT // repeated record id ?!?
1877 << sal_uInt16( 0x0000 )
1878 << sal_uInt16( 0x0004 )
1879 << sal_uInt16( 0x0000 )
1880 << EXC_WQSETT_DEFAULTFLAGS
1881 << nFlags;
1882 rStrm.WriteZeroBytes( 10 );
1883 rStrm << mnRefresh // refresh delay in minutes
1884 << EXC_WQSETT_FORMATFULL
1885 << sal_uInt16( 0x0000 );
1886 rStrm.EndRecord();
1888 // WEBQRYTABLES record
1889 if( mxQryTables.get() )
1891 rStrm.StartRecord( EXC_ID_WQTABLES, 4 + mxQryTables->GetSize() );
1892 rStrm << EXC_ID_WQTABLES // repeated record id ?!?
1893 << sal_uInt16( 0x0000 )
1894 << *mxQryTables; // comma separated list of source tables
1895 rStrm.EndRecord();
1899 // ----------------------------------------------------------------------------
1901 XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot& rRoot )
1903 SCTAB nScTab = rRoot.GetCurrScTab();
1904 SfxObjectShell* pShell = rRoot.GetDocShell();
1905 if( !pShell ) return;
1906 ScfPropertySet aModelProp( pShell->GetModel() );
1907 if( !aModelProp.Is() ) return;
1909 Reference< XAreaLinks > xAreaLinks;
1910 aModelProp.GetProperty( xAreaLinks, SC_UNO_AREALINKS );
1911 Reference< XIndexAccess > xLinksIA( xAreaLinks, UNO_QUERY );
1912 if( !xLinksIA.is() ) return;
1914 for( sal_Int32 nIndex = 0, nCount = xLinksIA->getCount(); nIndex < nCount; ++nIndex )
1916 Reference< XAreaLink > xAreaLink( xLinksIA->getByIndex( nIndex ), UNO_QUERY );
1917 if( xAreaLink.is() )
1919 CellRangeAddress aDestRange( xAreaLink->getDestArea() );
1920 if( static_cast< SCTAB >( aDestRange.Sheet ) == nScTab )
1922 ScfPropertySet aLinkProp( xAreaLink );
1923 OUString aFilter;
1924 if( aLinkProp.GetProperty( aFilter, SC_UNONAME_FILTER ) &&
1925 (aFilter == EXC_WEBQRY_FILTER) )
1927 // get properties
1928 OUString /*aFilterOpt,*/ aUrl;
1929 sal_Int32 nRefresh = 0;
1931 // aLinkProp.GetProperty( aFilterOpt, SC_UNONAME_FILTOPT );
1932 aLinkProp.GetProperty( aUrl, SC_UNONAME_LINKURL );
1933 aLinkProp.GetProperty( nRefresh, SC_UNONAME_REFDELAY );
1935 String aAbsDoc( ScGlobal::GetAbsDocName( aUrl, pShell ) );
1936 INetURLObject aUrlObj( aAbsDoc );
1937 String aWebQueryUrl( aUrlObj.getFSysPath( INetURLObject::FSYS_DOS ) );
1938 if( !aWebQueryUrl.Len() )
1939 aWebQueryUrl = aAbsDoc;
1941 // find range or create a new range
1942 String aRangeName;
1943 ScRange aScDestRange;
1944 ScUnoConversion::FillScRange( aScDestRange, aDestRange );
1945 if( const ScRangeData* pRangeData = rRoot.GetNamedRanges().findByRange( aScDestRange ) )
1947 aRangeName = pRangeData->GetName();
1949 else
1951 XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
1952 XclExpNameManager& rNameMgr = rRoot.GetNameManager();
1954 // create a new unique defined name containing the range
1955 XclTokenArrayRef xTokArr = rFmlaComp.CreateFormula( EXC_FMLATYPE_WQUERY, aScDestRange );
1956 sal_uInt16 nNameIdx = rNameMgr.InsertUniqueName( aUrlObj.getBase(), xTokArr, nScTab );
1957 aRangeName = rNameMgr.GetOrigName( nNameIdx );
1960 // create and store the web query record
1961 if( aRangeName.Len() )
1962 AppendNewRecord( new XclExpWebQuery(
1963 aRangeName, aWebQueryUrl, xAreaLink->getSourceArea(), nRefresh ) );
1970 // ============================================================================
1972 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */