fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xecontent.cxx
blobca05734ed370754289ecf63cb75eb2b55a084bdf
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 /** Implementation of the SST export.
81 @descr Stores all passed strings in a hash table and prevents repeated
82 insertion of equal strings. */
83 class XclExpSstImpl
85 public:
86 explicit XclExpSstImpl();
88 /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
89 sal_uInt32 Insert( XclExpStringRef xString );
91 /** Writes the complete SST and EXTSST records. */
92 void Save( XclExpStream& rStrm );
93 void SaveXml( XclExpXmlStream& rStrm );
95 private:
96 typedef ::std::list< XclExpStringRef > XclExpStringList;
97 typedef ::std::vector< XclExpHashEntry > XclExpHashVec;
98 typedef ::std::vector< XclExpHashVec > XclExpHashTab;
100 XclExpStringList maStringList; /// List of unique strings (in SST ID order).
101 XclExpHashTab maHashTab; /// Hashed table that manages string pointers.
102 sal_uInt32 mnTotal; /// Total count of strings (including doubles).
103 sal_uInt32 mnSize; /// Size of the SST (count of unique strings).
106 const sal_uInt32 EXC_SST_HASHTABLE_SIZE = 2048;
108 XclExpSstImpl::XclExpSstImpl() :
109 maHashTab( EXC_SST_HASHTABLE_SIZE ),
110 mnTotal( 0 ),
111 mnSize( 0 )
115 sal_uInt32 XclExpSstImpl::Insert( XclExpStringRef xString )
117 OSL_ENSURE( xString.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
118 if( !xString.get() )
119 xString.reset( new XclExpString );
121 ++mnTotal;
122 sal_uInt32 nSstIndex = 0;
124 // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
125 sal_uInt16 nHash = xString->GetHash();
126 (nHash ^= (nHash / EXC_SST_HASHTABLE_SIZE)) %= EXC_SST_HASHTABLE_SIZE;
128 XclExpHashVec& rVec = maHashTab[ nHash ];
129 XclExpHashEntry aEntry( xString.get(), mnSize );
130 XclExpHashVec::iterator aIt = ::std::lower_bound( rVec.begin(), rVec.end(), aEntry, XclExpHashEntrySWO() );
131 if( (aIt == rVec.end()) || (*aIt->mpString != *xString) )
133 nSstIndex = mnSize;
134 maStringList.push_back( xString );
135 rVec.insert( aIt, aEntry );
136 ++mnSize;
138 else
140 nSstIndex = aIt->mnSstIndex;
143 return nSstIndex;
146 void XclExpSstImpl::Save( XclExpStream& rStrm )
148 if( maStringList.empty() )
149 return;
151 SvMemoryStream aExtSst( 8192 );
153 sal_uInt32 nBucket = mnSize;
154 while( nBucket > 0x0100 )
155 nBucket /= 2;
157 sal_uInt16 nPerBucket = llimit_cast< sal_uInt16 >( nBucket, 8 );
158 sal_uInt16 nBucketIndex = 0;
160 // *** write the SST record ***
162 rStrm.StartRecord( EXC_ID_SST, 8 );
164 rStrm << mnTotal << mnSize;
165 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
167 if( !nBucketIndex )
169 // write bucket info before string to get correct record position
170 sal_uInt32 nStrmPos = static_cast< sal_uInt32 >( rStrm.GetSvStreamPos() );
171 sal_uInt16 nRecPos = rStrm.GetRawRecPos() + 4;
172 aExtSst.WriteUInt32( nStrmPos ) // stream position
173 .WriteUInt16( nRecPos ) // position from start of SST or CONTINUE
174 .WriteUInt16( 0 ); // reserved
177 rStrm << **aIt;
179 if( ++nBucketIndex == nPerBucket )
180 nBucketIndex = 0;
183 rStrm.EndRecord();
185 // *** write the EXTSST record ***
187 rStrm.StartRecord( EXC_ID_EXTSST, 0 );
189 rStrm << nPerBucket;
190 rStrm.SetSliceSize( 8 ); // size of one bucket info
191 aExtSst.Seek( STREAM_SEEK_TO_BEGIN );
192 rStrm.CopyFromStream( aExtSst );
194 rStrm.EndRecord();
197 void XclExpSstImpl::SaveXml( XclExpXmlStream& rStrm )
199 if( maStringList.empty() )
200 return;
202 sax_fastparser::FSHelperPtr pSst = rStrm.CreateOutputStream(
203 OUString( "xl/sharedStrings.xml"),
204 OUString( "sharedStrings.xml" ),
205 rStrm.GetCurrentStream()->getOutputStream(),
206 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
207 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
208 rStrm.PushStream( pSst );
210 pSst->startElement( XML_sst,
211 XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
212 XML_count, OString::number( mnTotal ).getStr(),
213 XML_uniqueCount, OString::number( mnSize ).getStr(),
214 FSEND );
216 for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
218 pSst->startElement( XML_si, FSEND );
219 (*aIt)->WriteXml( rStrm );
220 pSst->endElement( XML_si );
223 pSst->endElement( XML_sst );
225 rStrm.PopStream();
228 XclExpSst::XclExpSst() :
229 mxImpl( new XclExpSstImpl )
233 XclExpSst::~XclExpSst()
237 sal_uInt32 XclExpSst::Insert( XclExpStringRef xString )
239 return mxImpl->Insert( xString );
242 void XclExpSst::Save( XclExpStream& rStrm )
244 mxImpl->Save( rStrm );
247 void XclExpSst::SaveXml( XclExpXmlStream& rStrm )
249 mxImpl->SaveXml( rStrm );
252 // Merged cells ===============================================================
254 XclExpMergedcells::XclExpMergedcells( const XclExpRoot& rRoot ) :
255 XclExpRoot( rRoot )
259 void XclExpMergedcells::AppendRange( const ScRange& rRange, sal_uInt32 nBaseXFId )
261 if( GetBiff() == EXC_BIFF8 )
263 maMergedRanges.Append( rRange );
264 maBaseXFIds.push_back( nBaseXFId );
268 sal_uInt32 XclExpMergedcells::GetBaseXFId( const ScAddress& rPos ) const
270 OSL_ENSURE( maBaseXFIds.size() == maMergedRanges.size(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
271 ScfUInt32Vec::const_iterator aIt = maBaseXFIds.begin();
272 ScRangeList& rNCRanges = const_cast< ScRangeList& >( maMergedRanges );
273 for ( size_t i = 0, nRanges = rNCRanges.size(); i < nRanges; ++i, ++aIt )
275 const ScRange* pScRange = rNCRanges[ i ];
276 if( pScRange->In( rPos ) )
277 return *aIt;
279 return EXC_XFID_NOTFOUND;
282 void XclExpMergedcells::Save( XclExpStream& rStrm )
284 if( GetBiff() == EXC_BIFF8 )
286 XclRangeList aXclRanges;
287 GetAddressConverter().ConvertRangeList( aXclRanges, maMergedRanges, true );
288 size_t nFirstRange = 0;
289 size_t nRemainingRanges = aXclRanges.size();
290 while( nRemainingRanges > 0 )
292 size_t nRangeCount = ::std::min< size_t >( nRemainingRanges, EXC_MERGEDCELLS_MAXCOUNT );
293 rStrm.StartRecord( EXC_ID_MERGEDCELLS, 2 + 8 * nRangeCount );
294 aXclRanges.WriteSubList( rStrm, nFirstRange, nRangeCount );
295 rStrm.EndRecord();
296 nFirstRange += nRangeCount;
297 nRemainingRanges -= nRangeCount;
302 void XclExpMergedcells::SaveXml( XclExpXmlStream& rStrm )
304 size_t nCount = maMergedRanges.size();
305 if( !nCount )
306 return;
307 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
308 rWorksheet->startElement( XML_mergeCells,
309 XML_count, OString::number( nCount ).getStr(),
310 FSEND );
311 for( size_t i = 0; i < nCount; ++i )
313 if( const ScRange* pRange = maMergedRanges[ i ] )
315 rWorksheet->singleElement( XML_mergeCell,
316 XML_ref, XclXmlUtils::ToOString( *pRange ).getStr(),
317 FSEND );
320 rWorksheet->endElement( XML_mergeCells );
323 // Hyperlinks =================================================================
325 XclExpHyperlink::XclExpHyperlink( const XclExpRoot& rRoot, const SvxURLField& rUrlField, const ScAddress& rScPos ) :
326 XclExpRecord( EXC_ID_HLINK ),
327 maScPos( rScPos ),
328 mxVarData( new SvMemoryStream ),
329 mnFlags( 0 ),
330 mbSetDisplay( true )
332 const OUString& rUrl = rUrlField.GetURL();
333 const OUString& rRepr = rUrlField.GetRepresentation();
334 INetURLObject aUrlObj( rUrl );
335 const INetProtocol eProtocol = aUrlObj.GetProtocol();
336 bool bWithRepr = !rRepr.isEmpty();
337 XclExpStream aXclStrm( *mxVarData, rRoot ); // using in raw write mode.
339 // description
340 if( bWithRepr )
342 XclExpString aDescr( rRepr, EXC_STR_FORCEUNICODE, 255 );
343 aXclStrm << sal_uInt32( aDescr.Len() + 1 ); // string length + 1 trailing zero word
344 aDescr.WriteBuffer( aXclStrm ); // NO flags
345 aXclStrm << sal_uInt16( 0 );
347 mnFlags |= EXC_HLINK_DESCR;
348 m_Repr = rRepr;
351 // file link or URL
352 if( eProtocol == INetProtocol::File || eProtocol == INetProtocol::Smb )
354 sal_uInt16 nLevel;
355 bool bRel;
356 /* TODO: should we differentiate between BIFF and OOXML and write IURI
357 * encoded for OOXML? */
358 OUString aFileName( BuildFileName( nLevel, bRel, rUrl, rRoot, false ) );
360 if( eProtocol == INetProtocol::Smb )
362 // #n382718# (and #n261623#) Convert smb notation to '\\'
363 aFileName = aUrlObj.GetMainURL( INetURLObject::NO_DECODE );
364 aFileName = aFileName.copy(4); // skip the 'smb:' part
365 aFileName = aFileName.replace('/', '\\');
368 if( !bRel )
369 mnFlags |= EXC_HLINK_ABS;
370 mnFlags |= EXC_HLINK_BODY;
372 OString aAsciiLink(OUStringToOString(aFileName,
373 rRoot.GetTextEncoding()));
374 XclExpString aLink( aFileName, EXC_STR_FORCEUNICODE, 255 );
375 aXclStrm << XclTools::maGuidFileMoniker
376 << nLevel
377 << sal_uInt32( aAsciiLink.getLength() + 1 ); // string length + 1 trailing zero byte
378 aXclStrm.Write( aAsciiLink.getStr(), aAsciiLink.getLength() );
379 aXclStrm << sal_uInt8( 0 )
380 << sal_uInt32( 0xDEADFFFF );
381 aXclStrm.WriteZeroBytes( 20 );
382 aXclStrm << sal_uInt32( aLink.GetBufferSize() + 6 )
383 << sal_uInt32( aLink.GetBufferSize() ) // byte count, not string length
384 << sal_uInt16( 0x0003 );
385 aLink.WriteBuffer( aXclStrm ); // NO flags
387 if (m_Repr.isEmpty())
388 m_Repr = aFileName;
390 msTarget = XclXmlUtils::ToOUString( aLink );
391 // ooxml expects the file:/// part appended ( or at least
392 // ms2007 does, ms2010 is more tolerant )
393 msTarget = "file:///" + msTarget;
395 else if( eProtocol != INetProtocol::NotValid )
397 XclExpString aUrl( aUrlObj.GetURLNoMark(), EXC_STR_FORCEUNICODE, 255 );
398 aXclStrm << XclTools::maGuidUrlMoniker
399 << sal_uInt32( aUrl.GetBufferSize() + 2 ); // byte count + 1 trailing zero word
400 aUrl.WriteBuffer( aXclStrm ); // NO flags
401 aXclStrm << sal_uInt16( 0 );
403 mnFlags |= EXC_HLINK_BODY | EXC_HLINK_ABS;
404 if (m_Repr.isEmpty())
405 m_Repr = rUrl;
407 msTarget = XclXmlUtils::ToOUString( aUrl );
409 else if( !rUrl.isEmpty() && rUrl[0] == '#' ) // hack for #89066#
411 OUString aTextMark( rUrl.copy( 1 ) );
413 sal_Int32 nSepPos = aTextMark.indexOf( '.' );
414 if(nSepPos != -1)
416 aTextMark = aTextMark.replaceAt( nSepPos, 1, "!" );
417 OUString aSheetName( aTextMark.copy(0, nSepPos));
419 if ( aSheetName.indexOf(' ') != -1 && aSheetName[0] != '\'')
421 aTextMark = "'" + aTextMark.replaceAt(nSepPos, 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 OUString XclExpHyperlink::BuildFileName(
449 sal_uInt16& rnLevel, bool& rbRel, const OUString& rUrl, const XclExpRoot& rRoot, bool bEncoded )
451 INetURLObject aURLObject( rUrl );
452 OUString aDosName( bEncoded ? aURLObject.GetURLPath() : aURLObject.getFSysPath( INetURLObject::FSYS_DOS ) );
453 rnLevel = 0;
454 rbRel = rRoot.IsRelUrl();
456 if( rbRel )
458 // try to convert to relative file name
459 OUString aTmpName( aDosName );
460 aDosName = INetURLObject::GetRelURL( rRoot.GetBasePath(), rUrl,
461 INetURLObject::WAS_ENCODED,
462 (bEncoded ? INetURLObject::DECODE_TO_IURI : INetURLObject::DECODE_WITH_CHARSET));
464 if (aDosName.startsWith(INET_FILE_SCHEME))
466 // not converted to rel -> back to old, return absolute flag
467 aDosName = aTmpName;
468 rbRel = false;
470 else if (aDosName.startsWith("./"))
472 aDosName = aDosName.copy(2);
474 else
476 while (aDosName.startsWith("../"))
478 aDosName = aDosName.copy(3);
479 ++rnLevel;
483 return aDosName;
486 void XclExpHyperlink::WriteBody( XclExpStream& rStrm )
488 sal_uInt16 nXclCol = static_cast< sal_uInt16 >( maScPos.Col() );
489 sal_uInt16 nXclRow = static_cast< sal_uInt16 >( maScPos.Row() );
490 rStrm << nXclRow << nXclRow << nXclCol << nXclCol;
491 WriteEmbeddedData( rStrm );
494 void XclExpHyperlink::WriteEmbeddedData( XclExpStream& rStrm )
496 rStrm << XclTools::maGuidStdLink
497 << sal_uInt32( 2 )
498 << mnFlags;
500 mxVarData->Seek( STREAM_SEEK_TO_BEGIN );
501 rStrm.CopyFromStream( *mxVarData );
504 void XclExpHyperlink::SaveXml( XclExpXmlStream& rStrm )
506 OUString sId = !msTarget.isEmpty() ? rStrm.addRelation( rStrm.GetCurrentStream()->getOutputStream(),
507 XclXmlUtils::ToOUString( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ),
508 msTarget, true ) : OUString();
509 rStrm.GetCurrentStream()->singleElement( XML_hyperlink,
510 XML_ref, XclXmlUtils::ToOString( maScPos ).getStr(),
511 FSNS( XML_r, XML_id ), !sId.isEmpty()
512 ? XclXmlUtils::ToOString( sId ).getStr()
513 : NULL,
514 XML_location, mxTextMark.get() != NULL
515 ? XclXmlUtils::ToOString( *mxTextMark ).getStr()
516 : NULL,
517 // OOXTODO: XML_tooltip, from record HLinkTooltip 800h wzTooltip
518 XML_display, mbSetDisplay
519 ? XclXmlUtils::ToOString(m_Repr).getStr()
520 : NULL,
521 FSEND );
524 // Label ranges ===============================================================
526 XclExpLabelranges::XclExpLabelranges( const XclExpRoot& rRoot ) :
527 XclExpRoot( rRoot )
529 SCTAB nScTab = GetCurrScTab();
530 // row label ranges
531 FillRangeList( maRowRanges, rRoot.GetDoc().GetRowNameRangesRef(), nScTab );
532 // row labels only over 1 column (restriction of Excel97/2000/XP)
533 for ( size_t i = 0, nRanges = maRowRanges.size(); i < nRanges; ++i )
535 ScRange* pScRange = maRowRanges[ i ];
536 if( pScRange->aStart.Col() != pScRange->aEnd.Col() )
537 pScRange->aEnd.SetCol( pScRange->aStart.Col() );
539 // col label ranges
540 FillRangeList( maColRanges, rRoot.GetDoc().GetColNameRangesRef(), nScTab );
543 void XclExpLabelranges::FillRangeList( ScRangeList& rScRanges,
544 ScRangePairListRef xLabelRangesRef, SCTAB nScTab )
546 for ( size_t i = 0, nPairs = xLabelRangesRef->size(); i < nPairs; ++i )
548 ScRangePair* pRangePair = (*xLabelRangesRef)[i];
549 const ScRange& rScRange = pRangePair->GetRange( 0 );
550 if( rScRange.aStart.Tab() == nScTab )
551 rScRanges.Append( rScRange );
555 void XclExpLabelranges::Save( XclExpStream& rStrm )
557 XclExpAddressConverter& rAddrConv = GetAddressConverter();
558 XclRangeList aRowXclRanges, aColXclRanges;
559 rAddrConv.ConvertRangeList( aRowXclRanges, maRowRanges, false );
560 rAddrConv.ConvertRangeList( aColXclRanges, maColRanges, false );
561 if( !aRowXclRanges.empty() || !aColXclRanges.empty() )
563 rStrm.StartRecord( EXC_ID_LABELRANGES, 4 + 8 * (aRowXclRanges.size() + aColXclRanges.size()) );
564 rStrm << aRowXclRanges << aColXclRanges;
565 rStrm.EndRecord();
569 // Conditional formatting ====================================================
571 /** Represents a CF record that contains one condition of a conditional format. */
572 class XclExpCFImpl : protected XclExpRoot
574 public:
575 explicit XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority = 0 );
577 /** Writes the body of the CF record. */
578 void WriteBody( XclExpStream& rStrm );
579 void SaveXml( XclExpXmlStream& rStrm );
581 private:
582 const ScCondFormatEntry& mrFormatEntry; /// Calc conditional format entry.
583 XclFontData maFontData; /// Font formatting attributes.
584 XclExpCellBorder maBorder; /// Border formatting attributes.
585 XclExpCellArea maArea; /// Pattern formatting attributes.
586 XclTokenArrayRef mxTokArr1; /// Formula for first condition.
587 XclTokenArrayRef mxTokArr2; /// Formula for second condition.
588 sal_uInt32 mnFontColorId; /// Font color ID.
589 sal_uInt8 mnType; /// Type of the condition (cell/formula).
590 sal_uInt8 mnOperator; /// Comparison operator for cell type.
591 sal_Int32 mnPriority; /// Priority of this entry; needed for oox export
592 bool mbFontUsed; /// true = Any font attribute used.
593 bool mbHeightUsed; /// true = Font height used.
594 bool mbWeightUsed; /// true = Font weight used.
595 bool mbColorUsed; /// true = Font color used.
596 bool mbUnderlUsed; /// true = Font underline type used.
597 bool mbItalicUsed; /// true = Font posture used.
598 bool mbStrikeUsed; /// true = Font strikeout used.
599 bool mbBorderUsed; /// true = Border attribute used.
600 bool mbPattUsed; /// true = Pattern attribute used.
603 XclExpCFImpl::XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority ) :
604 XclExpRoot( rRoot ),
605 mrFormatEntry( rFormatEntry ),
606 mnFontColorId( 0 ),
607 mnType( EXC_CF_TYPE_CELL ),
608 mnOperator( EXC_CF_CMP_NONE ),
609 mnPriority( nPriority ),
610 mbFontUsed( false ),
611 mbHeightUsed( false ),
612 mbWeightUsed( false ),
613 mbColorUsed( false ),
614 mbUnderlUsed( false ),
615 mbItalicUsed( false ),
616 mbStrikeUsed( false ),
617 mbBorderUsed( false ),
618 mbPattUsed( false )
620 /* Get formatting attributes here, and not in WriteBody(). This is needed to
621 correctly insert all colors into the palette. */
623 if( SfxStyleSheetBase* pStyleSheet = GetDoc().GetStyleSheetPool()->Find( mrFormatEntry.GetStyle(), SFX_STYLE_FAMILY_PARA ) )
625 const SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
627 // font
628 mbHeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_HEIGHT, true );
629 mbWeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_WEIGHT, true );
630 mbColorUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_COLOR, true );
631 mbUnderlUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_UNDERLINE, true );
632 mbItalicUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_POSTURE, true );
633 mbStrikeUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_CROSSEDOUT, true );
634 mbFontUsed = mbHeightUsed || mbWeightUsed || mbColorUsed || mbUnderlUsed || mbItalicUsed || mbStrikeUsed;
635 if( mbFontUsed )
637 vcl::Font aFont;
638 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW );
639 maFontData.FillFromVclFont( aFont );
640 mnFontColorId = GetPalette().InsertColor( maFontData.maColor, EXC_COLOR_CELLTEXT );
643 // border
644 mbBorderUsed = ScfTools::CheckItem( rItemSet, ATTR_BORDER, true );
645 if( mbBorderUsed )
646 maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
648 // pattern
649 mbPattUsed = ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true );
650 if( mbPattUsed )
651 maArea.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
654 // *** mode and comparison operator ***
656 bool bFmla2 = false;
657 switch( rFormatEntry.GetOperation() )
659 case SC_COND_NONE: mnType = EXC_CF_TYPE_NONE; break;
660 case SC_COND_BETWEEN: mnOperator = EXC_CF_CMP_BETWEEN; bFmla2 = true; break;
661 case SC_COND_NOTBETWEEN: mnOperator = EXC_CF_CMP_NOT_BETWEEN; bFmla2 = true; break;
662 case SC_COND_EQUAL: mnOperator = EXC_CF_CMP_EQUAL; break;
663 case SC_COND_NOTEQUAL: mnOperator = EXC_CF_CMP_NOT_EQUAL; break;
664 case SC_COND_GREATER: mnOperator = EXC_CF_CMP_GREATER; break;
665 case SC_COND_LESS: mnOperator = EXC_CF_CMP_LESS; break;
666 case SC_COND_EQGREATER: mnOperator = EXC_CF_CMP_GREATER_EQUAL; break;
667 case SC_COND_EQLESS: mnOperator = EXC_CF_CMP_LESS_EQUAL; break;
668 case SC_COND_DIRECT: mnType = EXC_CF_TYPE_FMLA; break;
669 default: mnType = EXC_CF_TYPE_NONE;
670 OSL_FAIL( "XclExpCF::WriteBody - unknown condition type" );
673 // *** formulas ***
675 XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
677 boost::scoped_ptr< ScTokenArray > xScTokArr( mrFormatEntry.CreateTokenArry( 0 ) );
678 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
680 if( bFmla2 )
682 xScTokArr.reset( mrFormatEntry.CreateTokenArry( 1 ) );
683 mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
687 void XclExpCFImpl::WriteBody( XclExpStream& rStrm )
689 // *** mode and comparison operator ***
691 rStrm << mnType << mnOperator;
693 // *** formula sizes ***
695 sal_uInt16 nFmlaSize1 = mxTokArr1.get() ? mxTokArr1->GetSize() : 0;
696 sal_uInt16 nFmlaSize2 = mxTokArr2.get() ? mxTokArr2->GetSize() : 0;
697 rStrm << nFmlaSize1 << nFmlaSize2;
699 // *** formatting blocks ***
701 if( mbFontUsed || mbBorderUsed || mbPattUsed )
703 sal_uInt32 nFlags = EXC_CF_ALLDEFAULT;
705 ::set_flag( nFlags, EXC_CF_BLOCK_FONT, mbFontUsed );
706 ::set_flag( nFlags, EXC_CF_BLOCK_BORDER, mbBorderUsed );
707 ::set_flag( nFlags, EXC_CF_BLOCK_AREA, mbPattUsed );
709 // attributes used -> set flags to 0.
710 ::set_flag( nFlags, EXC_CF_BORDER_ALL, !mbBorderUsed );
711 ::set_flag( nFlags, EXC_CF_AREA_ALL, !mbPattUsed );
713 rStrm << nFlags << sal_uInt16( 0 );
715 if( mbFontUsed )
717 // font height, 0xFFFFFFFF indicates unused
718 sal_uInt32 nHeight = mbHeightUsed ? maFontData.mnHeight : 0xFFFFFFFF;
719 // font style: italic and strikeout
720 sal_uInt32 nStyle = 0;
721 ::set_flag( nStyle, EXC_CF_FONT_STYLE, maFontData.mbItalic );
722 ::set_flag( nStyle, EXC_CF_FONT_STRIKEOUT, maFontData.mbStrikeout );
723 // font color, 0xFFFFFFFF indicates unused
724 sal_uInt32 nColor = mbColorUsed ? GetPalette().GetColorIndex( mnFontColorId ) : 0xFFFFFFFF;
725 // font used flags for italic, weight, and strikeout -> 0 = used, 1 = default
726 sal_uInt32 nFontFlags1 = EXC_CF_FONT_ALLDEFAULT;
727 ::set_flag( nFontFlags1, EXC_CF_FONT_STYLE, !(mbItalicUsed || mbWeightUsed) );
728 ::set_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT, !mbStrikeUsed );
729 // font used flag for underline -> 0 = used, 1 = default
730 sal_uInt32 nFontFlags3 = mbUnderlUsed ? 0 : EXC_CF_FONT_UNDERL;
732 rStrm.WriteZeroBytesToRecord( 64 );
733 rStrm << nHeight
734 << nStyle
735 << maFontData.mnWeight
736 << EXC_FONTESC_NONE
737 << maFontData.mnUnderline;
738 rStrm.WriteZeroBytesToRecord( 3 );
739 rStrm << nColor
740 << sal_uInt32( 0 )
741 << nFontFlags1
742 << EXC_CF_FONT_ESCAPEM // escapement never used -> set the flag
743 << nFontFlags3;
744 rStrm.WriteZeroBytesToRecord( 16 );
745 rStrm << sal_uInt16( 1 ); // must be 1
748 if( mbBorderUsed )
750 sal_uInt16 nLineStyle = 0;
751 sal_uInt32 nLineColor = 0;
752 maBorder.SetFinalColors( GetPalette() );
753 maBorder.FillToCF8( nLineStyle, nLineColor );
754 rStrm << nLineStyle << nLineColor << sal_uInt16( 0 );
757 if( mbPattUsed )
759 sal_uInt16 nPattern = 0, nColor = 0;
760 maArea.SetFinalColors( GetPalette() );
761 maArea.FillToCF8( nPattern, nColor );
762 rStrm << nPattern << nColor;
765 else
767 // no data blocks at all
768 rStrm << sal_uInt32( 0 ) << sal_uInt16( 0 );
771 // *** formulas ***
773 if( mxTokArr1.get() )
774 mxTokArr1->WriteArray( rStrm );
775 if( mxTokArr2.get() )
776 mxTokArr2->WriteArray( rStrm );
779 namespace {
781 const char* GetOperatorString(ScConditionMode eMode, bool& bFrmla2)
783 const char *pRet = NULL;
784 switch(eMode)
786 case SC_COND_EQUAL:
787 pRet = "equal";
788 break;
789 case SC_COND_LESS:
790 pRet = "lessThan";
791 break;
792 case SC_COND_GREATER:
793 pRet = "greaterThan";
794 break;
795 case SC_COND_EQLESS:
796 pRet = "lessThanOrEqual";
797 break;
798 case SC_COND_EQGREATER:
799 pRet = "greaterThanOrEqual";
800 break;
801 case SC_COND_NOTEQUAL:
802 pRet = "notEqual";
803 break;
804 case SC_COND_BETWEEN:
805 bFrmla2 = true;
806 pRet = "between";
807 break;
808 case SC_COND_NOTBETWEEN:
809 bFrmla2 = true;
810 pRet = "notBetween";
811 break;
812 case SC_COND_DUPLICATE:
813 pRet = NULL;
814 break;
815 case SC_COND_NOTDUPLICATE:
816 pRet = NULL;
817 break;
818 case SC_COND_DIRECT:
819 break;
820 case SC_COND_NONE:
821 default:
822 break;
824 return pRet;
827 const char* GetTypeString(ScConditionMode eMode)
829 switch(eMode)
831 case SC_COND_DIRECT:
832 return "expression";
833 case SC_COND_TOP10:
834 case SC_COND_TOP_PERCENT:
835 case SC_COND_BOTTOM10:
836 case SC_COND_BOTTOM_PERCENT:
837 return "top10";
838 case SC_COND_ABOVE_AVERAGE:
839 case SC_COND_BELOW_AVERAGE:
840 case SC_COND_ABOVE_EQUAL_AVERAGE:
841 case SC_COND_BELOW_EQUAL_AVERAGE:
842 return "aboveAverage";
843 case SC_COND_NOTDUPLICATE:
844 return "uniqueValues";
845 case SC_COND_DUPLICATE:
846 return "duplicateValues";
847 case SC_COND_ERROR:
848 return "containsErrors";
849 case SC_COND_NOERROR:
850 return "notContainsErrors";
851 case SC_COND_BEGINS_WITH:
852 return "beginsWith";
853 case SC_COND_ENDS_WITH:
854 return "endsWith";
855 case SC_COND_CONTAINS_TEXT:
856 return "containsText";
857 case SC_COND_NOT_CONTAINS_TEXT:
858 return "notContainsText";
859 default:
860 return "cellIs";
864 bool IsTopBottomRule(ScConditionMode eMode)
866 switch(eMode)
868 case SC_COND_TOP10:
869 case SC_COND_BOTTOM10:
870 case SC_COND_TOP_PERCENT:
871 case SC_COND_BOTTOM_PERCENT:
872 return true;
873 default:
874 break;
877 return false;
880 bool IsTextRule(ScConditionMode eMode)
882 switch(eMode)
884 case SC_COND_BEGINS_WITH:
885 case SC_COND_ENDS_WITH:
886 case SC_COND_CONTAINS_TEXT:
887 case SC_COND_NOT_CONTAINS_TEXT:
888 return true;
889 default:
890 break;
893 return false;
898 void XclExpCFImpl::SaveXml( XclExpXmlStream& rStrm )
900 bool bFmla2 = false;
901 ScConditionMode eOperation = mrFormatEntry.GetOperation();
902 bool nAboveAverage = eOperation == SC_COND_ABOVE_AVERAGE ||
903 eOperation == SC_COND_ABOVE_EQUAL_AVERAGE;
904 bool nEqualAverage = eOperation == SC_COND_ABOVE_EQUAL_AVERAGE ||
905 eOperation == SC_COND_BELOW_EQUAL_AVERAGE;
906 bool nBottom = eOperation == SC_COND_BOTTOM10
907 || eOperation == SC_COND_BOTTOM_PERCENT;
908 bool nPercent = eOperation == SC_COND_TOP_PERCENT ||
909 eOperation == SC_COND_BOTTOM_PERCENT;
910 OString aRank("0");
911 if(IsTopBottomRule(eOperation))
913 // position and formula grammar are not important
914 // we only store a number there
915 aRank = XclXmlUtils::ToOString(mrFormatEntry.GetExpression(ScAddress(0,0,0), 0));
917 OString aText;
918 if(IsTextRule(eOperation))
920 // we need to write the text without quotes
921 // we have to actually get the string from
922 // the token array for that
923 boost::scoped_ptr<ScTokenArray> pTokenArray(mrFormatEntry.CreateTokenArry(0));
924 if(pTokenArray->GetLen())
925 aText = XclXmlUtils::ToOString(pTokenArray->First()->GetString().getString());
928 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
929 rWorksheet->startElement( XML_cfRule,
930 XML_type, GetTypeString( mrFormatEntry.GetOperation() ),
931 XML_priority, OString::number( mnPriority + 1 ).getStr(),
932 XML_operator, GetOperatorString( mrFormatEntry.GetOperation(), bFmla2 ),
933 XML_aboveAverage, OString::number( int(nAboveAverage) ).getStr(),
934 XML_equalAverage, OString::number( int(nEqualAverage) ).getStr(),
935 XML_bottom, OString::number( int(nBottom) ).getStr(),
936 XML_percent, OString::number( int(nPercent) ).getStr(),
937 XML_rank, aRank.getStr(),
938 XML_text, aText.getStr(),
939 XML_dxfId, OString::number( GetDxfs().GetDxfId( mrFormatEntry.GetStyle() ) ).getStr(),
940 FSEND );
941 if(!IsTextRule(eOperation) && !IsTopBottomRule(eOperation))
943 rWorksheet->startElement( XML_formula, FSEND );
944 rWorksheet->writeEscaped(XclXmlUtils::ToOUString( GetCompileFormulaContext(), mrFormatEntry.GetValidSrcPos(),
945 mrFormatEntry.CreateTokenArry(0)));
946 rWorksheet->endElement( XML_formula );
947 if (bFmla2)
949 rWorksheet->startElement( XML_formula, FSEND );
950 rWorksheet->writeEscaped(XclXmlUtils::ToOUString( GetCompileFormulaContext(), mrFormatEntry.GetValidSrcPos(),
951 mrFormatEntry.CreateTokenArry(1)));
952 rWorksheet->endElement( XML_formula );
955 // OOXTODO: XML_extLst
956 rWorksheet->endElement( XML_cfRule );
959 XclExpCF::XclExpCF( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry, sal_Int32 nPriority = 0 ) :
960 XclExpRecord( EXC_ID_CF ),
961 XclExpRoot( rRoot ),
962 mxImpl( new XclExpCFImpl( rRoot, rFormatEntry, nPriority ) )
966 XclExpCF::~XclExpCF()
970 void XclExpCF::WriteBody( XclExpStream& rStrm )
972 mxImpl->WriteBody( rStrm );
975 void XclExpCF::SaveXml( XclExpXmlStream& rStrm )
977 mxImpl->SaveXml( rStrm );
980 XclExpDateFormat::XclExpDateFormat( const XclExpRoot& rRoot, const ScCondDateFormatEntry& rFormatEntry, sal_Int32 nPriority ):
981 XclExpRecord( EXC_ID_CF ),
982 XclExpRoot( rRoot ),
983 mrFormatEntry(rFormatEntry),
984 mnPriority(nPriority)
988 XclExpDateFormat::~XclExpDateFormat()
992 namespace {
994 const char* getTimePeriodString( condformat::ScCondFormatDateType eType )
996 switch(eType)
998 case condformat::TODAY:
999 return "today";
1000 case condformat::YESTERDAY:
1001 return "yesterday";
1002 case condformat::TOMORROW:
1003 return "yesterday";
1004 case condformat::THISWEEK:
1005 return "thisWeek";
1006 case condformat::LASTWEEK:
1007 return "lastWeek";
1008 case condformat::NEXTWEEK:
1009 return "nextWeek";
1010 case condformat::THISMONTH:
1011 return "thisMonth";
1012 case condformat::LASTMONTH:
1013 return "lastMonth";
1014 case condformat::NEXTMONTH:
1015 return "nextMonth";
1016 case condformat::LAST7DAYS:
1017 return "last7Days";
1018 default:
1019 break;
1021 return NULL;
1026 void XclExpDateFormat::SaveXml( XclExpXmlStream& rStrm )
1028 // only write the supported entries into OOXML
1029 const char* sTimePeriod = getTimePeriodString(mrFormatEntry.GetDateType());
1030 if(!sTimePeriod)
1031 return;
1033 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1034 rWorksheet->startElement( XML_cfRule,
1035 XML_type, "timePeriod",
1036 XML_priority, OString::number( mnPriority + 1 ).getStr(),
1037 XML_timePeriod, sTimePeriod,
1038 XML_dxfId, OString::number( GetDxfs().GetDxfId( mrFormatEntry.GetStyleName() ) ).getStr(),
1039 FSEND );
1040 rWorksheet->endElement( XML_cfRule);
1043 XclExpCfvo::XclExpCfvo(const XclExpRoot& rRoot, const ScColorScaleEntry& rEntry, const ScAddress& rAddr, bool bFirst):
1044 XclExpRecord(),
1045 XclExpRoot( rRoot ),
1046 mrEntry(rEntry),
1047 maSrcPos(rAddr),
1048 mbFirst(bFirst)
1052 namespace {
1054 OString getColorScaleType( const ScColorScaleEntry& rEntry, bool bFirst )
1056 switch(rEntry.GetType())
1058 case COLORSCALE_MIN:
1059 return "min";
1060 case COLORSCALE_MAX:
1061 return "max";
1062 case COLORSCALE_PERCENT:
1063 return "percent";
1064 case COLORSCALE_FORMULA:
1065 return "formula";
1066 case COLORSCALE_AUTO:
1067 if(bFirst)
1068 return "min";
1069 else
1070 return "max";
1071 case COLORSCALE_PERCENTILE:
1072 return "percentile";
1073 default:
1074 break;
1077 return "num";
1082 void XclExpCfvo::SaveXml( XclExpXmlStream& rStrm )
1084 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1086 OString aValue;
1087 if(mrEntry.GetType() == COLORSCALE_FORMULA)
1089 OUString aFormula = XclXmlUtils::ToOUString( GetCompileFormulaContext(), maSrcPos,
1090 mrEntry.GetFormula()->Clone());
1091 aValue = OUStringToOString(aFormula, RTL_TEXTENCODING_UTF8 );
1093 else
1095 aValue = OString::number( mrEntry.GetValue() );
1098 rWorksheet->startElement( XML_cfvo,
1099 XML_type, getColorScaleType(mrEntry, mbFirst).getStr(),
1100 XML_val, aValue.getStr(),
1101 FSEND );
1103 rWorksheet->endElement( XML_cfvo );
1106 XclExpColScaleCol::XclExpColScaleCol( const XclExpRoot& rRoot, const Color& rColor ):
1107 XclExpRecord(),
1108 XclExpRoot( rRoot ),
1109 mrColor( rColor )
1113 XclExpColScaleCol::~XclExpColScaleCol()
1117 void XclExpColScaleCol::SaveXml( XclExpXmlStream& rStrm )
1119 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1121 rWorksheet->startElement( XML_color,
1122 XML_rgb, XclXmlUtils::ToOString( mrColor ).getStr(),
1123 FSEND );
1125 rWorksheet->endElement( XML_color );
1128 namespace {
1130 OString createHexStringFromDigit(sal_uInt8 nDigit)
1132 OString aString = OString::number( nDigit, 16 );
1133 if(aString.getLength() == 1)
1134 aString = aString + OString::number(0);
1135 return aString;
1138 OString createGuidStringFromInt(sal_uInt8 nGuid[16])
1140 OStringBuffer aBuffer;
1141 aBuffer.append('{');
1142 for(size_t i = 0; i < 16; ++i)
1144 aBuffer.append(createHexStringFromDigit(nGuid[i]));
1145 if(i == 3|| i == 5 || i == 7 || i == 9 )
1146 aBuffer.append('-');
1148 aBuffer.append('}');
1149 OString aString = aBuffer.makeStringAndClear();
1150 return aString.toAsciiUpperCase();
1153 OString generateGUIDString()
1155 sal_uInt8 nGuid[16];
1156 rtl_createUuid(nGuid, NULL, true);
1157 return createGuidStringFromInt(nGuid);
1162 XclExpCondfmt::XclExpCondfmt( const XclExpRoot& rRoot, const ScConditionalFormat& rCondFormat, XclExtLstRef xExtLst, sal_Int32& rIndex ) :
1163 XclExpRecord( EXC_ID_CONDFMT ),
1164 XclExpRoot( rRoot )
1166 const ScRangeList& aScRanges = rCondFormat.GetRange();
1167 GetAddressConverter().ConvertRangeList( maXclRanges, aScRanges, true );
1168 if( !maXclRanges.empty() )
1170 std::vector<XclExpExtCondFormatData> aExtEntries;
1171 for( size_t nIndex = 0, nCount = rCondFormat.size(); nIndex < nCount; ++nIndex )
1172 if( const ScFormatEntry* pFormatEntry = rCondFormat.GetEntry( nIndex ) )
1174 if(pFormatEntry->GetType() == condformat::CONDITION)
1175 maCFList.AppendNewRecord( new XclExpCF( GetRoot(), static_cast<const ScCondFormatEntry&>(*pFormatEntry), ++rIndex ) );
1176 else if(pFormatEntry->GetType() == condformat::COLORSCALE)
1177 maCFList.AppendNewRecord( new XclExpColorScale( GetRoot(), static_cast<const ScColorScaleFormat&>(*pFormatEntry), ++rIndex ) );
1178 else if(pFormatEntry->GetType() == condformat::DATABAR)
1180 const ScDataBarFormat& rFormat = static_cast<const ScDataBarFormat&>(*pFormatEntry);
1181 XclExpExtCondFormatData aExtEntry;
1182 aExtEntry.nPriority = -1;
1183 aExtEntry.aGUID = generateGUIDString();
1184 aExtEntry.pEntry = &rFormat;
1185 aExtEntries.push_back(aExtEntry);
1187 maCFList.AppendNewRecord( new XclExpDataBar( GetRoot(), rFormat, ++rIndex, aExtEntry.aGUID));
1189 else if(pFormatEntry->GetType() == condformat::ICONSET)
1191 // don't export iconSet entries that are not in OOXML
1192 const ScIconSetFormat& rIconSet = static_cast<const ScIconSetFormat&>(*pFormatEntry);
1193 bool bNeedsExt = false;
1194 switch (rIconSet.GetIconSetData()->eIconSetType)
1196 case IconSet_3Smilies:
1197 case IconSet_3ColorSmilies:
1198 case IconSet_3Stars:
1199 case IconSet_3Triangles:
1200 case IconSet_5Boxes:
1202 bNeedsExt = true;
1204 break;
1205 default:
1206 break;
1209 bNeedsExt |= rIconSet.GetIconSetData()->mbCustom;
1211 if (bNeedsExt)
1213 XclExpExtCondFormatData aExtEntry;
1214 aExtEntry.nPriority = ++rIndex;
1215 aExtEntry.aGUID = generateGUIDString();
1216 aExtEntry.pEntry = &rIconSet;
1217 aExtEntries.push_back(aExtEntry);
1219 else
1220 maCFList.AppendNewRecord( new XclExpIconSet( GetRoot(), rIconSet, ++rIndex ) );
1222 else if(pFormatEntry->GetType() == condformat::DATE)
1223 maCFList.AppendNewRecord( new XclExpDateFormat( GetRoot(), static_cast<const ScCondDateFormatEntry&>(*pFormatEntry), ++rIndex ) );
1225 aScRanges.Format( msSeqRef, SCA_VALID, NULL, formula::FormulaGrammar::CONV_XL_A1 );
1227 if(!aExtEntries.empty() && xExtLst.get())
1229 XclExpExtRef pParent = xExtLst->GetItem( XclExpExtDataBarType );
1230 if( !pParent.get() )
1232 xExtLst->AddRecord( XclExpExtRef(new XclExpExtCondFormat( *xExtLst.get() )) );
1233 pParent = xExtLst->GetItem( XclExpExtDataBarType );
1235 static_cast<XclExpExtCondFormat*>(xExtLst->GetItem( XclExpExtDataBarType ).get())->AddRecord(
1236 XclExpExtConditionalFormattingRef(new XclExpExtConditionalFormatting( *pParent, aExtEntries, aScRanges)));
1241 XclExpCondfmt::~XclExpCondfmt()
1245 bool XclExpCondfmt::IsValid() const
1247 return !maCFList.IsEmpty() && !maXclRanges.empty();
1250 void XclExpCondfmt::Save( XclExpStream& rStrm )
1252 if( IsValid() )
1254 XclExpRecord::Save( rStrm );
1255 maCFList.Save( rStrm );
1259 void XclExpCondfmt::WriteBody( XclExpStream& rStrm )
1261 OSL_ENSURE( !maCFList.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
1262 OSL_ENSURE( !maXclRanges.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
1264 rStrm << static_cast< sal_uInt16 >( maCFList.GetSize() )
1265 << sal_uInt16( 1 )
1266 << maXclRanges.GetEnclosingRange()
1267 << maXclRanges;
1270 void XclExpCondfmt::SaveXml( XclExpXmlStream& rStrm )
1272 if( !IsValid() )
1273 return;
1275 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1276 rWorksheet->startElement( XML_conditionalFormatting,
1277 XML_sqref, XclXmlUtils::ToOString( msSeqRef ).getStr(),
1278 // OOXTODO: XML_pivot,
1279 FSEND );
1281 maCFList.SaveXml( rStrm );
1283 rWorksheet->endElement( XML_conditionalFormatting );
1286 XclExpColorScale::XclExpColorScale( const XclExpRoot& rRoot, const ScColorScaleFormat& rFormat, sal_Int32 nPriority ):
1287 XclExpRecord(),
1288 XclExpRoot( rRoot ),
1289 mnPriority( nPriority )
1291 const ScRange* pRange = rFormat.GetRange().front();
1292 ScAddress aAddr = pRange->aStart;
1293 for(ScColorScaleFormat::const_iterator itr = rFormat.begin();
1294 itr != rFormat.end(); ++itr)
1296 // exact position is not important, we allow only absolute refs
1298 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1299 maCfvoList.AppendRecord( xCfvo );
1300 XclExpColScaleColList::RecordRefType xClo( new XclExpColScaleCol( GetRoot(), itr->GetColor() ) );
1301 maColList.AppendRecord( xClo );
1305 void XclExpColorScale::SaveXml( XclExpXmlStream& rStrm )
1307 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1309 rWorksheet->startElement( XML_cfRule,
1310 XML_type, "colorScale",
1311 XML_priority, OString::number( mnPriority + 1 ).getStr(),
1312 FSEND );
1314 rWorksheet->startElement( XML_colorScale, FSEND );
1316 maCfvoList.SaveXml(rStrm);
1317 maColList.SaveXml(rStrm);
1319 rWorksheet->endElement( XML_colorScale );
1321 rWorksheet->endElement( XML_cfRule );
1324 XclExpDataBar::XclExpDataBar( const XclExpRoot& rRoot, const ScDataBarFormat& rFormat, sal_Int32 nPriority, const OString& rGUID):
1325 XclExpRecord(),
1326 XclExpRoot( rRoot ),
1327 mrFormat( rFormat ),
1328 mnPriority( nPriority ),
1329 maGUID(rGUID)
1331 const ScRange* pRange = rFormat.GetRange().front();
1332 ScAddress aAddr = pRange->aStart;
1333 // exact position is not important, we allow only absolute refs
1334 mpCfvoLowerLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpLowerLimit.get(), aAddr, true ) );
1335 mpCfvoUpperLimit.reset( new XclExpCfvo( GetRoot(), *mrFormat.GetDataBarData()->mpUpperLimit.get(), aAddr, false ) );
1337 mpCol.reset( new XclExpColScaleCol( GetRoot(), mrFormat.GetDataBarData()->maPositiveColor ) );
1340 void XclExpDataBar::SaveXml( XclExpXmlStream& rStrm )
1342 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1344 rWorksheet->startElement( XML_cfRule,
1345 XML_type, "dataBar",
1346 XML_priority, OString::number( mnPriority + 1 ).getStr(),
1347 FSEND );
1349 rWorksheet->startElement( XML_dataBar,
1350 XML_showValue, OString::number(int(!mrFormat.GetDataBarData()->mbOnlyBar)),
1351 XML_minLength, OString::number(sal_uInt32(mrFormat.GetDataBarData()->mnMinLength)),
1352 XML_maxLength, OString::number(sal_uInt32(mrFormat.GetDataBarData()->mnMaxLength)),
1353 FSEND );
1355 mpCfvoLowerLimit->SaveXml(rStrm);
1356 mpCfvoUpperLimit->SaveXml(rStrm);
1357 mpCol->SaveXml(rStrm);
1359 rWorksheet->endElement( XML_dataBar );
1361 // extLst entries for Excel 2010 and 2013
1362 rWorksheet->startElement( XML_extLst, FSEND );
1363 rWorksheet->startElement( XML_ext,
1364 FSNS( XML_xmlns, XML_x14 ), "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
1365 XML_uri, "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}",
1366 FSEND );
1368 rWorksheet->startElementNS( XML_x14, XML_id, FSEND );
1369 rWorksheet->write( maGUID.getStr() );
1370 rWorksheet->endElementNS( XML_x14, XML_id );
1372 rWorksheet->endElement( XML_ext );
1373 rWorksheet->endElement( XML_extLst );
1375 rWorksheet->endElement( XML_cfRule );
1378 XclExpIconSet::XclExpIconSet( const XclExpRoot& rRoot, const ScIconSetFormat& rFormat, sal_Int32 nPriority ):
1379 XclExpRecord(),
1380 XclExpRoot( rRoot ),
1381 mrFormat( rFormat ),
1382 mnPriority( nPriority )
1384 const ScRange* pRange = rFormat.GetRange().front();
1385 ScAddress aAddr = pRange->aStart;
1386 for(ScIconSetFormat::const_iterator itr = rFormat.begin();
1387 itr != rFormat.end(); ++itr)
1389 // exact position is not important, we allow only absolute refs
1391 XclExpCfvoList::RecordRefType xCfvo( new XclExpCfvo( GetRoot(), *itr, aAddr ) );
1392 maCfvoList.AppendRecord( xCfvo );
1396 namespace {
1398 const char* getIconSetName( ScIconSetType eType )
1400 ScIconSetMap* pMap = ScIconSetFormat::getIconSetMap();
1401 for(; pMap->pName; ++pMap)
1403 if(pMap->eType == eType)
1404 return pMap->pName;
1407 return "";
1412 void XclExpIconSet::SaveXml( XclExpXmlStream& rStrm )
1414 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1416 rWorksheet->startElement( XML_cfRule,
1417 XML_type, "iconSet",
1418 XML_priority, OString::number( mnPriority + 1 ).getStr(),
1419 FSEND );
1421 const char* pIconSetName = getIconSetName(mrFormat.GetIconSetData()->eIconSetType);
1422 rWorksheet->startElement( XML_iconSet,
1423 XML_iconSet, pIconSetName,
1424 XML_showValue, mrFormat.GetIconSetData()->mbShowValue ? NULL : "0",
1425 XML_reverse, mrFormat.GetIconSetData()->mbReverse ? "1" : NULL,
1426 FSEND );
1428 maCfvoList.SaveXml( rStrm );
1430 rWorksheet->endElement( XML_iconSet );
1431 rWorksheet->endElement( XML_cfRule );
1434 XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot& rRoot, XclExtLstRef xExtLst ) :
1435 XclExpRoot( rRoot )
1437 if( const ScConditionalFormatList* pCondFmtList = GetDoc().GetCondFormList(GetCurrScTab()) )
1439 sal_Int32 nIndex = 0;
1440 for( ScConditionalFormatList::const_iterator itr = pCondFmtList->begin();
1441 itr != pCondFmtList->end(); ++itr)
1443 XclExpCondfmtList::RecordRefType xCondfmtRec( new XclExpCondfmt( GetRoot(), *itr, xExtLst, nIndex ));
1444 if( xCondfmtRec->IsValid() )
1445 maCondfmtList.AppendRecord( xCondfmtRec );
1450 void XclExpCondFormatBuffer::Save( XclExpStream& rStrm )
1452 maCondfmtList.Save( rStrm );
1455 void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream& rStrm )
1457 maCondfmtList.SaveXml( rStrm );
1460 // Validation =================================================================
1462 namespace {
1464 /** Writes a formula for the DV record. */
1465 void lclWriteDvFormula( XclExpStream& rStrm, const XclTokenArray* pXclTokArr )
1467 sal_uInt16 nFmlaSize = pXclTokArr ? pXclTokArr->GetSize() : 0;
1468 rStrm << nFmlaSize << sal_uInt16( 0 );
1469 if( pXclTokArr )
1470 pXclTokArr->WriteArray( rStrm );
1473 /** Writes a formula for the DV record, based on a single string. */
1474 void lclWriteDvFormula( XclExpStream& rStrm, const XclExpString& rString )
1476 // fake a formula with a single tStr token
1477 rStrm << static_cast< sal_uInt16 >( rString.GetSize() + 1 )
1478 << sal_uInt16( 0 )
1479 << EXC_TOKID_STR
1480 << rString;
1483 const char* lcl_GetValidationType( sal_uInt32 nFlags )
1485 switch( nFlags & EXC_DV_MODE_MASK )
1487 case EXC_DV_MODE_ANY: return "none";
1488 case EXC_DV_MODE_WHOLE: return "whole";
1489 case EXC_DV_MODE_DECIMAL: return "decimal";
1490 case EXC_DV_MODE_LIST: return "list";
1491 case EXC_DV_MODE_DATE: return "date";
1492 case EXC_DV_MODE_TIME: return "time";
1493 case EXC_DV_MODE_TEXTLEN: return "textLength";
1494 case EXC_DV_MODE_CUSTOM: return "custom";
1496 return NULL;
1499 const char* lcl_GetOperatorType( sal_uInt32 nFlags )
1501 switch( nFlags & EXC_DV_COND_MASK )
1503 case EXC_DV_COND_BETWEEN: return "between";
1504 case EXC_DV_COND_NOTBETWEEN: return "notBetween";
1505 case EXC_DV_COND_EQUAL: return "equal";
1506 case EXC_DV_COND_NOTEQUAL: return "notEqual";
1507 case EXC_DV_COND_GREATER: return "greaterThan";
1508 case EXC_DV_COND_LESS: return "lessThan";
1509 case EXC_DV_COND_EQGREATER: return "greaterThanOrEqual";
1510 case EXC_DV_COND_EQLESS: return "lessThanOrEqual";
1512 return NULL;
1515 } // namespace
1517 XclExpDV::XclExpDV( const XclExpRoot& rRoot, sal_uLong nScHandle ) :
1518 XclExpRecord( EXC_ID_DV ),
1519 XclExpRoot( rRoot ),
1520 mnFlags( 0 ),
1521 mnScHandle( nScHandle )
1523 if( const ScValidationData* pValData = GetDoc().GetValidationEntry( mnScHandle ) )
1525 // prompt box - empty string represented by single NUL character
1526 OUString aTitle, aText;
1527 bool bShowPrompt = pValData->GetInput( aTitle, aText );
1528 if( !aTitle.isEmpty() )
1529 maPromptTitle.Assign( aTitle );
1530 else
1531 maPromptTitle.Assign( '\0' );
1532 if( !aText.isEmpty() )
1533 maPromptText.Assign( aText );
1534 else
1535 maPromptText.Assign( '\0' );
1537 // error box - empty string represented by single NUL character
1538 ScValidErrorStyle eScErrorStyle;
1539 bool bShowError = pValData->GetErrMsg( aTitle, aText, eScErrorStyle );
1540 if( !aTitle.isEmpty() )
1541 maErrorTitle.Assign( aTitle );
1542 else
1543 maErrorTitle.Assign( '\0' );
1544 if( !aText.isEmpty() )
1545 maErrorText.Assign( aText );
1546 else
1547 maErrorText.Assign( '\0' );
1549 // flags
1550 switch( pValData->GetDataMode() )
1552 case SC_VALID_ANY: mnFlags |= EXC_DV_MODE_ANY; break;
1553 case SC_VALID_WHOLE: mnFlags |= EXC_DV_MODE_WHOLE; break;
1554 case SC_VALID_DECIMAL: mnFlags |= EXC_DV_MODE_DECIMAL; break;
1555 case SC_VALID_LIST: mnFlags |= EXC_DV_MODE_LIST; break;
1556 case SC_VALID_DATE: mnFlags |= EXC_DV_MODE_DATE; break;
1557 case SC_VALID_TIME: mnFlags |= EXC_DV_MODE_TIME; break;
1558 case SC_VALID_TEXTLEN: mnFlags |= EXC_DV_MODE_TEXTLEN; break;
1559 case SC_VALID_CUSTOM: mnFlags |= EXC_DV_MODE_CUSTOM; break;
1560 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown mode" );
1563 switch( pValData->GetOperation() )
1565 case SC_COND_NONE:
1566 case SC_COND_EQUAL: mnFlags |= EXC_DV_COND_EQUAL; break;
1567 case SC_COND_LESS: mnFlags |= EXC_DV_COND_LESS; break;
1568 case SC_COND_GREATER: mnFlags |= EXC_DV_COND_GREATER; break;
1569 case SC_COND_EQLESS: mnFlags |= EXC_DV_COND_EQLESS; break;
1570 case SC_COND_EQGREATER: mnFlags |= EXC_DV_COND_EQGREATER; break;
1571 case SC_COND_NOTEQUAL: mnFlags |= EXC_DV_COND_NOTEQUAL; break;
1572 case SC_COND_BETWEEN: mnFlags |= EXC_DV_COND_BETWEEN; break;
1573 case SC_COND_NOTBETWEEN: mnFlags |= EXC_DV_COND_NOTBETWEEN; break;
1574 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown condition" );
1576 switch( eScErrorStyle )
1578 case SC_VALERR_STOP: mnFlags |= EXC_DV_ERROR_STOP; break;
1579 case SC_VALERR_WARNING: mnFlags |= EXC_DV_ERROR_WARNING; break;
1580 case SC_VALERR_INFO: mnFlags |= EXC_DV_ERROR_INFO; break;
1581 case SC_VALERR_MACRO:
1582 // set INFO for validity with macro call, delete title
1583 mnFlags |= EXC_DV_ERROR_INFO;
1584 maErrorTitle.Assign( '\0' ); // contains macro name
1585 break;
1586 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown error style" );
1588 ::set_flag( mnFlags, EXC_DV_IGNOREBLANK, pValData->IsIgnoreBlank() );
1589 ::set_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN, pValData->GetListType() == css::sheet::TableValidationVisibility::INVISIBLE );
1590 ::set_flag( mnFlags, EXC_DV_SHOWPROMPT, bShowPrompt );
1591 ::set_flag( mnFlags, EXC_DV_SHOWERROR, bShowError );
1593 // formulas
1594 XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
1595 boost::scoped_ptr< ScTokenArray > xScTokArr;
1597 // first formula
1598 xScTokArr.reset( pValData->CreateTokenArry( 0 ) );
1599 if( xScTokArr.get() )
1601 if( pValData->GetDataMode() == SC_VALID_LIST )
1603 OUString aString;
1604 if( XclTokenArrayHelper::GetStringList( aString, *xScTokArr, '\n' ) )
1606 OUStringBuffer sFormulaBuf;
1607 sFormulaBuf.append( '"' );
1608 /* Formula is a list of string tokens -> build the Excel string.
1609 Data validity is BIFF8 only (important for the XclExpString object).
1610 Excel uses the NUL character as string list separator. */
1611 mxString1.reset( new XclExpString( EXC_STR_8BITLENGTH ) );
1612 sal_Int32 nTokenCnt = comphelper::string::getTokenCount(aString, '\n');
1613 sal_Int32 nStringIx = 0;
1614 for( sal_Int32 nToken = 0; nToken < nTokenCnt; ++nToken )
1616 OUString aToken( aString.getToken( 0, '\n', nStringIx ) );
1617 if( nToken > 0 )
1619 mxString1->Append(OUString(static_cast<sal_Unicode>('\0')));
1620 sFormulaBuf.append( ',' );
1622 mxString1->Append( aToken );
1623 sFormulaBuf.append( aToken );
1625 ::set_flag( mnFlags, EXC_DV_STRINGLIST );
1627 sFormulaBuf.append( '"' );
1628 msFormula1 = sFormulaBuf.makeStringAndClear();
1630 else
1632 /* All other formulas in validation are stored like conditional
1633 formatting formulas (with tRefN/tAreaN tokens as value or
1634 array class). But NOT the cell references and defined names
1635 in list validation - they are stored as reference class
1636 tokens... Example:
1637 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
1638 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
1639 Formula compiler supports this by offering two different functions
1640 CreateDataValFormula() and CreateListValFormula(). */
1641 if(GetOutput() == EXC_OUTPUT_BINARY)
1642 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_LISTVAL, *xScTokArr );
1643 else
1644 msFormula1 = XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData->GetSrcPos(),
1645 xScTokArr.get());
1648 else
1650 // no list validation -> convert the formula
1651 if(GetOutput() == EXC_OUTPUT_BINARY)
1652 mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1653 else
1654 msFormula1 = XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData->GetSrcPos(),
1655 xScTokArr.get());
1659 // second formula
1660 xScTokArr.reset( pValData->CreateTokenArry( 1 ) );
1661 if( xScTokArr.get() )
1663 if(GetOutput() == EXC_OUTPUT_BINARY)
1664 mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
1665 else
1666 msFormula2 = XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData->GetSrcPos(),
1667 xScTokArr.get());
1670 else
1672 OSL_FAIL( "XclExpDV::XclExpDV - missing core data" );
1673 mnScHandle = ULONG_MAX;
1677 XclExpDV::~XclExpDV()
1681 void XclExpDV::InsertCellRange( const ScRange& rRange )
1683 maScRanges.Join( rRange );
1686 bool XclExpDV::Finalize()
1688 GetAddressConverter().ConvertRangeList( maXclRanges, maScRanges, true );
1689 return (mnScHandle != ULONG_MAX) && !maXclRanges.empty();
1692 void XclExpDV::WriteBody( XclExpStream& rStrm )
1694 // flags and strings
1695 rStrm << mnFlags << maPromptTitle << maErrorTitle << maPromptText << maErrorText;
1696 // condition formulas
1697 if( mxString1.get() )
1698 lclWriteDvFormula( rStrm, *mxString1 );
1699 else
1700 lclWriteDvFormula( rStrm, mxTokArr1.get() );
1701 lclWriteDvFormula( rStrm, mxTokArr2.get() );
1702 // cell ranges
1703 rStrm << maXclRanges;
1706 void XclExpDV::SaveXml( XclExpXmlStream& rStrm )
1708 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1709 rWorksheet->startElement( XML_dataValidation,
1710 XML_allowBlank, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_IGNOREBLANK ) ),
1711 XML_error, XESTRING_TO_PSZ( maErrorText ),
1712 // OOXTODO: XML_errorStyle,
1713 XML_errorTitle, XESTRING_TO_PSZ( maErrorTitle ),
1714 // OOXTODO: XML_imeMode,
1715 XML_operator, lcl_GetOperatorType( mnFlags ),
1716 XML_prompt, XESTRING_TO_PSZ( maPromptText ),
1717 XML_promptTitle, XESTRING_TO_PSZ( maPromptTitle ),
1718 // showDropDown should have been showNoDropDown - check oox/xlsx import for details
1719 XML_showDropDown, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN ) ),
1720 XML_showErrorMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWERROR ) ),
1721 XML_showInputMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWPROMPT ) ),
1722 XML_sqref, XclXmlUtils::ToOString( maScRanges ).getStr(),
1723 XML_type, lcl_GetValidationType( mnFlags ),
1724 FSEND );
1725 if( !msFormula1.isEmpty() )
1727 rWorksheet->startElement( XML_formula1, FSEND );
1728 rWorksheet->writeEscaped( msFormula1 );
1729 rWorksheet->endElement( XML_formula1 );
1731 if( !msFormula2.isEmpty() )
1733 rWorksheet->startElement( XML_formula2, FSEND );
1734 rWorksheet->writeEscaped( msFormula2 );
1735 rWorksheet->endElement( XML_formula2 );
1737 rWorksheet->endElement( XML_dataValidation );
1740 XclExpDval::XclExpDval( const XclExpRoot& rRoot ) :
1741 XclExpRecord( EXC_ID_DVAL, 18 ),
1742 XclExpRoot( rRoot )
1746 XclExpDval::~XclExpDval()
1750 void XclExpDval::InsertCellRange( const ScRange& rRange, sal_uLong nScHandle )
1752 if( GetBiff() == EXC_BIFF8 )
1754 XclExpDV& rDVRec = SearchOrCreateDv( nScHandle );
1755 rDVRec.InsertCellRange( rRange );
1759 void XclExpDval::Save( XclExpStream& rStrm )
1761 // check all records
1762 size_t nPos = maDVList.GetSize();
1763 while( nPos )
1765 --nPos; // backwards to keep nPos valid
1766 XclExpDVRef xDVRec = maDVList.GetRecord( nPos );
1767 if( !xDVRec->Finalize() )
1768 maDVList.RemoveRecord( nPos );
1771 // write the DVAL and the DV's
1772 if( !maDVList.IsEmpty() )
1774 XclExpRecord::Save( rStrm );
1775 maDVList.Save( rStrm );
1779 void XclExpDval::SaveXml( XclExpXmlStream& rStrm )
1781 if( maDVList.IsEmpty() )
1782 return;
1784 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1785 rWorksheet->startElement( XML_dataValidations,
1786 XML_count, OString::number( maDVList.GetSize() ).getStr(),
1787 // OOXTODO: XML_disablePrompts,
1788 // OOXTODO: XML_xWindow,
1789 // OOXTODO: XML_yWindow,
1790 FSEND );
1791 maDVList.SaveXml( rStrm );
1792 rWorksheet->endElement( XML_dataValidations );
1795 XclExpDV& XclExpDval::SearchOrCreateDv( sal_uLong nScHandle )
1797 // test last found record
1798 if( mxLastFoundDV.get() && (mxLastFoundDV->GetScHandle() == nScHandle) )
1799 return *mxLastFoundDV;
1801 // binary search
1802 size_t nCurrPos = 0;
1803 if( !maDVList.IsEmpty() )
1805 size_t nFirstPos = 0;
1806 size_t nLastPos = maDVList.GetSize() - 1;
1807 bool bLoop = true;
1808 sal_uLong nCurrScHandle = ::std::numeric_limits< sal_uLong >::max();
1809 while( (nFirstPos <= nLastPos) && bLoop )
1811 nCurrPos = (nFirstPos + nLastPos) / 2;
1812 mxLastFoundDV = maDVList.GetRecord( nCurrPos );
1813 nCurrScHandle = mxLastFoundDV->GetScHandle();
1814 if( nCurrScHandle == nScHandle )
1815 bLoop = false;
1816 else if( nCurrScHandle < nScHandle )
1817 nFirstPos = nCurrPos + 1;
1818 else if( nCurrPos )
1819 nLastPos = nCurrPos - 1;
1820 else // special case for nLastPos = -1
1821 bLoop = false;
1823 if( nCurrScHandle == nScHandle )
1824 return *mxLastFoundDV;
1825 else if( nCurrScHandle < nScHandle )
1826 ++nCurrPos;
1829 // create new DV record
1830 mxLastFoundDV.reset( new XclExpDV( *this, nScHandle ) );
1831 maDVList.InsertRecord( mxLastFoundDV, nCurrPos );
1832 return *mxLastFoundDV;
1835 void XclExpDval::WriteBody( XclExpStream& rStrm )
1837 rStrm.WriteZeroBytes( 10 );
1838 rStrm << EXC_DVAL_NOOBJ << static_cast< sal_uInt32 >( maDVList.GetSize() );
1841 // Web Queries ================================================================
1843 XclExpWebQuery::XclExpWebQuery(
1844 const OUString& rRangeName,
1845 const OUString& rUrl,
1846 const OUString& rSource,
1847 sal_Int32 nRefrSecs ) :
1848 maDestRange( rRangeName ),
1849 maUrl( rUrl ),
1850 // refresh delay time: seconds -> minutes
1851 mnRefresh( ulimit_cast< sal_Int16 >( (nRefrSecs + 59L) / 60L ) ),
1852 mbEntireDoc( false )
1854 // comma separated list of HTML table names or indexes
1855 sal_Int32 nTokenCnt = comphelper::string::getTokenCount(rSource, ';');
1856 OUString aNewTables;
1857 OUString aAppendTable;
1858 sal_Int32 nStringIx = 0;
1859 bool bExitLoop = false;
1860 for( sal_Int32 nToken = 0; (nToken < nTokenCnt) && !bExitLoop; ++nToken )
1862 OUString aToken( rSource.getToken( 0, ';', nStringIx ) );
1863 mbEntireDoc = ScfTools::IsHTMLDocName( aToken );
1864 bExitLoop = mbEntireDoc || ScfTools::IsHTMLTablesName( aToken );
1865 if( !bExitLoop && ScfTools::GetHTMLNameFromName( aToken, aAppendTable ) )
1866 aNewTables = ScGlobal::addToken( aNewTables, aAppendTable, ',' );
1869 if( !bExitLoop ) // neither HTML_all nor HTML_tables found
1871 if( !aNewTables.isEmpty() )
1872 mxQryTables.reset( new XclExpString( aNewTables ) );
1873 else
1874 mbEntireDoc = true;
1878 XclExpWebQuery::~XclExpWebQuery()
1882 void XclExpWebQuery::Save( XclExpStream& rStrm )
1884 OSL_ENSURE( !mbEntireDoc || !mxQryTables.get(), "XclExpWebQuery::Save - illegal mode" );
1885 sal_uInt16 nFlags;
1887 // QSI record
1888 rStrm.StartRecord( EXC_ID_QSI, 10 + maDestRange.GetSize() );
1889 rStrm << EXC_QSI_DEFAULTFLAGS
1890 << sal_uInt16( 0x0010 )
1891 << sal_uInt16( 0x0012 )
1892 << sal_uInt32( 0x00000000 )
1893 << maDestRange;
1894 rStrm.EndRecord();
1896 // PARAMQRY record
1897 nFlags = 0;
1898 ::insert_value( nFlags, EXC_PQRYTYPE_WEBQUERY, 0, 3 );
1899 ::set_flag( nFlags, EXC_PQRY_WEBQUERY );
1900 ::set_flag( nFlags, EXC_PQRY_TABLES, !mbEntireDoc );
1901 rStrm.StartRecord( EXC_ID_PQRY, 12 );
1902 rStrm << nFlags
1903 << sal_uInt16( 0x0000 )
1904 << sal_uInt16( 0x0001 );
1905 rStrm.WriteZeroBytes( 6 );
1906 rStrm.EndRecord();
1908 // WQSTRING record
1909 rStrm.StartRecord( EXC_ID_WQSTRING, maUrl.GetSize() );
1910 rStrm << maUrl;
1911 rStrm.EndRecord();
1913 // unknown record 0x0802
1914 rStrm.StartRecord( EXC_ID_0802, 16 + maDestRange.GetSize() );
1915 rStrm << EXC_ID_0802; // repeated record id ?!?
1916 rStrm.WriteZeroBytes( 6 );
1917 rStrm << sal_uInt16( 0x0003 )
1918 << sal_uInt32( 0x00000000 )
1919 << sal_uInt16( 0x0010 )
1920 << maDestRange;
1921 rStrm.EndRecord();
1923 // WEBQRYSETTINGS record
1924 nFlags = mxQryTables.get() ? EXC_WQSETT_SPECTABLES : EXC_WQSETT_ALL;
1925 rStrm.StartRecord( EXC_ID_WQSETT, 28 );
1926 rStrm << EXC_ID_WQSETT // repeated record id ?!?
1927 << sal_uInt16( 0x0000 )
1928 << sal_uInt16( 0x0004 )
1929 << sal_uInt16( 0x0000 )
1930 << EXC_WQSETT_DEFAULTFLAGS
1931 << nFlags;
1932 rStrm.WriteZeroBytes( 10 );
1933 rStrm << mnRefresh // refresh delay in minutes
1934 << EXC_WQSETT_FORMATFULL
1935 << sal_uInt16( 0x0000 );
1936 rStrm.EndRecord();
1938 // WEBQRYTABLES record
1939 if( mxQryTables.get() )
1941 rStrm.StartRecord( EXC_ID_WQTABLES, 4 + mxQryTables->GetSize() );
1942 rStrm << EXC_ID_WQTABLES // repeated record id ?!?
1943 << sal_uInt16( 0x0000 )
1944 << *mxQryTables; // comma separated list of source tables
1945 rStrm.EndRecord();
1949 XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot& rRoot )
1951 SCTAB nScTab = rRoot.GetCurrScTab();
1952 SfxObjectShell* pShell = rRoot.GetDocShell();
1953 if( !pShell ) return;
1954 ScfPropertySet aModelProp( pShell->GetModel() );
1955 if( !aModelProp.Is() ) return;
1957 Reference< XAreaLinks > xAreaLinks;
1958 aModelProp.GetProperty( xAreaLinks, SC_UNO_AREALINKS );
1959 if( !xAreaLinks.is() ) return;
1961 for( sal_Int32 nIndex = 0, nCount = xAreaLinks->getCount(); nIndex < nCount; ++nIndex )
1963 Reference< XAreaLink > xAreaLink( xAreaLinks->getByIndex( nIndex ), UNO_QUERY );
1964 if( xAreaLink.is() )
1966 CellRangeAddress aDestRange( xAreaLink->getDestArea() );
1967 if( static_cast< SCTAB >( aDestRange.Sheet ) == nScTab )
1969 ScfPropertySet aLinkProp( xAreaLink );
1970 OUString aFilter;
1971 if( aLinkProp.GetProperty( aFilter, SC_UNONAME_FILTER ) &&
1972 (aFilter == EXC_WEBQRY_FILTER) )
1974 // get properties
1975 OUString /*aFilterOpt,*/ aUrl;
1976 sal_Int32 nRefresh = 0;
1978 // aLinkProp.GetProperty( aFilterOpt, SC_UNONAME_FILTOPT );
1979 aLinkProp.GetProperty( aUrl, SC_UNONAME_LINKURL );
1980 aLinkProp.GetProperty( nRefresh, SC_UNONAME_REFDELAY );
1982 OUString aAbsDoc( ScGlobal::GetAbsDocName( aUrl, pShell ) );
1983 INetURLObject aUrlObj( aAbsDoc );
1984 OUString aWebQueryUrl( aUrlObj.getFSysPath( INetURLObject::FSYS_DOS ) );
1985 if( aWebQueryUrl.isEmpty() )
1986 aWebQueryUrl = aAbsDoc;
1988 // find range or create a new range
1989 OUString aRangeName;
1990 ScRange aScDestRange;
1991 ScUnoConversion::FillScRange( aScDestRange, aDestRange );
1992 if( const ScRangeData* pRangeData = rRoot.GetNamedRanges().findByRange( aScDestRange ) )
1994 aRangeName = pRangeData->GetName();
1996 else
1998 XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
1999 XclExpNameManager& rNameMgr = rRoot.GetNameManager();
2001 // create a new unique defined name containing the range
2002 XclTokenArrayRef xTokArr = rFmlaComp.CreateFormula( EXC_FMLATYPE_WQUERY, aScDestRange );
2003 sal_uInt16 nNameIdx = rNameMgr.InsertUniqueName( aUrlObj.getBase(), xTokArr, nScTab );
2004 aRangeName = rNameMgr.GetOrigName( nNameIdx );
2007 // create and store the web query record
2008 if( !aRangeName.isEmpty() )
2009 AppendNewRecord( new XclExpWebQuery(
2010 aRangeName, aWebQueryUrl, xAreaLink->getSourceArea(), nRefresh ) );
2017 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */