1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
24 #include <com/sun/star/sheet/XAreaLinks.hpp>
25 #include <com/sun/star/sheet/XAreaLink.hpp>
26 #include <comphelper/string.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <tools/urlobj.hxx>
29 #include <svl/itemset.hxx>
30 #include <formula/grammar.hxx>
31 #include "scitems.hxx"
32 #include <editeng/eeitem.hxx>
33 #include <editeng/flditem.hxx>
34 #include "document.hxx"
35 #include "validat.hxx"
36 #include "unonames.hxx"
37 #include "convuno.hxx"
38 #include "rangenam.hxx"
39 #include "tokenarray.hxx"
40 #include "stlpool.hxx"
41 #include "patattr.hxx"
42 #include "fapihelper.hxx"
43 #include "xehelper.hxx"
44 #include "xestyle.hxx"
48 using namespace ::oox
;
50 using ::com::sun::star::uno::Reference
;
51 using ::com::sun::star::uno::Any
;
52 using ::com::sun::star::uno::UNO_QUERY
;
53 using ::com::sun::star::table::CellRangeAddress
;
54 using ::com::sun::star::sheet::XAreaLinks
;
55 using ::com::sun::star::sheet::XAreaLink
;
57 // Shared string table ========================================================
59 /** A single string entry in the hash table. */
60 struct XclExpHashEntry
62 const XclExpString
* mpString
; /// Pointer to the string (no ownership).
63 sal_uInt32 mnSstIndex
; /// The SST index of this string.
64 inline explicit XclExpHashEntry( const XclExpString
* pString
= nullptr, sal_uInt32 nSstIndex
= 0 ) :
65 mpString( pString
), mnSstIndex( nSstIndex
) {}
68 /** Function object for strict weak ordering. */
69 struct XclExpHashEntrySWO
71 inline bool operator()( const XclExpHashEntry
& rLeft
, const XclExpHashEntry
& rRight
) const
72 { return *rLeft
.mpString
< *rRight
.mpString
; }
75 /** Implementation of the SST export.
76 @descr Stores all passed strings in a hash table and prevents repeated
77 insertion of equal strings. */
81 explicit XclExpSstImpl();
83 /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
84 sal_uInt32
Insert( XclExpStringRef xString
);
86 /** Writes the complete SST and EXTSST records. */
87 void Save( XclExpStream
& rStrm
);
88 void SaveXml( XclExpXmlStream
& rStrm
);
91 typedef ::std::list
< XclExpStringRef
> XclExpStringList
;
92 typedef ::std::vector
< XclExpHashEntry
> XclExpHashVec
;
93 typedef ::std::vector
< XclExpHashVec
> XclExpHashTab
;
95 XclExpStringList maStringList
; /// List of unique strings (in SST ID order).
96 XclExpHashTab maHashTab
; /// Hashed table that manages string pointers.
97 sal_uInt32 mnTotal
; /// Total count of strings (including doubles).
98 sal_uInt32 mnSize
; /// Size of the SST (count of unique strings).
101 const sal_uInt32 EXC_SST_HASHTABLE_SIZE
= 2048;
103 XclExpSstImpl::XclExpSstImpl() :
104 maHashTab( EXC_SST_HASHTABLE_SIZE
),
110 sal_uInt32
XclExpSstImpl::Insert( XclExpStringRef xString
)
112 OSL_ENSURE( xString
.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
114 xString
.reset( new XclExpString
);
117 sal_uInt32 nSstIndex
= 0;
119 // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
120 sal_uInt16 nHash
= xString
->GetHash();
121 (nHash
^= (nHash
/ EXC_SST_HASHTABLE_SIZE
)) %= EXC_SST_HASHTABLE_SIZE
;
123 XclExpHashVec
& rVec
= maHashTab
[ nHash
];
124 XclExpHashEntry
aEntry( xString
.get(), mnSize
);
125 XclExpHashVec::iterator aIt
= ::std::lower_bound( rVec
.begin(), rVec
.end(), aEntry
, XclExpHashEntrySWO() );
126 if( (aIt
== rVec
.end()) || (*aIt
->mpString
!= *xString
) )
129 maStringList
.push_back( xString
);
130 rVec
.insert( aIt
, aEntry
);
135 nSstIndex
= aIt
->mnSstIndex
;
141 void XclExpSstImpl::Save( XclExpStream
& rStrm
)
143 if( maStringList
.empty() )
146 SvMemoryStream
aExtSst( 8192 );
148 sal_uInt32 nBucket
= mnSize
;
149 while( nBucket
> 0x0100 )
152 sal_uInt16 nPerBucket
= llimit_cast
< sal_uInt16
>( nBucket
, 8 );
153 sal_uInt16 nBucketIndex
= 0;
155 // *** write the SST record ***
157 rStrm
.StartRecord( EXC_ID_SST
, 8 );
159 rStrm
<< mnTotal
<< mnSize
;
160 for( XclExpStringList::const_iterator aIt
= maStringList
.begin(), aEnd
= maStringList
.end(); aIt
!= aEnd
; ++aIt
)
164 // write bucket info before string to get correct record position
165 sal_uInt32 nStrmPos
= static_cast< sal_uInt32
>( rStrm
.GetSvStreamPos() );
166 sal_uInt16 nRecPos
= rStrm
.GetRawRecPos() + 4;
167 aExtSst
.WriteUInt32( nStrmPos
) // stream position
168 .WriteUInt16( nRecPos
) // position from start of SST or CONTINUE
169 .WriteUInt16( 0 ); // reserved
174 if( ++nBucketIndex
== nPerBucket
)
180 // *** write the EXTSST record ***
182 rStrm
.StartRecord( EXC_ID_EXTSST
, 0 );
185 rStrm
.SetSliceSize( 8 ); // size of one bucket info
186 aExtSst
.Seek( STREAM_SEEK_TO_BEGIN
);
187 rStrm
.CopyFromStream( aExtSst
);
192 void XclExpSstImpl::SaveXml( XclExpXmlStream
& rStrm
)
194 if( maStringList
.empty() )
197 sax_fastparser::FSHelperPtr pSst
= rStrm
.CreateOutputStream(
198 "xl/sharedStrings.xml",
200 rStrm
.GetCurrentStream()->getOutputStream(),
201 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
202 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
203 rStrm
.PushStream( pSst
);
205 pSst
->startElement( XML_sst
,
206 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
207 XML_count
, OString::number( mnTotal
).getStr(),
208 XML_uniqueCount
, OString::number( mnSize
).getStr(),
211 for( XclExpStringList::const_iterator aIt
= maStringList
.begin(), aEnd
= maStringList
.end(); aIt
!= aEnd
; ++aIt
)
213 pSst
->startElement( XML_si
, FSEND
);
214 (*aIt
)->WriteXml( rStrm
);
215 pSst
->endElement( XML_si
);
218 pSst
->endElement( XML_sst
);
223 XclExpSst::XclExpSst() :
224 mxImpl( new XclExpSstImpl
)
228 XclExpSst::~XclExpSst()
232 sal_uInt32
XclExpSst::Insert( const XclExpStringRef
& xString
)
234 return mxImpl
->Insert( xString
);
237 void XclExpSst::Save( XclExpStream
& rStrm
)
239 mxImpl
->Save( rStrm
);
242 void XclExpSst::SaveXml( XclExpXmlStream
& rStrm
)
244 mxImpl
->SaveXml( rStrm
);
247 // Merged cells ===============================================================
249 XclExpMergedcells::XclExpMergedcells( const XclExpRoot
& rRoot
) :
254 void XclExpMergedcells::AppendRange( const ScRange
& rRange
, sal_uInt32 nBaseXFId
)
256 if( GetBiff() == EXC_BIFF8
)
258 maMergedRanges
.Append( rRange
);
259 maBaseXFIds
.push_back( nBaseXFId
);
263 sal_uInt32
XclExpMergedcells::GetBaseXFId( const ScAddress
& rPos
) const
265 OSL_ENSURE( maBaseXFIds
.size() == maMergedRanges
.size(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
266 ScfUInt32Vec::const_iterator aIt
= maBaseXFIds
.begin();
267 ScRangeList
& rNCRanges
= const_cast< ScRangeList
& >( maMergedRanges
);
268 for ( size_t i
= 0, nRanges
= rNCRanges
.size(); i
< nRanges
; ++i
, ++aIt
)
270 const ScRange
* pScRange
= rNCRanges
[ i
];
271 if( pScRange
->In( rPos
) )
274 return EXC_XFID_NOTFOUND
;
277 void XclExpMergedcells::Save( XclExpStream
& rStrm
)
279 if( GetBiff() == EXC_BIFF8
)
281 XclRangeList aXclRanges
;
282 GetAddressConverter().ConvertRangeList( aXclRanges
, maMergedRanges
, true );
283 size_t nFirstRange
= 0;
284 size_t nRemainingRanges
= aXclRanges
.size();
285 while( nRemainingRanges
> 0 )
287 size_t nRangeCount
= ::std::min
< size_t >( nRemainingRanges
, EXC_MERGEDCELLS_MAXCOUNT
);
288 rStrm
.StartRecord( EXC_ID_MERGEDCELLS
, 2 + 8 * nRangeCount
);
289 aXclRanges
.WriteSubList( rStrm
, nFirstRange
, nRangeCount
);
291 nFirstRange
+= nRangeCount
;
292 nRemainingRanges
-= nRangeCount
;
297 void XclExpMergedcells::SaveXml( XclExpXmlStream
& rStrm
)
299 size_t nCount
= maMergedRanges
.size();
302 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
303 rWorksheet
->startElement( XML_mergeCells
,
304 XML_count
, OString::number( nCount
).getStr(),
306 for( size_t i
= 0; i
< nCount
; ++i
)
308 if( const ScRange
* pRange
= maMergedRanges
[ i
] )
310 rWorksheet
->singleElement( XML_mergeCell
,
311 XML_ref
, XclXmlUtils::ToOString( *pRange
).getStr(),
315 rWorksheet
->endElement( XML_mergeCells
);
318 // Hyperlinks =================================================================
320 XclExpHyperlink::XclExpHyperlink( const XclExpRoot
& rRoot
, const SvxURLField
& rUrlField
, const ScAddress
& rScPos
) :
321 XclExpRecord( EXC_ID_HLINK
),
323 mxVarData( new SvMemoryStream
),
327 const OUString
& rUrl
= rUrlField
.GetURL();
328 const OUString
& rRepr
= rUrlField
.GetRepresentation();
329 INetURLObject
aUrlObj( rUrl
);
330 const INetProtocol eProtocol
= aUrlObj
.GetProtocol();
331 bool bWithRepr
= !rRepr
.isEmpty();
332 XclExpStream
aXclStrm( *mxVarData
, rRoot
); // using in raw write mode.
337 XclExpString
aDescr( rRepr
, EXC_STR_FORCEUNICODE
, 255 );
338 aXclStrm
<< sal_uInt32( aDescr
.Len() + 1 ); // string length + 1 trailing zero word
339 aDescr
.WriteBuffer( aXclStrm
); // NO flags
340 aXclStrm
<< sal_uInt16( 0 );
342 mnFlags
|= EXC_HLINK_DESCR
;
347 if( eProtocol
== INetProtocol::File
|| eProtocol
== INetProtocol::Smb
)
351 /* TODO: should we differentiate between BIFF and OOXML and write IURI
352 * encoded for OOXML? */
353 OUString
aFileName( BuildFileName( nLevel
, bRel
, rUrl
, rRoot
, false ) );
355 if( eProtocol
== INetProtocol::Smb
)
357 // #n382718# (and #n261623#) Convert smb notation to '\\'
358 aFileName
= aUrlObj
.GetMainURL( INetURLObject::NO_DECODE
);
359 aFileName
= aFileName
.copy(4); // skip the 'smb:' part
360 aFileName
= aFileName
.replace('/', '\\');
364 mnFlags
|= EXC_HLINK_ABS
;
365 mnFlags
|= EXC_HLINK_BODY
;
367 OString
aAsciiLink(OUStringToOString(aFileName
,
368 rRoot
.GetTextEncoding()));
369 XclExpString
aLink( aFileName
, EXC_STR_FORCEUNICODE
, 255 );
370 aXclStrm
<< XclTools::maGuidFileMoniker
372 << sal_uInt32( aAsciiLink
.getLength() + 1 ); // string length + 1 trailing zero byte
373 aXclStrm
.Write( aAsciiLink
.getStr(), aAsciiLink
.getLength() );
374 aXclStrm
<< sal_uInt8( 0 )
375 << sal_uInt32( 0xDEADFFFF );
376 aXclStrm
.WriteZeroBytes( 20 );
377 aXclStrm
<< sal_uInt32( aLink
.GetBufferSize() + 6 )
378 << sal_uInt32( aLink
.GetBufferSize() ) // byte count, not string length
379 << sal_uInt16( 0x0003 );
380 aLink
.WriteBuffer( aXclStrm
); // NO flags
382 if (m_Repr
.isEmpty())
385 msTarget
= XclXmlUtils::ToOUString( aLink
);
386 // ooxml expects the file:/// part appended ( or at least
387 // ms2007 does, ms2010 is more tolerant )
388 msTarget
= "file:///" + msTarget
;
390 else if( eProtocol
!= INetProtocol::NotValid
)
392 XclExpString
aUrl( aUrlObj
.GetURLNoMark(), EXC_STR_FORCEUNICODE
, 255 );
393 aXclStrm
<< XclTools::maGuidUrlMoniker
394 << sal_uInt32( aUrl
.GetBufferSize() + 2 ); // byte count + 1 trailing zero word
395 aUrl
.WriteBuffer( aXclStrm
); // NO flags
396 aXclStrm
<< sal_uInt16( 0 );
398 mnFlags
|= EXC_HLINK_BODY
| EXC_HLINK_ABS
;
399 if (m_Repr
.isEmpty())
402 msTarget
= XclXmlUtils::ToOUString( aUrl
);
404 else if( !rUrl
.isEmpty() && rUrl
[0] == '#' ) // hack for #89066#
406 OUString
aTextMark( rUrl
.copy( 1 ) );
408 sal_Int32 nSepPos
= aTextMark
.lastIndexOf( '.' );
410 aTextMark
= aTextMark
.replaceAt( nSepPos
, 1, "!" );
412 nSepPos
= aTextMark
.lastIndexOf( '!' );
416 OUString
aSheetName( aTextMark
.copy(0, nSepPos
));
418 if ( aSheetName
.indexOf(' ') != -1 && aSheetName
[0] != '\'')
420 aTextMark
= "'" + aTextMark
.replaceAt(nSepPos
, 0, "'");
424 mxTextMark
.reset( new XclExpString( aTextMark
, EXC_STR_FORCEUNICODE
, 255 ) );
428 if( !mxTextMark
.get() && aUrlObj
.HasMark() )
429 mxTextMark
.reset( new XclExpString( aUrlObj
.GetMark(), EXC_STR_FORCEUNICODE
, 255 ) );
431 if( mxTextMark
.get() )
433 aXclStrm
<< sal_uInt32( mxTextMark
->Len() + 1 ); // string length + 1 trailing zero word
434 mxTextMark
->WriteBuffer( aXclStrm
); // NO flags
435 aXclStrm
<< sal_uInt16( 0 );
437 mnFlags
|= EXC_HLINK_MARK
;
440 SetRecSize( 32 + mxVarData
->Tell() );
443 XclExpHyperlink::~XclExpHyperlink()
447 OUString
XclExpHyperlink::BuildFileName(
448 sal_uInt16
& rnLevel
, bool& rbRel
, const OUString
& rUrl
, const XclExpRoot
& rRoot
, bool bEncoded
)
450 INetURLObject
aURLObject( rUrl
);
451 OUString
aDosName( bEncoded
? aURLObject
.GetURLPath() : aURLObject
.getFSysPath( INetURLObject::FSYS_DOS
) );
453 rbRel
= rRoot
.IsRelUrl();
457 // try to convert to relative file name
458 OUString
aTmpName( aDosName
);
459 aDosName
= INetURLObject::GetRelURL( rRoot
.GetBasePath(), rUrl
,
460 INetURLObject::WAS_ENCODED
,
461 (bEncoded
? INetURLObject::DECODE_TO_IURI
: INetURLObject::DECODE_WITH_CHARSET
));
463 if (aDosName
.startsWith(INET_FILE_SCHEME
))
465 // not converted to rel -> back to old, return absolute flag
469 else if (aDosName
.startsWith("./"))
471 aDosName
= aDosName
.copy(2);
475 while (aDosName
.startsWith("../"))
477 aDosName
= aDosName
.copy(3);
485 void XclExpHyperlink::WriteBody( XclExpStream
& rStrm
)
487 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( maScPos
.Col() );
488 sal_uInt16 nXclRow
= static_cast< sal_uInt16
>( maScPos
.Row() );
489 rStrm
<< nXclRow
<< nXclRow
<< nXclCol
<< nXclCol
;
490 WriteEmbeddedData( rStrm
);
493 void XclExpHyperlink::WriteEmbeddedData( XclExpStream
& rStrm
)
495 rStrm
<< XclTools::maGuidStdLink
499 mxVarData
->Seek( STREAM_SEEK_TO_BEGIN
);
500 rStrm
.CopyFromStream( *mxVarData
);
503 void XclExpHyperlink::SaveXml( XclExpXmlStream
& rStrm
)
505 OUString sId
= !msTarget
.isEmpty() ? rStrm
.addRelation( rStrm
.GetCurrentStream()->getOutputStream(),
506 XclXmlUtils::ToOUString( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ),
507 msTarget
, true ) : OUString();
508 rStrm
.GetCurrentStream()->singleElement( XML_hyperlink
,
509 XML_ref
, XclXmlUtils::ToOString( maScPos
).getStr(),
510 FSNS( XML_r
, XML_id
), !sId
.isEmpty()
511 ? XclXmlUtils::ToOString( sId
).getStr()
513 XML_location
, mxTextMark
.get() != nullptr
514 ? XclXmlUtils::ToOString( *mxTextMark
).getStr()
516 // OOXTODO: XML_tooltip, from record HLinkTooltip 800h wzTooltip
517 XML_display
, mbSetDisplay
518 ? XclXmlUtils::ToOString(m_Repr
).getStr()
523 // Label ranges ===============================================================
525 XclExpLabelranges::XclExpLabelranges( const XclExpRoot
& rRoot
) :
528 SCTAB nScTab
= GetCurrScTab();
530 FillRangeList( maRowRanges
, rRoot
.GetDoc().GetRowNameRangesRef(), nScTab
);
531 // row labels only over 1 column (restriction of Excel97/2000/XP)
532 for ( size_t i
= 0, nRanges
= maRowRanges
.size(); i
< nRanges
; ++i
)
534 ScRange
* pScRange
= maRowRanges
[ i
];
535 if( pScRange
->aStart
.Col() != pScRange
->aEnd
.Col() )
536 pScRange
->aEnd
.SetCol( pScRange
->aStart
.Col() );
539 FillRangeList( maColRanges
, rRoot
.GetDoc().GetColNameRangesRef(), nScTab
);
542 void XclExpLabelranges::FillRangeList( ScRangeList
& rScRanges
,
543 const ScRangePairListRef
& xLabelRangesRef
, SCTAB nScTab
)
545 for ( size_t i
= 0, nPairs
= xLabelRangesRef
->size(); i
< nPairs
; ++i
)
547 ScRangePair
* pRangePair
= (*xLabelRangesRef
)[i
];
548 const ScRange
& rScRange
= pRangePair
->GetRange( 0 );
549 if( rScRange
.aStart
.Tab() == nScTab
)
550 rScRanges
.Append( rScRange
);
554 void XclExpLabelranges::Save( XclExpStream
& rStrm
)
556 XclExpAddressConverter
& rAddrConv
= GetAddressConverter();
557 XclRangeList aRowXclRanges
, aColXclRanges
;
558 rAddrConv
.ConvertRangeList( aRowXclRanges
, maRowRanges
, false );
559 rAddrConv
.ConvertRangeList( aColXclRanges
, maColRanges
, false );
560 if( !aRowXclRanges
.empty() || !aColXclRanges
.empty() )
562 rStrm
.StartRecord( EXC_ID_LABELRANGES
, 4 + 8 * (aRowXclRanges
.size() + aColXclRanges
.size()) );
563 rStrm
<< aRowXclRanges
<< aColXclRanges
;
568 // Conditional formatting ====================================================
570 /** Represents a CF record that contains one condition of a conditional format. */
571 class XclExpCFImpl
: protected XclExpRoot
574 explicit XclExpCFImpl( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
, sal_Int32 nPriority
= 0 );
576 /** Writes the body of the CF record. */
577 void WriteBody( XclExpStream
& rStrm
);
578 void SaveXml( XclExpXmlStream
& rStrm
);
581 const ScCondFormatEntry
& mrFormatEntry
; /// Calc conditional format entry.
582 XclFontData maFontData
; /// Font formatting attributes.
583 XclExpCellBorder maBorder
; /// Border formatting attributes.
584 XclExpCellArea maArea
; /// Pattern formatting attributes.
585 XclTokenArrayRef mxTokArr1
; /// Formula for first condition.
586 XclTokenArrayRef mxTokArr2
; /// Formula for second condition.
587 sal_uInt32 mnFontColorId
; /// Font color ID.
588 sal_uInt8 mnType
; /// Type of the condition (cell/formula).
589 sal_uInt8 mnOperator
; /// Comparison operator for cell type.
590 sal_Int32 mnPriority
; /// Priority of this entry; needed for oox export
591 bool mbFontUsed
; /// true = Any font attribute used.
592 bool mbHeightUsed
; /// true = Font height used.
593 bool mbWeightUsed
; /// true = Font weight used.
594 bool mbColorUsed
; /// true = Font color used.
595 bool mbUnderlUsed
; /// true = Font underline type used.
596 bool mbItalicUsed
; /// true = Font posture used.
597 bool mbStrikeUsed
; /// true = Font strikeout used.
598 bool mbBorderUsed
; /// true = Border attribute used.
599 bool mbPattUsed
; /// true = Pattern attribute used.
603 XclExpCFImpl::XclExpCFImpl( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
, sal_Int32 nPriority
) :
605 mrFormatEntry( rFormatEntry
),
607 mnType( EXC_CF_TYPE_CELL
),
608 mnOperator( EXC_CF_CMP_NONE
),
609 mnPriority( nPriority
),
611 mbHeightUsed( false ),
612 mbWeightUsed( false ),
613 mbColorUsed( false ),
614 mbUnderlUsed( false ),
615 mbItalicUsed( false ),
616 mbStrikeUsed( false ),
617 mbBorderUsed( false ),
621 /* Get formatting attributes here, and not in WriteBody(). This is needed to
622 correctly insert all colors into the palette. */
624 if( SfxStyleSheetBase
* pStyleSheet
= GetDoc().GetStyleSheetPool()->Find( mrFormatEntry
.GetStyle(), SfxStyleFamily::Para
) )
626 const SfxItemSet
& rItemSet
= pStyleSheet
->GetItemSet();
629 mbHeightUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_HEIGHT
, true );
630 mbWeightUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_WEIGHT
, true );
631 mbColorUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_COLOR
, true );
632 mbUnderlUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_UNDERLINE
, true );
633 mbItalicUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_POSTURE
, true );
634 mbStrikeUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_CROSSEDOUT
, true );
635 mbFontUsed
= mbHeightUsed
|| mbWeightUsed
|| mbColorUsed
|| mbUnderlUsed
|| mbItalicUsed
|| mbStrikeUsed
;
639 ScPatternAttr::GetFont( aFont
, rItemSet
, SC_AUTOCOL_RAW
);
640 maFontData
.FillFromVclFont( aFont
);
641 mnFontColorId
= GetPalette().InsertColor( maFontData
.maColor
, EXC_COLOR_CELLTEXT
);
645 mbBorderUsed
= ScfTools::CheckItem( rItemSet
, ATTR_BORDER
, true );
647 maBorder
.FillFromItemSet( rItemSet
, GetPalette(), GetBiff() );
650 mbPattUsed
= ScfTools::CheckItem( rItemSet
, ATTR_BACKGROUND
, true );
652 maArea
.FillFromItemSet( rItemSet
, GetPalette(), GetBiff() );
655 // *** mode and comparison operator ***
657 switch( rFormatEntry
.GetOperation() )
660 mnType
= EXC_CF_TYPE_NONE
;
662 case SC_COND_BETWEEN
:
663 mnOperator
= EXC_CF_CMP_BETWEEN
;
666 case SC_COND_NOTBETWEEN
:
667 mnOperator
= EXC_CF_CMP_NOT_BETWEEN
;
671 mnOperator
= EXC_CF_CMP_EQUAL
;
673 case SC_COND_NOTEQUAL
:
674 mnOperator
= EXC_CF_CMP_NOT_EQUAL
;
676 case SC_COND_GREATER
:
677 mnOperator
= EXC_CF_CMP_GREATER
;
680 mnOperator
= EXC_CF_CMP_LESS
;
682 case SC_COND_EQGREATER
:
683 mnOperator
= EXC_CF_CMP_GREATER_EQUAL
;
686 mnOperator
= EXC_CF_CMP_LESS_EQUAL
;
689 mnType
= EXC_CF_TYPE_FMLA
;
692 mnType
= EXC_CF_TYPE_NONE
;
693 OSL_FAIL( "XclExpCF::WriteBody - unknown condition type" );
697 void XclExpCFImpl::WriteBody( XclExpStream
& rStrm
)
702 XclExpFormulaCompiler
& rFmlaComp
= GetFormulaCompiler();
704 std::unique_ptr
< ScTokenArray
> xScTokArr( mrFormatEntry
.CreateFlatCopiedTokenArray( 0 ) );
705 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_CONDFMT
, *xScTokArr
);
709 xScTokArr
.reset( mrFormatEntry
.CreateFlatCopiedTokenArray( 1 ) );
710 mxTokArr2
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_CONDFMT
, *xScTokArr
);
713 // *** mode and comparison operator ***
715 rStrm
<< mnType
<< mnOperator
;
717 // *** formula sizes ***
719 sal_uInt16 nFmlaSize1
= mxTokArr1
.get() ? mxTokArr1
->GetSize() : 0;
720 sal_uInt16 nFmlaSize2
= mxTokArr2
.get() ? mxTokArr2
->GetSize() : 0;
721 rStrm
<< nFmlaSize1
<< nFmlaSize2
;
723 // *** formatting blocks ***
725 if( mbFontUsed
|| mbBorderUsed
|| mbPattUsed
)
727 sal_uInt32 nFlags
= EXC_CF_ALLDEFAULT
;
729 ::set_flag( nFlags
, EXC_CF_BLOCK_FONT
, mbFontUsed
);
730 ::set_flag( nFlags
, EXC_CF_BLOCK_BORDER
, mbBorderUsed
);
731 ::set_flag( nFlags
, EXC_CF_BLOCK_AREA
, mbPattUsed
);
733 // attributes used -> set flags to 0.
734 ::set_flag( nFlags
, EXC_CF_BORDER_ALL
, !mbBorderUsed
);
735 ::set_flag( nFlags
, EXC_CF_AREA_ALL
, !mbPattUsed
);
737 rStrm
<< nFlags
<< sal_uInt16( 0 );
741 // font height, 0xFFFFFFFF indicates unused
742 sal_uInt32 nHeight
= mbHeightUsed
? maFontData
.mnHeight
: 0xFFFFFFFF;
743 // font style: italic and strikeout
744 sal_uInt32 nStyle
= 0;
745 ::set_flag( nStyle
, EXC_CF_FONT_STYLE
, maFontData
.mbItalic
);
746 ::set_flag( nStyle
, EXC_CF_FONT_STRIKEOUT
, maFontData
.mbStrikeout
);
747 // font color, 0xFFFFFFFF indicates unused
748 sal_uInt32 nColor
= mbColorUsed
? GetPalette().GetColorIndex( mnFontColorId
) : 0xFFFFFFFF;
749 // font used flags for italic, weight, and strikeout -> 0 = used, 1 = default
750 sal_uInt32 nFontFlags1
= EXC_CF_FONT_ALLDEFAULT
;
751 ::set_flag( nFontFlags1
, EXC_CF_FONT_STYLE
, !(mbItalicUsed
|| mbWeightUsed
) );
752 ::set_flag( nFontFlags1
, EXC_CF_FONT_STRIKEOUT
, !mbStrikeUsed
);
753 // font used flag for underline -> 0 = used, 1 = default
754 sal_uInt32 nFontFlags3
= mbUnderlUsed
? 0 : EXC_CF_FONT_UNDERL
;
756 rStrm
.WriteZeroBytesToRecord( 64 );
759 << maFontData
.mnWeight
761 << maFontData
.mnUnderline
;
762 rStrm
.WriteZeroBytesToRecord( 3 );
766 << EXC_CF_FONT_ESCAPEM
// escapement never used -> set the flag
768 rStrm
.WriteZeroBytesToRecord( 16 );
769 rStrm
<< sal_uInt16( 1 ); // must be 1
774 sal_uInt16 nLineStyle
= 0;
775 sal_uInt32 nLineColor
= 0;
776 maBorder
.SetFinalColors( GetPalette() );
777 maBorder
.FillToCF8( nLineStyle
, nLineColor
);
778 rStrm
<< nLineStyle
<< nLineColor
<< sal_uInt16( 0 );
783 sal_uInt16 nPattern
= 0, nColor
= 0;
784 maArea
.SetFinalColors( GetPalette() );
785 maArea
.FillToCF8( nPattern
, nColor
);
786 rStrm
<< nPattern
<< nColor
;
791 // no data blocks at all
792 rStrm
<< sal_uInt32( 0 ) << sal_uInt16( 0 );
797 if( mxTokArr1
.get() )
798 mxTokArr1
->WriteArray( rStrm
);
799 if( mxTokArr2
.get() )
800 mxTokArr2
->WriteArray( rStrm
);
805 const char* GetOperatorString(ScConditionMode eMode
, bool& bFrmla2
)
807 const char *pRet
= nullptr;
816 case SC_COND_GREATER
:
817 pRet
= "greaterThan";
820 pRet
= "lessThanOrEqual";
822 case SC_COND_EQGREATER
:
823 pRet
= "greaterThanOrEqual";
825 case SC_COND_NOTEQUAL
:
828 case SC_COND_BETWEEN
:
832 case SC_COND_NOTBETWEEN
:
836 case SC_COND_DUPLICATE
:
839 case SC_COND_NOTDUPLICATE
:
851 const char* GetTypeString(ScConditionMode eMode
)
858 case SC_COND_TOP_PERCENT
:
859 case SC_COND_BOTTOM10
:
860 case SC_COND_BOTTOM_PERCENT
:
862 case SC_COND_ABOVE_AVERAGE
:
863 case SC_COND_BELOW_AVERAGE
:
864 case SC_COND_ABOVE_EQUAL_AVERAGE
:
865 case SC_COND_BELOW_EQUAL_AVERAGE
:
866 return "aboveAverage";
867 case SC_COND_NOTDUPLICATE
:
868 return "uniqueValues";
869 case SC_COND_DUPLICATE
:
870 return "duplicateValues";
872 return "containsErrors";
873 case SC_COND_NOERROR
:
874 return "notContainsErrors";
875 case SC_COND_BEGINS_WITH
:
877 case SC_COND_ENDS_WITH
:
879 case SC_COND_CONTAINS_TEXT
:
880 return "containsText";
881 case SC_COND_NOT_CONTAINS_TEXT
:
882 return "notContainsText";
888 bool IsTopBottomRule(ScConditionMode eMode
)
893 case SC_COND_BOTTOM10
:
894 case SC_COND_TOP_PERCENT
:
895 case SC_COND_BOTTOM_PERCENT
:
904 bool IsTextRule(ScConditionMode eMode
)
908 case SC_COND_BEGINS_WITH
:
909 case SC_COND_ENDS_WITH
:
910 case SC_COND_CONTAINS_TEXT
:
911 case SC_COND_NOT_CONTAINS_TEXT
:
922 void XclExpCFImpl::SaveXml( XclExpXmlStream
& rStrm
)
925 ScConditionMode eOperation
= mrFormatEntry
.GetOperation();
926 bool bAboveAverage
= eOperation
== SC_COND_ABOVE_AVERAGE
||
927 eOperation
== SC_COND_ABOVE_EQUAL_AVERAGE
;
928 bool bEqualAverage
= eOperation
== SC_COND_ABOVE_EQUAL_AVERAGE
||
929 eOperation
== SC_COND_BELOW_EQUAL_AVERAGE
;
930 bool bBottom
= eOperation
== SC_COND_BOTTOM10
931 || eOperation
== SC_COND_BOTTOM_PERCENT
;
932 bool bPercent
= eOperation
== SC_COND_TOP_PERCENT
||
933 eOperation
== SC_COND_BOTTOM_PERCENT
;
935 if(IsTopBottomRule(eOperation
))
937 // position and formula grammar are not important
938 // we only store a number there
939 aRank
= XclXmlUtils::ToOString(mrFormatEntry
.GetExpression(ScAddress(0,0,0), 0));
942 if(IsTextRule(eOperation
))
944 // we need to write the text without quotes
945 // we have to actually get the string from
946 // the token array for that
947 std::unique_ptr
<ScTokenArray
> pTokenArray(mrFormatEntry
.CreateFlatCopiedTokenArray(0));
948 if(pTokenArray
->GetLen())
949 aText
= XclXmlUtils::ToOString(pTokenArray
->First()->GetString().getString());
952 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
953 rWorksheet
->startElement( XML_cfRule
,
954 XML_type
, GetTypeString( mrFormatEntry
.GetOperation() ),
955 XML_priority
, OString::number( mnPriority
+ 1 ).getStr(),
956 XML_operator
, GetOperatorString( mrFormatEntry
.GetOperation(), bFmla2
),
957 XML_aboveAverage
, OString::number( int(bAboveAverage
) ).getStr(),
958 XML_equalAverage
, OString::number( int(bEqualAverage
) ).getStr(),
959 XML_bottom
, OString::number( int(bBottom
) ).getStr(),
960 XML_percent
, OString::number( int(bPercent
) ).getStr(),
961 XML_rank
, aRank
.getStr(),
962 XML_text
, aText
.getStr(),
963 XML_dxfId
, OString::number( GetDxfs().GetDxfId( mrFormatEntry
.GetStyle() ) ).getStr(),
965 if(!IsTextRule(eOperation
) && !IsTopBottomRule(eOperation
))
967 rWorksheet
->startElement( XML_formula
, FSEND
);
968 std::unique_ptr
<ScTokenArray
> pTokenArray(mrFormatEntry
.CreateFlatCopiedTokenArray(0));
969 rWorksheet
->writeEscaped(XclXmlUtils::ToOUString( GetCompileFormulaContext(), mrFormatEntry
.GetValidSrcPos(),
971 rWorksheet
->endElement( XML_formula
);
974 rWorksheet
->startElement( XML_formula
, FSEND
);
975 std::unique_ptr
<ScTokenArray
> pTokenArray2(mrFormatEntry
.CreateFlatCopiedTokenArray(1));
976 rWorksheet
->writeEscaped(XclXmlUtils::ToOUString( GetCompileFormulaContext(), mrFormatEntry
.GetValidSrcPos(),
977 pTokenArray2
.get()));
978 rWorksheet
->endElement( XML_formula
);
981 // OOXTODO: XML_extLst
982 rWorksheet
->endElement( XML_cfRule
);
985 XclExpCF::XclExpCF( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
, sal_Int32 nPriority
= 0 ) :
986 XclExpRecord( EXC_ID_CF
),
988 mxImpl( new XclExpCFImpl( rRoot
, rFormatEntry
, nPriority
) )
992 XclExpCF::~XclExpCF()
996 void XclExpCF::WriteBody( XclExpStream
& rStrm
)
998 mxImpl
->WriteBody( rStrm
);
1001 void XclExpCF::SaveXml( XclExpXmlStream
& rStrm
)
1003 mxImpl
->SaveXml( rStrm
);
1006 XclExpDateFormat::XclExpDateFormat( const XclExpRoot
& rRoot
, const ScCondDateFormatEntry
& rFormatEntry
, sal_Int32 nPriority
):
1007 XclExpRecord( EXC_ID_CF
),
1008 XclExpRoot( rRoot
),
1009 mrFormatEntry(rFormatEntry
),
1010 mnPriority(nPriority
)
1014 XclExpDateFormat::~XclExpDateFormat()
1020 const char* getTimePeriodString( condformat::ScCondFormatDateType eType
)
1024 case condformat::TODAY
:
1026 case condformat::YESTERDAY
:
1028 case condformat::TOMORROW
:
1030 case condformat::THISWEEK
:
1032 case condformat::LASTWEEK
:
1034 case condformat::NEXTWEEK
:
1036 case condformat::THISMONTH
:
1038 case condformat::LASTMONTH
:
1040 case condformat::NEXTMONTH
:
1042 case condformat::LAST7DAYS
:
1052 void XclExpDateFormat::SaveXml( XclExpXmlStream
& rStrm
)
1054 // only write the supported entries into OOXML
1055 const char* sTimePeriod
= getTimePeriodString(mrFormatEntry
.GetDateType());
1059 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1060 rWorksheet
->startElement( XML_cfRule
,
1061 XML_type
, "timePeriod",
1062 XML_priority
, OString::number( mnPriority
+ 1 ).getStr(),
1063 XML_timePeriod
, sTimePeriod
,
1064 XML_dxfId
, OString::number( GetDxfs().GetDxfId( mrFormatEntry
.GetStyleName() ) ).getStr(),
1066 rWorksheet
->endElement( XML_cfRule
);
1069 XclExpCfvo::XclExpCfvo(const XclExpRoot
& rRoot
, const ScColorScaleEntry
& rEntry
, const ScAddress
& rAddr
, bool bFirst
):
1071 XclExpRoot( rRoot
),
1080 OString
getColorScaleType( const ScColorScaleEntry
& rEntry
, bool bFirst
)
1082 switch(rEntry
.GetType())
1084 case COLORSCALE_MIN
:
1086 case COLORSCALE_MAX
:
1088 case COLORSCALE_PERCENT
:
1090 case COLORSCALE_FORMULA
:
1092 case COLORSCALE_AUTO
:
1097 case COLORSCALE_PERCENTILE
:
1098 return "percentile";
1108 void XclExpCfvo::SaveXml( XclExpXmlStream
& rStrm
)
1110 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1113 if(mrEntry
.GetType() == COLORSCALE_FORMULA
)
1115 OUString aFormula
= XclXmlUtils::ToOUString( GetCompileFormulaContext(), maSrcPos
,
1116 mrEntry
.GetFormula());
1117 aValue
= OUStringToOString(aFormula
, RTL_TEXTENCODING_UTF8
);
1121 aValue
= OString::number( mrEntry
.GetValue() );
1124 rWorksheet
->startElement( XML_cfvo
,
1125 XML_type
, getColorScaleType(mrEntry
, mbFirst
).getStr(),
1126 XML_val
, aValue
.getStr(),
1129 rWorksheet
->endElement( XML_cfvo
);
1132 XclExpColScaleCol::XclExpColScaleCol( const XclExpRoot
& rRoot
, const Color
& rColor
):
1134 XclExpRoot( rRoot
),
1139 XclExpColScaleCol::~XclExpColScaleCol()
1143 void XclExpColScaleCol::SaveXml( XclExpXmlStream
& rStrm
)
1145 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1147 rWorksheet
->startElement( XML_color
,
1148 XML_rgb
, XclXmlUtils::ToOString( mrColor
).getStr(),
1151 rWorksheet
->endElement( XML_color
);
1156 OString
createHexStringFromDigit(sal_uInt8 nDigit
)
1158 OString aString
= OString::number( nDigit
, 16 );
1159 if(aString
.getLength() == 1)
1160 aString
= aString
+ OString::number(0);
1164 OString
createGuidStringFromInt(sal_uInt8 nGuid
[16])
1166 OStringBuffer aBuffer
;
1167 aBuffer
.append('{');
1168 for(size_t i
= 0; i
< 16; ++i
)
1170 aBuffer
.append(createHexStringFromDigit(nGuid
[i
]));
1171 if(i
== 3|| i
== 5 || i
== 7 || i
== 9 )
1172 aBuffer
.append('-');
1174 aBuffer
.append('}');
1175 OString aString
= aBuffer
.makeStringAndClear();
1176 return aString
.toAsciiUpperCase();
1179 OString
generateGUIDString()
1181 sal_uInt8 nGuid
[16];
1182 rtl_createUuid(nGuid
, nullptr, true);
1183 return createGuidStringFromInt(nGuid
);
1188 XclExpCondfmt::XclExpCondfmt( const XclExpRoot
& rRoot
, const ScConditionalFormat
& rCondFormat
, XclExtLstRef xExtLst
, sal_Int32
& rIndex
) :
1189 XclExpRecord( EXC_ID_CONDFMT
),
1192 const ScRangeList
& aScRanges
= rCondFormat
.GetRange();
1193 GetAddressConverter().ConvertRangeList( maXclRanges
, aScRanges
, true );
1194 if( !maXclRanges
.empty() )
1196 std::vector
<XclExpExtCondFormatData
> aExtEntries
;
1197 for( size_t nIndex
= 0, nCount
= rCondFormat
.size(); nIndex
< nCount
; ++nIndex
)
1198 if( const ScFormatEntry
* pFormatEntry
= rCondFormat
.GetEntry( nIndex
) )
1200 if(pFormatEntry
->GetType() == condformat::CONDITION
)
1201 maCFList
.AppendNewRecord( new XclExpCF( GetRoot(), static_cast<const ScCondFormatEntry
&>(*pFormatEntry
), ++rIndex
) );
1202 else if(pFormatEntry
->GetType() == condformat::COLORSCALE
)
1203 maCFList
.AppendNewRecord( new XclExpColorScale( GetRoot(), static_cast<const ScColorScaleFormat
&>(*pFormatEntry
), ++rIndex
) );
1204 else if(pFormatEntry
->GetType() == condformat::DATABAR
)
1206 const ScDataBarFormat
& rFormat
= static_cast<const ScDataBarFormat
&>(*pFormatEntry
);
1207 XclExpExtCondFormatData aExtEntry
;
1208 aExtEntry
.nPriority
= -1;
1209 aExtEntry
.aGUID
= generateGUIDString();
1210 aExtEntry
.pEntry
= &rFormat
;
1211 aExtEntries
.push_back(aExtEntry
);
1213 maCFList
.AppendNewRecord( new XclExpDataBar( GetRoot(), rFormat
, ++rIndex
, aExtEntry
.aGUID
));
1215 else if(pFormatEntry
->GetType() == condformat::ICONSET
)
1217 // don't export iconSet entries that are not in OOXML
1218 const ScIconSetFormat
& rIconSet
= static_cast<const ScIconSetFormat
&>(*pFormatEntry
);
1219 bool bNeedsExt
= false;
1220 switch (rIconSet
.GetIconSetData()->eIconSetType
)
1222 case IconSet_3Smilies
:
1223 case IconSet_3ColorSmilies
:
1224 case IconSet_3Stars
:
1225 case IconSet_3Triangles
:
1226 case IconSet_5Boxes
:
1235 bNeedsExt
|= rIconSet
.GetIconSetData()->mbCustom
;
1239 XclExpExtCondFormatData aExtEntry
;
1240 aExtEntry
.nPriority
= ++rIndex
;
1241 aExtEntry
.aGUID
= generateGUIDString();
1242 aExtEntry
.pEntry
= &rIconSet
;
1243 aExtEntries
.push_back(aExtEntry
);
1246 maCFList
.AppendNewRecord( new XclExpIconSet( GetRoot(), rIconSet
, ++rIndex
) );
1248 else if(pFormatEntry
->GetType() == condformat::DATE
)
1249 maCFList
.AppendNewRecord( new XclExpDateFormat( GetRoot(), static_cast<const ScCondDateFormatEntry
&>(*pFormatEntry
), ++rIndex
) );
1251 aScRanges
.Format( msSeqRef
, ScRefFlags::VALID
, nullptr, formula::FormulaGrammar::CONV_XL_OOX
, ' ' );
1253 if(!aExtEntries
.empty() && xExtLst
.get())
1255 XclExpExtRef pParent
= xExtLst
->GetItem( XclExpExtDataBarType
);
1256 if( !pParent
.get() )
1258 xExtLst
->AddRecord( XclExpExtRef(new XclExpExtCondFormat( *xExtLst
.get() )) );
1259 pParent
= xExtLst
->GetItem( XclExpExtDataBarType
);
1261 static_cast<XclExpExtCondFormat
*>(xExtLst
->GetItem( XclExpExtDataBarType
).get())->AddRecord(
1262 std::make_shared
<XclExpExtConditionalFormatting
>( *pParent
, aExtEntries
, aScRanges
));
1267 XclExpCondfmt::~XclExpCondfmt()
1271 bool XclExpCondfmt::IsValid() const
1273 return !maCFList
.IsEmpty() && !maXclRanges
.empty();
1276 void XclExpCondfmt::Save( XclExpStream
& rStrm
)
1280 XclExpRecord::Save( rStrm
);
1281 maCFList
.Save( rStrm
);
1285 void XclExpCondfmt::WriteBody( XclExpStream
& rStrm
)
1287 OSL_ENSURE( !maCFList
.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
1288 OSL_ENSURE( !maXclRanges
.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
1290 rStrm
<< static_cast< sal_uInt16
>( maCFList
.GetSize() )
1292 << maXclRanges
.GetEnclosingRange()
1296 void XclExpCondfmt::SaveXml( XclExpXmlStream
& rStrm
)
1301 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1302 rWorksheet
->startElement( XML_conditionalFormatting
,
1303 XML_sqref
, XclXmlUtils::ToOString( msSeqRef
).getStr(),
1304 // OOXTODO: XML_pivot,
1307 maCFList
.SaveXml( rStrm
);
1309 rWorksheet
->endElement( XML_conditionalFormatting
);
1312 XclExpColorScale::XclExpColorScale( const XclExpRoot
& rRoot
, const ScColorScaleFormat
& rFormat
, sal_Int32 nPriority
):
1314 XclExpRoot( rRoot
),
1315 mnPriority( nPriority
)
1317 const ScRange
* pRange
= rFormat
.GetRange().front();
1318 ScAddress aAddr
= pRange
->aStart
;
1319 for(ScColorScaleEntries::const_iterator itr
= rFormat
.begin();
1320 itr
!= rFormat
.end(); ++itr
)
1322 // exact position is not important, we allow only absolute refs
1324 XclExpCfvoList::RecordRefType
xCfvo( new XclExpCfvo( GetRoot(), *itr
[0], aAddr
) );
1325 maCfvoList
.AppendRecord( xCfvo
);
1326 XclExpColScaleColList::RecordRefType
xClo( new XclExpColScaleCol( GetRoot(), itr
[0]->GetColor() ) );
1327 maColList
.AppendRecord( xClo
);
1331 void XclExpColorScale::SaveXml( XclExpXmlStream
& rStrm
)
1333 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1335 rWorksheet
->startElement( XML_cfRule
,
1336 XML_type
, "colorScale",
1337 XML_priority
, OString::number( mnPriority
+ 1 ).getStr(),
1340 rWorksheet
->startElement( XML_colorScale
, FSEND
);
1342 maCfvoList
.SaveXml(rStrm
);
1343 maColList
.SaveXml(rStrm
);
1345 rWorksheet
->endElement( XML_colorScale
);
1347 rWorksheet
->endElement( XML_cfRule
);
1350 XclExpDataBar::XclExpDataBar( const XclExpRoot
& rRoot
, const ScDataBarFormat
& rFormat
, sal_Int32 nPriority
, const OString
& rGUID
):
1352 XclExpRoot( rRoot
),
1353 mrFormat( rFormat
),
1354 mnPriority( nPriority
),
1357 const ScRange
* pRange
= rFormat
.GetRange().front();
1358 ScAddress aAddr
= pRange
->aStart
;
1359 // exact position is not important, we allow only absolute refs
1360 mpCfvoLowerLimit
.reset( new XclExpCfvo( GetRoot(), *mrFormat
.GetDataBarData()->mpLowerLimit
.get(), aAddr
, true ) );
1361 mpCfvoUpperLimit
.reset( new XclExpCfvo( GetRoot(), *mrFormat
.GetDataBarData()->mpUpperLimit
.get(), aAddr
, false ) );
1363 mpCol
.reset( new XclExpColScaleCol( GetRoot(), mrFormat
.GetDataBarData()->maPositiveColor
) );
1366 void XclExpDataBar::SaveXml( XclExpXmlStream
& rStrm
)
1368 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1370 rWorksheet
->startElement( XML_cfRule
,
1371 XML_type
, "dataBar",
1372 XML_priority
, OString::number( mnPriority
+ 1 ).getStr(),
1375 rWorksheet
->startElement( XML_dataBar
,
1376 XML_showValue
, OString::number(int(!mrFormat
.GetDataBarData()->mbOnlyBar
)),
1377 XML_minLength
, OString::number(sal_uInt32(mrFormat
.GetDataBarData()->mnMinLength
)),
1378 XML_maxLength
, OString::number(sal_uInt32(mrFormat
.GetDataBarData()->mnMaxLength
)),
1381 mpCfvoLowerLimit
->SaveXml(rStrm
);
1382 mpCfvoUpperLimit
->SaveXml(rStrm
);
1383 mpCol
->SaveXml(rStrm
);
1385 rWorksheet
->endElement( XML_dataBar
);
1387 // extLst entries for Excel 2010 and 2013
1388 rWorksheet
->startElement( XML_extLst
, FSEND
);
1389 rWorksheet
->startElement( XML_ext
,
1390 FSNS( XML_xmlns
, XML_x14
), "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
1391 XML_uri
, "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}",
1394 rWorksheet
->startElementNS( XML_x14
, XML_id
, FSEND
);
1395 rWorksheet
->write( maGUID
.getStr() );
1396 rWorksheet
->endElementNS( XML_x14
, XML_id
);
1398 rWorksheet
->endElement( XML_ext
);
1399 rWorksheet
->endElement( XML_extLst
);
1401 rWorksheet
->endElement( XML_cfRule
);
1404 XclExpIconSet::XclExpIconSet( const XclExpRoot
& rRoot
, const ScIconSetFormat
& rFormat
, sal_Int32 nPriority
):
1406 XclExpRoot( rRoot
),
1407 mrFormat( rFormat
),
1408 mnPriority( nPriority
)
1410 const ScRange
* pRange
= rFormat
.GetRange().front();
1411 ScAddress aAddr
= pRange
->aStart
;
1412 for (auto const& itr
: rFormat
)
1414 // exact position is not important, we allow only absolute refs
1416 XclExpCfvoList::RecordRefType
xCfvo( new XclExpCfvo( GetRoot(), *itr
, aAddr
) );
1417 maCfvoList
.AppendRecord( xCfvo
);
1423 const char* getIconSetName( ScIconSetType eType
)
1425 ScIconSetMap
* pMap
= ScIconSetFormat::getIconSetMap();
1426 for(; pMap
->pName
; ++pMap
)
1428 if(pMap
->eType
== eType
)
1437 void XclExpIconSet::SaveXml( XclExpXmlStream
& rStrm
)
1439 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1441 rWorksheet
->startElement( XML_cfRule
,
1442 XML_type
, "iconSet",
1443 XML_priority
, OString::number( mnPriority
+ 1 ).getStr(),
1446 const char* pIconSetName
= getIconSetName(mrFormat
.GetIconSetData()->eIconSetType
);
1447 rWorksheet
->startElement( XML_iconSet
,
1448 XML_iconSet
, pIconSetName
,
1449 XML_showValue
, mrFormat
.GetIconSetData()->mbShowValue
? nullptr : "0",
1450 XML_reverse
, mrFormat
.GetIconSetData()->mbReverse
? "1" : nullptr,
1453 maCfvoList
.SaveXml( rStrm
);
1455 rWorksheet
->endElement( XML_iconSet
);
1456 rWorksheet
->endElement( XML_cfRule
);
1459 XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot
& rRoot
, XclExtLstRef xExtLst
) :
1462 if( const ScConditionalFormatList
* pCondFmtList
= GetDoc().GetCondFormList(GetCurrScTab()) )
1464 sal_Int32 nIndex
= 0;
1465 for( ScConditionalFormatList::const_iterator itr
= pCondFmtList
->begin();
1466 itr
!= pCondFmtList
->end(); ++itr
)
1468 XclExpCondfmtList::RecordRefType
xCondfmtRec( new XclExpCondfmt( GetRoot(), **itr
, xExtLst
, nIndex
));
1469 if( xCondfmtRec
->IsValid() )
1470 maCondfmtList
.AppendRecord( xCondfmtRec
);
1475 void XclExpCondFormatBuffer::Save( XclExpStream
& rStrm
)
1477 maCondfmtList
.Save( rStrm
);
1480 void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream
& rStrm
)
1482 maCondfmtList
.SaveXml( rStrm
);
1485 // Validation =================================================================
1489 /** Writes a formula for the DV record. */
1490 void lclWriteDvFormula( XclExpStream
& rStrm
, const XclTokenArray
* pXclTokArr
)
1492 sal_uInt16 nFmlaSize
= pXclTokArr
? pXclTokArr
->GetSize() : 0;
1493 rStrm
<< nFmlaSize
<< sal_uInt16( 0 );
1495 pXclTokArr
->WriteArray( rStrm
);
1498 /** Writes a formula for the DV record, based on a single string. */
1499 void lclWriteDvFormula( XclExpStream
& rStrm
, const XclExpString
& rString
)
1501 // fake a formula with a single tStr token
1502 rStrm
<< static_cast< sal_uInt16
>( rString
.GetSize() + 1 )
1508 const char* lcl_GetValidationType( sal_uInt32 nFlags
)
1510 switch( nFlags
& EXC_DV_MODE_MASK
)
1512 case EXC_DV_MODE_ANY
: return "none";
1513 case EXC_DV_MODE_WHOLE
: return "whole";
1514 case EXC_DV_MODE_DECIMAL
: return "decimal";
1515 case EXC_DV_MODE_LIST
: return "list";
1516 case EXC_DV_MODE_DATE
: return "date";
1517 case EXC_DV_MODE_TIME
: return "time";
1518 case EXC_DV_MODE_TEXTLEN
: return "textLength";
1519 case EXC_DV_MODE_CUSTOM
: return "custom";
1524 const char* lcl_GetOperatorType( sal_uInt32 nFlags
)
1526 switch( nFlags
& EXC_DV_COND_MASK
)
1528 case EXC_DV_COND_BETWEEN
: return "between";
1529 case EXC_DV_COND_NOTBETWEEN
: return "notBetween";
1530 case EXC_DV_COND_EQUAL
: return "equal";
1531 case EXC_DV_COND_NOTEQUAL
: return "notEqual";
1532 case EXC_DV_COND_GREATER
: return "greaterThan";
1533 case EXC_DV_COND_LESS
: return "lessThan";
1534 case EXC_DV_COND_EQGREATER
: return "greaterThanOrEqual";
1535 case EXC_DV_COND_EQLESS
: return "lessThanOrEqual";
1542 XclExpDV::XclExpDV( const XclExpRoot
& rRoot
, sal_uLong nScHandle
) :
1543 XclExpRecord( EXC_ID_DV
),
1544 XclExpRoot( rRoot
),
1546 mnScHandle( nScHandle
)
1548 if( const ScValidationData
* pValData
= GetDoc().GetValidationEntry( mnScHandle
) )
1550 // prompt box - empty string represented by single NUL character
1551 OUString aTitle
, aText
;
1552 bool bShowPrompt
= pValData
->GetInput( aTitle
, aText
);
1553 if( !aTitle
.isEmpty() )
1554 maPromptTitle
.Assign( aTitle
);
1556 maPromptTitle
.Assign( '\0' );
1557 if( !aText
.isEmpty() )
1558 maPromptText
.Assign( aText
);
1560 maPromptText
.Assign( '\0' );
1562 // error box - empty string represented by single NUL character
1563 ScValidErrorStyle eScErrorStyle
;
1564 bool bShowError
= pValData
->GetErrMsg( aTitle
, aText
, eScErrorStyle
);
1565 if( !aTitle
.isEmpty() )
1566 maErrorTitle
.Assign( aTitle
);
1568 maErrorTitle
.Assign( '\0' );
1569 if( !aText
.isEmpty() )
1570 maErrorText
.Assign( aText
);
1572 maErrorText
.Assign( '\0' );
1575 switch( pValData
->GetDataMode() )
1577 case SC_VALID_ANY
: mnFlags
|= EXC_DV_MODE_ANY
; break;
1578 case SC_VALID_WHOLE
: mnFlags
|= EXC_DV_MODE_WHOLE
; break;
1579 case SC_VALID_DECIMAL
: mnFlags
|= EXC_DV_MODE_DECIMAL
; break;
1580 case SC_VALID_LIST
: mnFlags
|= EXC_DV_MODE_LIST
; break;
1581 case SC_VALID_DATE
: mnFlags
|= EXC_DV_MODE_DATE
; break;
1582 case SC_VALID_TIME
: mnFlags
|= EXC_DV_MODE_TIME
; break;
1583 case SC_VALID_TEXTLEN
: mnFlags
|= EXC_DV_MODE_TEXTLEN
; break;
1584 case SC_VALID_CUSTOM
: mnFlags
|= EXC_DV_MODE_CUSTOM
; break;
1585 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown mode" );
1588 switch( pValData
->GetOperation() )
1591 case SC_COND_EQUAL
: mnFlags
|= EXC_DV_COND_EQUAL
; break;
1592 case SC_COND_LESS
: mnFlags
|= EXC_DV_COND_LESS
; break;
1593 case SC_COND_GREATER
: mnFlags
|= EXC_DV_COND_GREATER
; break;
1594 case SC_COND_EQLESS
: mnFlags
|= EXC_DV_COND_EQLESS
; break;
1595 case SC_COND_EQGREATER
: mnFlags
|= EXC_DV_COND_EQGREATER
; break;
1596 case SC_COND_NOTEQUAL
: mnFlags
|= EXC_DV_COND_NOTEQUAL
; break;
1597 case SC_COND_BETWEEN
: mnFlags
|= EXC_DV_COND_BETWEEN
; break;
1598 case SC_COND_NOTBETWEEN
: mnFlags
|= EXC_DV_COND_NOTBETWEEN
; break;
1599 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown condition" );
1601 switch( eScErrorStyle
)
1603 case SC_VALERR_STOP
: mnFlags
|= EXC_DV_ERROR_STOP
; break;
1604 case SC_VALERR_WARNING
: mnFlags
|= EXC_DV_ERROR_WARNING
; break;
1605 case SC_VALERR_INFO
: mnFlags
|= EXC_DV_ERROR_INFO
; break;
1606 case SC_VALERR_MACRO
:
1607 // set INFO for validity with macro call, delete title
1608 mnFlags
|= EXC_DV_ERROR_INFO
;
1609 maErrorTitle
.Assign( '\0' ); // contains macro name
1611 default: OSL_FAIL( "XclExpDV::XclExpDV - unknown error style" );
1613 ::set_flag( mnFlags
, EXC_DV_IGNOREBLANK
, pValData
->IsIgnoreBlank() );
1614 ::set_flag( mnFlags
, EXC_DV_SUPPRESSDROPDOWN
, pValData
->GetListType() == css::sheet::TableValidationVisibility::INVISIBLE
);
1615 ::set_flag( mnFlags
, EXC_DV_SHOWPROMPT
, bShowPrompt
);
1616 ::set_flag( mnFlags
, EXC_DV_SHOWERROR
, bShowError
);
1619 XclExpFormulaCompiler
& rFmlaComp
= GetFormulaCompiler();
1620 std::unique_ptr
< ScTokenArray
> xScTokArr
;
1623 xScTokArr
.reset( pValData
->CreateFlatCopiedTokenArray( 0 ) );
1624 if( xScTokArr
.get() )
1626 if( pValData
->GetDataMode() == SC_VALID_LIST
)
1629 if( XclTokenArrayHelper::GetStringList( aString
, *xScTokArr
, '\n' ) )
1631 OUStringBuffer sFormulaBuf
;
1632 sFormulaBuf
.append( '"' );
1633 /* Formula is a list of string tokens -> build the Excel string.
1634 Data validity is BIFF8 only (important for the XclExpString object).
1635 Excel uses the NUL character as string list separator. */
1636 mxString1
.reset( new XclExpString( EXC_STR_8BITLENGTH
) );
1637 sal_Int32 nTokenCnt
= comphelper::string::getTokenCount(aString
, '\n');
1638 sal_Int32 nStringIx
= 0;
1639 for( sal_Int32 nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
1641 OUString
aToken( aString
.getToken( 0, '\n', nStringIx
) );
1644 mxString1
->Append(OUString(static_cast<sal_Unicode
>('\0')));
1645 sFormulaBuf
.append( ',' );
1647 mxString1
->Append( aToken
);
1648 sFormulaBuf
.append( aToken
);
1650 ::set_flag( mnFlags
, EXC_DV_STRINGLIST
);
1652 sFormulaBuf
.append( '"' );
1653 msFormula1
= sFormulaBuf
.makeStringAndClear();
1657 /* All other formulas in validation are stored like conditional
1658 formatting formulas (with tRefN/tAreaN tokens as value or
1659 array class). But NOT the cell references and defined names
1660 in list validation - they are stored as reference class
1662 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
1663 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
1664 Formula compiler supports this by offering two different functions
1665 CreateDataValFormula() and CreateListValFormula(). */
1666 if(GetOutput() == EXC_OUTPUT_BINARY
)
1667 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_LISTVAL
, *xScTokArr
);
1669 msFormula1
= XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData
->GetSrcPos(),
1675 // no list validation -> convert the formula
1676 if(GetOutput() == EXC_OUTPUT_BINARY
)
1677 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_DATAVAL
, *xScTokArr
);
1679 msFormula1
= XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData
->GetSrcPos(),
1685 xScTokArr
.reset( pValData
->CreateFlatCopiedTokenArray( 1 ) );
1686 if( xScTokArr
.get() )
1688 if(GetOutput() == EXC_OUTPUT_BINARY
)
1689 mxTokArr2
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_DATAVAL
, *xScTokArr
);
1691 msFormula2
= XclXmlUtils::ToOUString( GetCompileFormulaContext(), pValData
->GetSrcPos(),
1697 OSL_FAIL( "XclExpDV::XclExpDV - missing core data" );
1698 mnScHandle
= ULONG_MAX
;
1702 XclExpDV::~XclExpDV()
1706 void XclExpDV::InsertCellRange( const ScRange
& rRange
)
1708 maScRanges
.Join( rRange
);
1711 bool XclExpDV::Finalize()
1713 GetAddressConverter().ConvertRangeList( maXclRanges
, maScRanges
, true );
1714 return (mnScHandle
!= ULONG_MAX
) && !maXclRanges
.empty();
1717 void XclExpDV::WriteBody( XclExpStream
& rStrm
)
1719 // flags and strings
1720 rStrm
<< mnFlags
<< maPromptTitle
<< maErrorTitle
<< maPromptText
<< maErrorText
;
1721 // condition formulas
1722 if( mxString1
.get() )
1723 lclWriteDvFormula( rStrm
, *mxString1
);
1725 lclWriteDvFormula( rStrm
, mxTokArr1
.get() );
1726 lclWriteDvFormula( rStrm
, mxTokArr2
.get() );
1728 rStrm
<< maXclRanges
;
1731 void XclExpDV::SaveXml( XclExpXmlStream
& rStrm
)
1733 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1734 rWorksheet
->startElement( XML_dataValidation
,
1735 XML_allowBlank
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_IGNOREBLANK
) ),
1736 XML_error
, XESTRING_TO_PSZ( maErrorText
),
1737 // OOXTODO: XML_errorStyle,
1738 XML_errorTitle
, XESTRING_TO_PSZ( maErrorTitle
),
1739 // OOXTODO: XML_imeMode,
1740 XML_operator
, lcl_GetOperatorType( mnFlags
),
1741 XML_prompt
, XESTRING_TO_PSZ( maPromptText
),
1742 XML_promptTitle
, XESTRING_TO_PSZ( maPromptTitle
),
1743 // showDropDown should have been showNoDropDown - check oox/xlsx import for details
1744 XML_showDropDown
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_SUPPRESSDROPDOWN
) ),
1745 XML_showErrorMessage
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_SHOWERROR
) ),
1746 XML_showInputMessage
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_SHOWPROMPT
) ),
1747 XML_sqref
, XclXmlUtils::ToOString( maScRanges
).getStr(),
1748 XML_type
, lcl_GetValidationType( mnFlags
),
1750 if( !msFormula1
.isEmpty() )
1752 rWorksheet
->startElement( XML_formula1
, FSEND
);
1753 rWorksheet
->writeEscaped( msFormula1
);
1754 rWorksheet
->endElement( XML_formula1
);
1756 if( !msFormula2
.isEmpty() )
1758 rWorksheet
->startElement( XML_formula2
, FSEND
);
1759 rWorksheet
->writeEscaped( msFormula2
);
1760 rWorksheet
->endElement( XML_formula2
);
1762 rWorksheet
->endElement( XML_dataValidation
);
1765 XclExpDval::XclExpDval( const XclExpRoot
& rRoot
) :
1766 XclExpRecord( EXC_ID_DVAL
, 18 ),
1771 XclExpDval::~XclExpDval()
1775 void XclExpDval::InsertCellRange( const ScRange
& rRange
, sal_uLong nScHandle
)
1777 if( GetBiff() == EXC_BIFF8
)
1779 XclExpDV
& rDVRec
= SearchOrCreateDv( nScHandle
);
1780 rDVRec
.InsertCellRange( rRange
);
1784 void XclExpDval::Save( XclExpStream
& rStrm
)
1786 // check all records
1787 size_t nPos
= maDVList
.GetSize();
1790 --nPos
; // backwards to keep nPos valid
1791 XclExpDVRef xDVRec
= maDVList
.GetRecord( nPos
);
1792 if( !xDVRec
->Finalize() )
1793 maDVList
.RemoveRecord( nPos
);
1796 // write the DVAL and the DV's
1797 if( !maDVList
.IsEmpty() )
1799 XclExpRecord::Save( rStrm
);
1800 maDVList
.Save( rStrm
);
1804 void XclExpDval::SaveXml( XclExpXmlStream
& rStrm
)
1806 if( maDVList
.IsEmpty() )
1809 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1810 rWorksheet
->startElement( XML_dataValidations
,
1811 XML_count
, OString::number( maDVList
.GetSize() ).getStr(),
1812 // OOXTODO: XML_disablePrompts,
1813 // OOXTODO: XML_xWindow,
1814 // OOXTODO: XML_yWindow,
1816 maDVList
.SaveXml( rStrm
);
1817 rWorksheet
->endElement( XML_dataValidations
);
1820 XclExpDV
& XclExpDval::SearchOrCreateDv( sal_uLong nScHandle
)
1822 // test last found record
1823 if( mxLastFoundDV
.get() && (mxLastFoundDV
->GetScHandle() == nScHandle
) )
1824 return *mxLastFoundDV
;
1827 size_t nCurrPos
= 0;
1828 if( !maDVList
.IsEmpty() )
1830 size_t nFirstPos
= 0;
1831 size_t nLastPos
= maDVList
.GetSize() - 1;
1833 sal_uLong nCurrScHandle
= ::std::numeric_limits
< sal_uLong
>::max();
1834 while( (nFirstPos
<= nLastPos
) && bLoop
)
1836 nCurrPos
= (nFirstPos
+ nLastPos
) / 2;
1837 mxLastFoundDV
= maDVList
.GetRecord( nCurrPos
);
1838 nCurrScHandle
= mxLastFoundDV
->GetScHandle();
1839 if( nCurrScHandle
== nScHandle
)
1841 else if( nCurrScHandle
< nScHandle
)
1842 nFirstPos
= nCurrPos
+ 1;
1844 nLastPos
= nCurrPos
- 1;
1845 else // special case for nLastPos = -1
1848 if( nCurrScHandle
== nScHandle
)
1849 return *mxLastFoundDV
;
1850 else if( nCurrScHandle
< nScHandle
)
1854 // create new DV record
1855 mxLastFoundDV
.reset( new XclExpDV( *this, nScHandle
) );
1856 maDVList
.InsertRecord( mxLastFoundDV
, nCurrPos
);
1857 return *mxLastFoundDV
;
1860 void XclExpDval::WriteBody( XclExpStream
& rStrm
)
1862 rStrm
.WriteZeroBytes( 10 );
1863 rStrm
<< EXC_DVAL_NOOBJ
<< static_cast< sal_uInt32
>( maDVList
.GetSize() );
1866 // Web Queries ================================================================
1868 XclExpWebQuery::XclExpWebQuery(
1869 const OUString
& rRangeName
,
1870 const OUString
& rUrl
,
1871 const OUString
& rSource
,
1872 sal_Int32 nRefrSecs
) :
1873 maDestRange( rRangeName
),
1875 // refresh delay time: seconds -> minutes
1876 mnRefresh( ulimit_cast
< sal_Int16
>( (nRefrSecs
+ 59) / 60 ) ),
1877 mbEntireDoc( false )
1879 // comma separated list of HTML table names or indexes
1880 sal_Int32 nTokenCnt
= comphelper::string::getTokenCount(rSource
, ';');
1881 OUString aNewTables
;
1882 OUString aAppendTable
;
1883 sal_Int32 nStringIx
= 0;
1884 bool bExitLoop
= false;
1885 for( sal_Int32 nToken
= 0; (nToken
< nTokenCnt
) && !bExitLoop
; ++nToken
)
1887 OUString
aToken( rSource
.getToken( 0, ';', nStringIx
) );
1888 mbEntireDoc
= ScfTools::IsHTMLDocName( aToken
);
1889 bExitLoop
= mbEntireDoc
|| ScfTools::IsHTMLTablesName( aToken
);
1890 if( !bExitLoop
&& ScfTools::GetHTMLNameFromName( aToken
, aAppendTable
) )
1891 aNewTables
= ScGlobal::addToken( aNewTables
, aAppendTable
, ',' );
1894 if( !bExitLoop
) // neither HTML_all nor HTML_tables found
1896 if( !aNewTables
.isEmpty() )
1897 mxQryTables
.reset( new XclExpString( aNewTables
) );
1903 XclExpWebQuery::~XclExpWebQuery()
1907 void XclExpWebQuery::Save( XclExpStream
& rStrm
)
1909 OSL_ENSURE( !mbEntireDoc
|| !mxQryTables
.get(), "XclExpWebQuery::Save - illegal mode" );
1913 rStrm
.StartRecord( EXC_ID_QSI
, 10 + maDestRange
.GetSize() );
1914 rStrm
<< EXC_QSI_DEFAULTFLAGS
1915 << sal_uInt16( 0x0010 )
1916 << sal_uInt16( 0x0012 )
1917 << sal_uInt32( 0x00000000 )
1923 ::insert_value( nFlags
, EXC_PQRYTYPE_WEBQUERY
, 0, 3 );
1924 ::set_flag( nFlags
, EXC_PQRY_WEBQUERY
);
1925 ::set_flag( nFlags
, EXC_PQRY_TABLES
, !mbEntireDoc
);
1926 rStrm
.StartRecord( EXC_ID_PQRY
, 12 );
1928 << sal_uInt16( 0x0000 )
1929 << sal_uInt16( 0x0001 );
1930 rStrm
.WriteZeroBytes( 6 );
1934 rStrm
.StartRecord( EXC_ID_WQSTRING
, maUrl
.GetSize() );
1938 // unknown record 0x0802
1939 rStrm
.StartRecord( EXC_ID_0802
, 16 + maDestRange
.GetSize() );
1940 rStrm
<< EXC_ID_0802
; // repeated record id ?!?
1941 rStrm
.WriteZeroBytes( 6 );
1942 rStrm
<< sal_uInt16( 0x0003 )
1943 << sal_uInt32( 0x00000000 )
1944 << sal_uInt16( 0x0010 )
1948 // WEBQRYSETTINGS record
1949 nFlags
= mxQryTables
.get() ? EXC_WQSETT_SPECTABLES
: EXC_WQSETT_ALL
;
1950 rStrm
.StartRecord( EXC_ID_WQSETT
, 28 );
1951 rStrm
<< EXC_ID_WQSETT
// repeated record id ?!?
1952 << sal_uInt16( 0x0000 )
1953 << sal_uInt16( 0x0004 )
1954 << sal_uInt16( 0x0000 )
1955 << EXC_WQSETT_DEFAULTFLAGS
1957 rStrm
.WriteZeroBytes( 10 );
1958 rStrm
<< mnRefresh
// refresh delay in minutes
1959 << EXC_WQSETT_FORMATFULL
1960 << sal_uInt16( 0x0000 );
1963 // WEBQRYTABLES record
1964 if( mxQryTables
.get() )
1966 rStrm
.StartRecord( EXC_ID_WQTABLES
, 4 + mxQryTables
->GetSize() );
1967 rStrm
<< EXC_ID_WQTABLES
// repeated record id ?!?
1968 << sal_uInt16( 0x0000 )
1969 << *mxQryTables
; // comma separated list of source tables
1974 XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot
& rRoot
)
1976 SCTAB nScTab
= rRoot
.GetCurrScTab();
1977 SfxObjectShell
* pShell
= rRoot
.GetDocShell();
1978 if( !pShell
) return;
1979 ScfPropertySet
aModelProp( pShell
->GetModel() );
1980 if( !aModelProp
.Is() ) return;
1982 Reference
< XAreaLinks
> xAreaLinks
;
1983 aModelProp
.GetProperty( xAreaLinks
, SC_UNO_AREALINKS
);
1984 if( !xAreaLinks
.is() ) return;
1986 for( sal_Int32 nIndex
= 0, nCount
= xAreaLinks
->getCount(); nIndex
< nCount
; ++nIndex
)
1988 Reference
< XAreaLink
> xAreaLink( xAreaLinks
->getByIndex( nIndex
), UNO_QUERY
);
1989 if( xAreaLink
.is() )
1991 CellRangeAddress
aDestRange( xAreaLink
->getDestArea() );
1992 if( static_cast< SCTAB
>( aDestRange
.Sheet
) == nScTab
)
1994 ScfPropertySet
aLinkProp( xAreaLink
);
1996 if( aLinkProp
.GetProperty( aFilter
, SC_UNONAME_FILTER
) &&
1997 (aFilter
== EXC_WEBQRY_FILTER
) )
2000 OUString
/*aFilterOpt,*/ aUrl
;
2001 sal_Int32 nRefresh
= 0;
2003 // aLinkProp.GetProperty( aFilterOpt, SC_UNONAME_FILTOPT );
2004 aLinkProp
.GetProperty( aUrl
, SC_UNONAME_LINKURL
);
2005 aLinkProp
.GetProperty( nRefresh
, SC_UNONAME_REFDELAY
);
2007 OUString
aAbsDoc( ScGlobal::GetAbsDocName( aUrl
, pShell
) );
2008 INetURLObject
aUrlObj( aAbsDoc
);
2009 OUString
aWebQueryUrl( aUrlObj
.getFSysPath( INetURLObject::FSYS_DOS
) );
2010 if( aWebQueryUrl
.isEmpty() )
2011 aWebQueryUrl
= aAbsDoc
;
2013 // find range or create a new range
2014 OUString aRangeName
;
2015 ScRange aScDestRange
;
2016 ScUnoConversion::FillScRange( aScDestRange
, aDestRange
);
2017 if( const ScRangeData
* pRangeData
= rRoot
.GetNamedRanges().findByRange( aScDestRange
) )
2019 aRangeName
= pRangeData
->GetName();
2023 XclExpFormulaCompiler
& rFmlaComp
= rRoot
.GetFormulaCompiler();
2024 XclExpNameManager
& rNameMgr
= rRoot
.GetNameManager();
2026 // create a new unique defined name containing the range
2027 XclTokenArrayRef xTokArr
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_WQUERY
, aScDestRange
);
2028 sal_uInt16 nNameIdx
= rNameMgr
.InsertUniqueName( aUrlObj
.getBase(), xTokArr
, nScTab
);
2029 aRangeName
= rNameMgr
.GetOrigName( nNameIdx
);
2032 // create and store the web query record
2033 if( !aRangeName
.isEmpty() )
2034 AppendNewRecord( new XclExpWebQuery(
2035 aRangeName
, aWebQueryUrl
, xAreaLink
->getSourceArea(), nRefresh
) );
2042 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */