1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xecontent.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 #include "xecontent.hxx"
37 #include <com/sun/star/container/XIndexAccess.hpp>
38 #include <com/sun/star/frame/XModel.hpp>
39 #include <com/sun/star/sheet/XAreaLinks.hpp>
40 #include <com/sun/star/sheet/XAreaLink.hpp>
41 #include <sfx2/objsh.hxx>
42 #include <tools/urlobj.hxx>
43 #include <svtools/itemset.hxx>
44 #include <formula/grammar.hxx>
45 #include "scitems.hxx"
46 #include <svx/eeitem.hxx>
47 #include <svx/flditem.hxx>
48 #include "document.hxx"
49 #include "validat.hxx"
50 #include "unonames.hxx"
51 #include "convuno.hxx"
52 #include "rangenam.hxx"
53 #include "tokenarray.hxx"
54 #include "stlpool.hxx"
55 #include "patattr.hxx"
56 #include "fapihelper.hxx"
57 #include "xehelper.hxx"
58 #include "xestyle.hxx"
61 #include <oox/core/tokens.hxx>
63 using ::com::sun::star::uno::Reference
;
64 using ::com::sun::star::uno::Any
;
65 using ::com::sun::star::uno::UNO_QUERY
;
66 using ::com::sun::star::beans::XPropertySet
;
67 using ::com::sun::star::container::XIndexAccess
;
68 using ::com::sun::star::frame::XModel
;
69 using ::com::sun::star::table::CellRangeAddress
;
70 using ::com::sun::star::sheet::XAreaLinks
;
71 using ::com::sun::star::sheet::XAreaLink
;
73 using ::rtl::OUString
;
74 using ::rtl::OUStringBuffer
;
76 // Shared string table ========================================================
78 // 1 = SST hash table statistics prompt
79 #define EXC_INCL_SST_STATISTICS 0
81 // ----------------------------------------------------------------------------
83 /** A single string entry in the hash table. */
84 struct XclExpHashEntry
86 const XclExpString
* mpString
; /// Pointer to the string (no ownership).
87 sal_uInt32 mnSstIndex
; /// The SST index of this string.
88 inline explicit XclExpHashEntry( const XclExpString
* pString
= 0, sal_uInt32 nSstIndex
= 0 ) :
89 mpString( pString
), mnSstIndex( nSstIndex
) {}
92 /** Function object for strict weak ordering. */
93 struct XclExpHashEntrySWO
95 inline bool operator()( const XclExpHashEntry
& rLeft
, const XclExpHashEntry
& rRight
) const
96 { return *rLeft
.mpString
< *rRight
.mpString
; }
99 // ----------------------------------------------------------------------------
101 /** Implementation of the SST export.
102 @descr Stores all passed strings in a hash table and prevents repeated
103 insertion of equal strings. */
107 explicit XclExpSstImpl();
109 /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
110 sal_uInt32
Insert( XclExpStringRef xString
);
112 /** Writes the complete SST and EXTSST records. */
113 void Save( XclExpStream
& rStrm
);
114 void SaveXml( XclExpXmlStream
& rStrm
);
117 typedef ::std::list
< XclExpStringRef
> XclExpStringList
;
118 typedef ::std::vector
< XclExpHashEntry
> XclExpHashVec
;
119 typedef ::std::vector
< XclExpHashVec
> XclExpHashTab
;
121 XclExpStringList maStringList
; /// List of unique strings (in SST ID order).
122 XclExpHashTab maHashTab
; /// Hashed table that manages string pointers.
123 sal_uInt32 mnTotal
; /// Total count of strings (including doubles).
124 sal_uInt32 mnSize
; /// Size of the SST (count of unique strings).
127 // ----------------------------------------------------------------------------
129 const sal_uInt32 EXC_SST_HASHTABLE_SIZE
= 2048;
131 XclExpSstImpl::XclExpSstImpl() :
132 maHashTab( EXC_SST_HASHTABLE_SIZE
),
138 sal_uInt32
XclExpSstImpl::Insert( XclExpStringRef xString
)
140 DBG_ASSERT( xString
.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
142 xString
.reset( new XclExpString
);
145 sal_uInt32 nSstIndex
= 0;
147 // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
148 sal_uInt16 nHash
= xString
->GetHash();
149 (nHash
^= (nHash
/ EXC_SST_HASHTABLE_SIZE
)) %= EXC_SST_HASHTABLE_SIZE
;
151 XclExpHashVec
& rVec
= maHashTab
[ nHash
];
152 XclExpHashEntry
aEntry( xString
.get(), mnSize
);
153 XclExpHashVec::iterator aIt
= ::std::lower_bound( rVec
.begin(), rVec
.end(), aEntry
, XclExpHashEntrySWO() );
154 if( (aIt
== rVec
.end()) || (*aIt
->mpString
!= *xString
) )
157 maStringList
.push_back( xString
);
158 rVec
.insert( aIt
, aEntry
);
163 nSstIndex
= aIt
->mnSstIndex
;
169 void XclExpSstImpl::Save( XclExpStream
& rStrm
)
171 if( maStringList
.empty() )
174 #if (OSL_DEBUG_LEVEL > 1) && EXC_INCL_SST_STATISTICS
175 { // own scope for the statistics
176 #define APPENDINT( value ) Append( ByteString::CreateFromInt32( value ) )
178 size_t nPerBucket
= mnSize
/ EXC_SST_HASHTABLE_SIZE
+ 1, nEff
= 0;
179 for( XclExpHashTab::const_iterator aTIt
= maHashTab
.begin(), aTEnd
= maHashTab
.end(); aTIt
!= aTEnd
; ++aTIt
)
181 size_t nSize
= aTIt
->size();
182 if( nSize
>= aVec
.size() ) aVec
.resize( nSize
+ 1, 0 );
184 if( nSize
> nPerBucket
) nEff
+= nSize
- nPerBucket
;
186 ByteString
aStr( "SST HASHING STATISTICS\n\n" );
187 aStr
.Append( "Total count:\t" ).APPENDINT( mnTotal
).Append( " strings\n" );
188 aStr
.Append( "Reduced to:\t" ).APPENDINT( mnSize
).Append( " strings (" );
189 aStr
.APPENDINT( 100 * mnSize
/ mnTotal
).Append( "%)\n" );
190 aStr
.Append( "Effectivity:\t\t" ).APPENDINT( 100 - 100 * nEff
/ mnSize
);
191 aStr
.Append( "% (best: " ).APPENDINT( nPerBucket
).Append( " strings per bucket)\n" );
192 aStr
.Append( "\t\tCount of buckets\nBucket size\ttotal\tmax\tTotal strings\n" );
193 for( size_t nIx
= 0, nSize
= aVec
.size(), nInc
= 1; nIx
< nSize
; nIx
+= nInc
)
195 if( (nIx
== 10) || (nIx
== 100) || (nIx
== 1000) ) nInc
= nIx
;
196 size_t nMaxIx
= ::std::min( nIx
+ nInc
, nSize
), nCount
= 0, nMaxCount
= 0, nStrings
= 0;
197 for( size_t nSubIx
= nIx
; nSubIx
< nMaxIx
; ++nSubIx
)
199 nCount
+= aVec
[ nSubIx
];
200 if( aVec
[ nSubIx
] > nMaxCount
) nMaxCount
= aVec
[ nSubIx
];
201 nStrings
+= nSubIx
* aVec
[ nSubIx
];
205 aStr
.APPENDINT( nIx
);
206 if( nMaxIx
- nIx
> 1 ) aStr
.Append( '-' ).APPENDINT( nMaxIx
- 1 );
207 aStr
.Append( "\t\t" ).APPENDINT( nCount
).Append( '\t' ).APPENDINT( nMaxCount
);
208 aStr
.Append( '\t' ).APPENDINT( nStrings
).Append( '\n' );
211 DBG_ERRORFILE( aStr
.GetBuffer() );
216 SvMemoryStream
aExtSst( 8192 );
218 sal_uInt32 nBucket
= mnSize
;
219 while( nBucket
> 0x0100 )
222 sal_uInt16 nPerBucket
= llimit_cast
< sal_uInt16
>( nBucket
, 8 );
223 sal_uInt16 nBucketIndex
= 0;
225 // *** write the SST record ***
227 rStrm
.StartRecord( EXC_ID_SST
, 8 );
229 rStrm
<< mnTotal
<< mnSize
;
230 for( XclExpStringList::const_iterator aIt
= maStringList
.begin(), aEnd
= maStringList
.end(); aIt
!= aEnd
; ++aIt
)
234 // write bucket info before string to get correct record position
235 sal_uInt32 nStrmPos
= static_cast< sal_uInt32
>( rStrm
.GetSvStreamPos() );
236 sal_uInt16 nRecPos
= rStrm
.GetRawRecPos() + 4;
237 aExtSst
<< nStrmPos
// stream position
238 << nRecPos
// position from start of SST or CONTINUE
239 << sal_uInt16( 0 ); // reserved
244 if( ++nBucketIndex
== nPerBucket
)
250 // *** write the EXTSST record ***
252 rStrm
.StartRecord( EXC_ID_EXTSST
, 0 );
255 rStrm
.SetSliceSize( 8 ); // size of one bucket info
256 aExtSst
.Seek( STREAM_SEEK_TO_BEGIN
);
257 rStrm
.CopyFromStream( aExtSst
);
262 void XclExpSstImpl::SaveXml( XclExpXmlStream
& rStrm
)
264 if( maStringList
.empty() )
267 sax_fastparser::FSHelperPtr pSst
= rStrm
.CreateOutputStream(
268 OUString::createFromAscii( "xl/sharedStrings.xml" ),
269 OUString::createFromAscii( "sharedStrings.xml" ),
270 rStrm
.GetCurrentStream()->getOutputStream(),
271 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
272 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
273 rStrm
.PushStream( pSst
);
275 pSst
->startElement( XML_sst
,
276 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
277 XML_count
, OString::valueOf( (sal_Int32
) mnTotal
).getStr(),
278 XML_uniqueCount
, OString::valueOf( (sal_Int32
) mnSize
).getStr(),
281 for( XclExpStringList::const_iterator aIt
= maStringList
.begin(), aEnd
= maStringList
.end(); aIt
!= aEnd
; ++aIt
)
283 pSst
->startElement( XML_si
, FSEND
);
284 (*aIt
)->WriteXml( rStrm
);
285 pSst
->endElement( XML_si
);
288 pSst
->endElement( XML_sst
);
293 // ----------------------------------------------------------------------------
295 XclExpSst::XclExpSst() :
296 mxImpl( new XclExpSstImpl
)
300 XclExpSst::~XclExpSst()
304 sal_uInt32
XclExpSst::Insert( XclExpStringRef xString
)
306 return mxImpl
->Insert( xString
);
309 void XclExpSst::Save( XclExpStream
& rStrm
)
311 mxImpl
->Save( rStrm
);
314 void XclExpSst::SaveXml( XclExpXmlStream
& rStrm
)
316 mxImpl
->SaveXml( rStrm
);
319 // Merged cells ===============================================================
321 XclExpMergedcells::XclExpMergedcells( const XclExpRoot
& rRoot
) :
326 void XclExpMergedcells::AppendRange( const ScRange
& rRange
, sal_uInt32 nBaseXFId
)
328 if( GetBiff() == EXC_BIFF8
)
330 maMergedRanges
.Append( rRange
);
331 maBaseXFIds
.push_back( nBaseXFId
);
335 sal_uInt32
XclExpMergedcells::GetBaseXFId( const ScAddress
& rPos
) const
337 DBG_ASSERT( maBaseXFIds
.size() == maMergedRanges
.Count(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
338 ScfUInt32Vec::const_iterator aIt
= maBaseXFIds
.begin();
339 ScRangeList
& rNCRanges
= const_cast< ScRangeList
& >( maMergedRanges
);
340 for( const ScRange
* pScRange
= rNCRanges
.First(); pScRange
; pScRange
= rNCRanges
.Next(), ++aIt
)
341 if( pScRange
->In( rPos
) )
343 return EXC_XFID_NOTFOUND
;
346 void XclExpMergedcells::Save( XclExpStream
& rStrm
)
348 if( GetBiff() == EXC_BIFF8
)
350 XclRangeList aXclRanges
;
351 GetAddressConverter().ConvertRangeList( aXclRanges
, maMergedRanges
, true );
352 size_t nFirstRange
= 0;
353 size_t nRemainingRanges
= aXclRanges
.size();
354 while( nRemainingRanges
> 0 )
356 size_t nRangeCount
= ::std::min
< size_t >( nRemainingRanges
, EXC_MERGEDCELLS_MAXCOUNT
);
357 rStrm
.StartRecord( EXC_ID_MERGEDCELLS
, 2 + 8 * nRangeCount
);
358 aXclRanges
.WriteSubList( rStrm
, nFirstRange
, nRangeCount
);
360 nFirstRange
+= nRangeCount
;
361 nRemainingRanges
-= nRangeCount
;
366 void XclExpMergedcells::SaveXml( XclExpXmlStream
& rStrm
)
368 ULONG nCount
= maMergedRanges
.Count();
371 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
372 rWorksheet
->startElement( XML_mergeCells
,
373 XML_count
, OString::valueOf( (sal_Int32
) nCount
).getStr(),
375 for( ULONG i
= 0; i
< nCount
; ++i
)
377 if( const ScRange
* pRange
= maMergedRanges
.GetObject( i
) )
379 rWorksheet
->singleElement( XML_mergeCell
,
380 XML_ref
, XclXmlUtils::ToOString( *pRange
).getStr(),
384 rWorksheet
->endElement( XML_mergeCells
);
387 // Hyperlinks =================================================================
389 XclExpHyperlink::XclExpHyperlink( const XclExpRoot
& rRoot
, const SvxURLField
& rUrlField
, const ScAddress
& rScPos
) :
390 XclExpRecord( EXC_ID_HLINK
),
392 mxVarData( new SvMemoryStream
),
395 const String
& rUrl
= rUrlField
.GetURL();
396 const String
& rRepr
= rUrlField
.GetRepresentation();
397 INetURLObject
aUrlObj( rUrl
);
398 const INetProtocol eProtocol
= aUrlObj
.GetProtocol();
399 bool bWithRepr
= rRepr
.Len() > 0;
400 XclExpStream
aXclStrm( *mxVarData
, rRoot
); // using in raw write mode.
405 XclExpString
aDescr( rRepr
, EXC_STR_FORCEUNICODE
, 255 );
406 aXclStrm
<< sal_uInt32( aDescr
.Len() + 1 ); // string length + 1 trailing zero word
407 aDescr
.WriteBuffer( aXclStrm
); // NO flags
408 aXclStrm
<< sal_uInt16( 0 );
410 mnFlags
|= EXC_HLINK_DESCR
;
411 mxRepr
.reset( new String( rRepr
) );
415 if( eProtocol
== INET_PROT_FILE
|| eProtocol
== INET_PROT_SMB
)
419 String
aFileName( BuildFileName( nLevel
, bRel
, rUrl
, rRoot
) );
421 if( eProtocol
== INET_PROT_SMB
)
423 // #n382718# (and #n261623#) Convert smb notation to '\\'
424 aFileName
= aUrlObj
.GetMainURL( INetURLObject::NO_DECODE
);
425 aFileName
= String( aFileName
.GetBuffer() + 4 ); // skip the 'smb:' part
426 aFileName
.SearchAndReplaceAll( '/', '\\' );
430 mnFlags
|= EXC_HLINK_ABS
;
431 mnFlags
|= EXC_HLINK_BODY
;
433 ByteString
aAsciiLink( aFileName
, rRoot
.GetTextEncoding() );
434 XclExpString
aLink( aFileName
, EXC_STR_FORCEUNICODE
, 255 );
435 aXclStrm
<< XclTools::maGuidFileMoniker
437 << sal_uInt32( aAsciiLink
.Len() + 1 ); // string length + 1 trailing zero byte
438 aXclStrm
.Write( aAsciiLink
.GetBuffer(), aAsciiLink
.Len() );
439 aXclStrm
<< sal_uInt8( 0 )
440 << sal_uInt32( 0xDEADFFFF );
441 aXclStrm
.WriteZeroBytes( 20 );
442 aXclStrm
<< sal_uInt32( aLink
.GetBufferSize() + 6 )
443 << sal_uInt32( aLink
.GetBufferSize() ) // byte count, not string length
444 << sal_uInt16( 0x0003 );
445 aLink
.WriteBuffer( aXclStrm
); // NO flags
448 mxRepr
.reset( new String( aFileName
) );
450 msTarget
= XclXmlUtils::ToOUString( aLink
);
452 else if( eProtocol
!= INET_PROT_NOT_VALID
)
454 XclExpString
aUrl( aUrlObj
.GetURLNoMark(), EXC_STR_FORCEUNICODE
, 255 );
455 aXclStrm
<< XclTools::maGuidUrlMoniker
456 << sal_uInt32( aUrl
.GetBufferSize() + 2 ); // byte count + 1 trailing zero word
457 aUrl
.WriteBuffer( aXclStrm
); // NO flags
458 aXclStrm
<< sal_uInt16( 0 );
460 mnFlags
|= EXC_HLINK_BODY
| EXC_HLINK_ABS
;
462 mxRepr
.reset( new String( rUrl
) );
464 msTarget
= XclXmlUtils::ToOUString( aUrl
);
466 else if( rUrl
.GetChar( 0 ) == '#' ) // hack for #89066#
468 String
aTextMark( rUrl
.Copy( 1 ) );
469 aTextMark
.SearchAndReplace( '.', '!' );
470 mxTextMark
.reset( new XclExpString( aTextMark
, EXC_STR_FORCEUNICODE
, 255 ) );
474 if( !mxTextMark
.get() && aUrlObj
.HasMark() )
475 mxTextMark
.reset( new XclExpString( aUrlObj
.GetMark(), EXC_STR_FORCEUNICODE
, 255 ) );
477 if( mxTextMark
.get() )
479 aXclStrm
<< sal_uInt32( mxTextMark
->Len() + 1 ); // string length + 1 trailing zero word
480 mxTextMark
->WriteBuffer( aXclStrm
); // NO flags
481 aXclStrm
<< sal_uInt16( 0 );
483 mnFlags
|= EXC_HLINK_MARK
;
486 SetRecSize( 32 + mxVarData
->Tell() );
489 XclExpHyperlink::~XclExpHyperlink()
493 String
XclExpHyperlink::BuildFileName(
494 sal_uInt16
& rnLevel
, bool& rbRel
, const String
& rUrl
, const XclExpRoot
& rRoot
) const
496 String
aDosName( INetURLObject( rUrl
).getFSysPath( INetURLObject::FSYS_DOS
) );
498 rbRel
= rRoot
.IsRelUrl();
502 // try to convert to relative file name
503 String
aTmpName( aDosName
);
504 aDosName
= INetURLObject::GetRelURL( rRoot
.GetBasePath(), rUrl
,
505 INetURLObject::WAS_ENCODED
, INetURLObject::DECODE_WITH_CHARSET
);
507 if( aDosName
.SearchAscii( INET_FILE_SCHEME
) == 0 )
509 // not converted to rel -> back to old, return absolute flag
513 else if( aDosName
.SearchAscii( "./" ) == 0 )
515 aDosName
.Erase( 0, 2 );
519 while( aDosName
.SearchAndReplaceAscii( "../", EMPTY_STRING
) == 0 )
526 void XclExpHyperlink::WriteBody( XclExpStream
& rStrm
)
528 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( maScPos
.Col() );
529 sal_uInt16 nXclRow
= static_cast< sal_uInt16
>( maScPos
.Row() );
530 rStrm
<< nXclRow
<< nXclRow
<< nXclCol
<< nXclCol
;
531 WriteEmbeddedData( rStrm
);
534 void XclExpHyperlink::WriteEmbeddedData( XclExpStream
& rStrm
)
536 rStrm
<< XclTools::maGuidStdLink
540 mxVarData
->Seek( STREAM_SEEK_TO_BEGIN
);
541 rStrm
.CopyFromStream( *mxVarData
);
544 void XclExpHyperlink::SaveXml( XclExpXmlStream
& rStrm
)
546 OUString sId
= rStrm
.addRelation( rStrm
.GetCurrentStream()->getOutputStream(),
547 XclXmlUtils::ToOUString( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ),
549 XclXmlUtils::ToOUString( "External" ) );
550 rStrm
.GetCurrentStream()->singleElement( XML_hyperlink
,
551 XML_ref
, XclXmlUtils::ToOString( maScPos
).getStr(),
552 FSNS( XML_r
, XML_id
), XclXmlUtils::ToOString( sId
).getStr(),
553 XML_location
, mxTextMark
.get() != NULL
554 ? XclXmlUtils::ToOString( *mxTextMark
).getStr()
556 // OOXTODO: XML_tooltip, from record HLinkTooltip 800h wzTooltip
557 XML_display
, XclXmlUtils::ToOString( *mxRepr
).getStr(),
561 // Label ranges ===============================================================
563 XclExpLabelranges::XclExpLabelranges( const XclExpRoot
& rRoot
) :
566 SCTAB nScTab
= GetCurrScTab();
568 FillRangeList( maRowRanges
, rRoot
.GetDoc().GetRowNameRangesRef(), nScTab
);
569 // row labels only over 1 column (restriction of Excel97/2000/XP)
570 for( ScRange
* pScRange
= maRowRanges
.First(); pScRange
; pScRange
= maRowRanges
.Next() )
571 if( pScRange
->aStart
.Col() != pScRange
->aEnd
.Col() )
572 pScRange
->aEnd
.SetCol( pScRange
->aStart
.Col() );
574 FillRangeList( maColRanges
, rRoot
.GetDoc().GetColNameRangesRef(), nScTab
);
577 void XclExpLabelranges::FillRangeList( ScRangeList
& rScRanges
,
578 ScRangePairListRef xLabelRangesRef
, SCTAB nScTab
)
580 for( const ScRangePair
* pRangePair
= xLabelRangesRef
->First(); pRangePair
; pRangePair
= xLabelRangesRef
->Next() )
582 const ScRange
& rScRange
= pRangePair
->GetRange( 0 );
583 if( rScRange
.aStart
.Tab() == nScTab
)
584 rScRanges
.Append( rScRange
);
588 void XclExpLabelranges::Save( XclExpStream
& rStrm
)
590 XclExpAddressConverter
& rAddrConv
= GetAddressConverter();
591 XclRangeList aRowXclRanges
, aColXclRanges
;
592 rAddrConv
.ConvertRangeList( aRowXclRanges
, maRowRanges
, false );
593 rAddrConv
.ConvertRangeList( aColXclRanges
, maColRanges
, false );
594 if( !aRowXclRanges
.empty() || !aColXclRanges
.empty() )
596 rStrm
.StartRecord( EXC_ID_LABELRANGES
, 4 + 8 * (aRowXclRanges
.size() + aColXclRanges
.size()) );
597 rStrm
<< aRowXclRanges
<< aColXclRanges
;
602 // Conditional formatting ====================================================
604 /** Represents a CF record that contains one condition of a conditional format. */
605 class XclExpCFImpl
: protected XclExpRoot
608 explicit XclExpCFImpl( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
);
610 /** Writes the body of the CF record. */
611 void WriteBody( XclExpStream
& rStrm
);
614 const ScCondFormatEntry
& mrFormatEntry
; /// Calc conditional format entry.
615 XclFontData maFontData
; /// Font formatting attributes.
616 XclExpCellBorder maBorder
; /// Border formatting attributes.
617 XclExpCellArea maArea
; /// Pattern formatting attributes.
618 XclTokenArrayRef mxTokArr1
; /// Formula for first condition.
619 XclTokenArrayRef mxTokArr2
; /// Formula for second condition.
620 sal_uInt32 mnFontColorId
; /// Font color ID.
621 sal_uInt8 mnType
; /// Type of the condition (cell/formula).
622 sal_uInt8 mnOperator
; /// Comparison operator for cell type.
623 bool mbFontUsed
; /// true = Any font attribute used.
624 bool mbHeightUsed
; /// true = Font height used.
625 bool mbWeightUsed
; /// true = Font weight used.
626 bool mbColorUsed
; /// true = Font color used.
627 bool mbUnderlUsed
; /// true = Font underline type used.
628 bool mbItalicUsed
; /// true = Font posture used.
629 bool mbStrikeUsed
; /// true = Font strikeout used.
630 bool mbBorderUsed
; /// true = Border attribute used.
631 bool mbPattUsed
; /// true = Pattern attribute used.
634 // ----------------------------------------------------------------------------
636 XclExpCFImpl::XclExpCFImpl( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
) :
638 mrFormatEntry( rFormatEntry
),
640 mnType( EXC_CF_TYPE_CELL
),
641 mnOperator( EXC_CF_CMP_NONE
),
643 mbHeightUsed( false ),
644 mbWeightUsed( false ),
645 mbColorUsed( false ),
646 mbUnderlUsed( false ),
647 mbItalicUsed( false ),
648 mbStrikeUsed( false ),
649 mbBorderUsed( false ),
652 /* Get formatting attributes here, and not in WriteBody(). This is needed to
653 correctly insert all colors into the palette. */
655 if( SfxStyleSheetBase
* pStyleSheet
= GetDoc().GetStyleSheetPool()->Find( mrFormatEntry
.GetStyle(), SFX_STYLE_FAMILY_PARA
) )
657 const SfxItemSet
& rItemSet
= pStyleSheet
->GetItemSet();
660 mbHeightUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_HEIGHT
, true );
661 mbWeightUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_WEIGHT
, true );
662 mbColorUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_COLOR
, true );
663 mbUnderlUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_UNDERLINE
, true );
664 mbItalicUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_POSTURE
, true );
665 mbStrikeUsed
= ScfTools::CheckItem( rItemSet
, ATTR_FONT_CROSSEDOUT
, true );
666 mbFontUsed
= mbHeightUsed
|| mbWeightUsed
|| mbColorUsed
|| mbUnderlUsed
|| mbItalicUsed
|| mbStrikeUsed
;
670 ScPatternAttr::GetFont( aFont
, rItemSet
, SC_AUTOCOL_RAW
);
671 maFontData
.FillFromVclFont( aFont
);
672 mnFontColorId
= GetPalette().InsertColor( maFontData
.maColor
, EXC_COLOR_CELLTEXT
);
676 mbBorderUsed
= ScfTools::CheckItem( rItemSet
, ATTR_BORDER
, true );
678 maBorder
.FillFromItemSet( rItemSet
, GetPalette(), GetBiff() );
681 mbPattUsed
= ScfTools::CheckItem( rItemSet
, ATTR_BACKGROUND
, true );
683 maArea
.FillFromItemSet( rItemSet
, GetPalette(), GetBiff() );
686 // *** mode and comparison operator ***
689 switch( rFormatEntry
.GetOperation() )
691 case SC_COND_NONE
: mnType
= EXC_CF_TYPE_NONE
; break;
692 case SC_COND_BETWEEN
: mnOperator
= EXC_CF_CMP_BETWEEN
; bFmla2
= true; break;
693 case SC_COND_NOTBETWEEN
: mnOperator
= EXC_CF_CMP_NOT_BETWEEN
; bFmla2
= true; break;
694 case SC_COND_EQUAL
: mnOperator
= EXC_CF_CMP_EQUAL
; break;
695 case SC_COND_NOTEQUAL
: mnOperator
= EXC_CF_CMP_NOT_EQUAL
; break;
696 case SC_COND_GREATER
: mnOperator
= EXC_CF_CMP_GREATER
; break;
697 case SC_COND_LESS
: mnOperator
= EXC_CF_CMP_LESS
; break;
698 case SC_COND_EQGREATER
: mnOperator
= EXC_CF_CMP_GREATER_EQUAL
; break;
699 case SC_COND_EQLESS
: mnOperator
= EXC_CF_CMP_LESS_EQUAL
; break;
700 case SC_COND_DIRECT
: mnType
= EXC_CF_TYPE_FMLA
; break;
701 default: mnType
= EXC_CF_TYPE_NONE
;
702 DBG_ERRORFILE( "XclExpCF::WriteBody - unknown condition type" );
707 XclExpFormulaCompiler
& rFmlaComp
= GetFormulaCompiler();
709 ::std::auto_ptr
< ScTokenArray
> xScTokArr( mrFormatEntry
.CreateTokenArry( 0 ) );
710 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_CONDFMT
, *xScTokArr
);
714 xScTokArr
.reset( mrFormatEntry
.CreateTokenArry( 1 ) );
715 mxTokArr2
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_CONDFMT
, *xScTokArr
);
719 void XclExpCFImpl::WriteBody( XclExpStream
& rStrm
)
721 // *** mode and comparison operator ***
723 rStrm
<< mnType
<< mnOperator
;
725 // *** formula sizes ***
727 sal_uInt16 nFmlaSize1
= mxTokArr1
.get() ? mxTokArr1
->GetSize() : 0;
728 sal_uInt16 nFmlaSize2
= mxTokArr2
.get() ? mxTokArr2
->GetSize() : 0;
729 rStrm
<< nFmlaSize1
<< nFmlaSize2
;
731 // *** formatting blocks ***
733 if( mbFontUsed
|| mbBorderUsed
|| mbPattUsed
)
735 sal_uInt32 nFlags
= EXC_CF_ALLDEFAULT
;
737 ::set_flag( nFlags
, EXC_CF_BLOCK_FONT
, mbFontUsed
);
738 ::set_flag( nFlags
, EXC_CF_BLOCK_BORDER
, mbBorderUsed
);
739 ::set_flag( nFlags
, EXC_CF_BLOCK_AREA
, mbPattUsed
);
741 // attributes used -> set flags to 0.
742 ::set_flag( nFlags
, EXC_CF_BORDER_ALL
, !mbBorderUsed
);
743 ::set_flag( nFlags
, EXC_CF_AREA_ALL
, !mbPattUsed
);
745 rStrm
<< nFlags
<< sal_uInt16( 0 );
749 // font height, 0xFFFFFFFF indicates unused
750 sal_uInt32 nHeight
= mbHeightUsed
? maFontData
.mnHeight
: 0xFFFFFFFF;
751 // font style: italic and strikeout
752 sal_uInt32 nStyle
= 0;
753 ::set_flag( nStyle
, EXC_CF_FONT_STYLE
, maFontData
.mbItalic
);
754 ::set_flag( nStyle
, EXC_CF_FONT_STRIKEOUT
, maFontData
.mbStrikeout
);
755 // font color, 0xFFFFFFFF indicates unused
756 sal_uInt32 nColor
= mbColorUsed
? GetPalette().GetColorIndex( mnFontColorId
) : 0xFFFFFFFF;
757 // font used flags for italic, weight, and strikeout -> 0 = used, 1 = default
758 sal_uInt32 nFontFlags1
= EXC_CF_FONT_ALLDEFAULT
;
759 ::set_flag( nFontFlags1
, EXC_CF_FONT_STYLE
, !(mbItalicUsed
|| mbWeightUsed
) );
760 ::set_flag( nFontFlags1
, EXC_CF_FONT_STRIKEOUT
, !mbStrikeUsed
);
761 // font used flag for underline -> 0 = used, 1 = default
762 sal_uInt32 nFontFlags3
= mbUnderlUsed
? 0 : EXC_CF_FONT_UNDERL
;
764 rStrm
.WriteZeroBytesToRecord( 64 );
767 << maFontData
.mnWeight
769 << maFontData
.mnUnderline
;
770 rStrm
.WriteZeroBytesToRecord( 3 );
774 << EXC_CF_FONT_ESCAPEM
// escapement never used -> set the flag
776 rStrm
.WriteZeroBytesToRecord( 16 );
777 rStrm
<< sal_uInt16( 1 ); // must be 1
782 sal_uInt16 nLineStyle
= 0;
783 sal_uInt32 nLineColor
= 0;
784 maBorder
.SetFinalColors( GetPalette() );
785 maBorder
.FillToCF8( nLineStyle
, nLineColor
);
786 rStrm
<< nLineStyle
<< nLineColor
<< sal_uInt16( 0 );
791 sal_uInt16 nPattern
= 0, nColor
= 0;
792 maArea
.SetFinalColors( GetPalette() );
793 maArea
.FillToCF8( nPattern
, nColor
);
794 rStrm
<< nPattern
<< nColor
;
799 // no data blocks at all
800 rStrm
<< sal_uInt32( 0 ) << sal_uInt16( 0 );
805 if( mxTokArr1
.get() )
806 mxTokArr1
->WriteArray( rStrm
);
807 if( mxTokArr2
.get() )
808 mxTokArr2
->WriteArray( rStrm
);
811 // ----------------------------------------------------------------------------
813 XclExpCF::XclExpCF( const XclExpRoot
& rRoot
, const ScCondFormatEntry
& rFormatEntry
) :
814 XclExpRecord( EXC_ID_CF
),
816 mxImpl( new XclExpCFImpl( rRoot
, rFormatEntry
) )
820 XclExpCF::~XclExpCF()
824 void XclExpCF::WriteBody( XclExpStream
& rStrm
)
826 mxImpl
->WriteBody( rStrm
);
829 // ----------------------------------------------------------------------------
831 XclExpCondfmt::XclExpCondfmt( const XclExpRoot
& rRoot
, const ScConditionalFormat
& rCondFormat
) :
832 XclExpRecord( EXC_ID_CONDFMT
),
835 ScRangeList aScRanges
;
836 GetDoc().FindConditionalFormat( rCondFormat
.GetKey(), aScRanges
, GetCurrScTab() );
837 GetAddressConverter().ConvertRangeList( maXclRanges
, aScRanges
, true );
838 if( !maXclRanges
.empty() )
840 for( USHORT nIndex
= 0, nCount
= rCondFormat
.Count(); nIndex
< nCount
; ++nIndex
)
841 if( const ScCondFormatEntry
* pEntry
= rCondFormat
.GetEntry( nIndex
) )
842 maCFList
.AppendNewRecord( new XclExpCF( GetRoot(), *pEntry
) );
843 aScRanges
.Format( msSeqRef
, SCA_VALID
, NULL
, formula::FormulaGrammar::CONV_XL_A1
);
847 XclExpCondfmt::~XclExpCondfmt()
851 bool XclExpCondfmt::IsValid() const
853 return !maCFList
.IsEmpty() && !maXclRanges
.empty();
856 void XclExpCondfmt::Save( XclExpStream
& rStrm
)
860 XclExpRecord::Save( rStrm
);
861 maCFList
.Save( rStrm
);
865 void XclExpCondfmt::WriteBody( XclExpStream
& rStrm
)
867 DBG_ASSERT( !maCFList
.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
868 DBG_ASSERT( !maXclRanges
.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
870 rStrm
<< static_cast< sal_uInt16
>( maCFList
.GetSize() )
872 << maXclRanges
.GetEnclosingRange()
876 void XclExpCondfmt::SaveXml( XclExpXmlStream
& rStrm
)
881 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
882 rWorksheet
->startElement( XML_conditionalFormatting
,
883 XML_sqref
, XclXmlUtils::ToOString( msSeqRef
).getStr(),
884 // OOXTODO: XML_pivot,
886 maCFList
.SaveXml( rStrm
);
887 // OOXTODO: XML_extLst
888 rWorksheet
->endElement( XML_conditionalFormatting
);
891 // ----------------------------------------------------------------------------
893 XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot
& rRoot
) :
896 if( const ScConditionalFormatList
* pCondFmtList
= GetDoc().GetCondFormList() )
898 if( const ScConditionalFormatPtr
* ppCondFmt
= pCondFmtList
->GetData() )
900 const ScConditionalFormatPtr
* ppCondEnd
= ppCondFmt
+ pCondFmtList
->Count();
901 for( ; ppCondFmt
< ppCondEnd
; ++ppCondFmt
)
905 XclExpCondfmtList::RecordRefType
xCondfmtRec( new XclExpCondfmt( GetRoot(), **ppCondFmt
) );
906 if( xCondfmtRec
->IsValid() )
907 maCondfmtList
.AppendRecord( xCondfmtRec
);
914 void XclExpCondFormatBuffer::Save( XclExpStream
& rStrm
)
916 maCondfmtList
.Save( rStrm
);
919 void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream
& rStrm
)
921 maCondfmtList
.SaveXml( rStrm
);
924 // Validation =================================================================
928 /** Writes a formula for the DV record. */
929 void lclWriteDvFormula( XclExpStream
& rStrm
, const XclTokenArray
* pXclTokArr
)
931 sal_uInt16 nFmlaSize
= pXclTokArr
? pXclTokArr
->GetSize() : 0;
932 rStrm
<< nFmlaSize
<< sal_uInt16( 0 );
934 pXclTokArr
->WriteArray( rStrm
);
937 /** Writes a formula for the DV record, based on a single string. */
938 void lclWriteDvFormula( XclExpStream
& rStrm
, const XclExpString
& rString
)
940 // fake a formula with a single tStr token
941 rStrm
<< static_cast< sal_uInt16
>( rString
.GetSize() + 1 )
947 const char* lcl_GetValidationType( sal_uInt32 nFlags
)
949 switch( nFlags
& EXC_DV_MODE_MASK
)
951 case EXC_DV_MODE_ANY
: return "none";
952 case EXC_DV_MODE_WHOLE
: return "whole";
953 case EXC_DV_MODE_DECIMAL
: return "decimal";
954 case EXC_DV_MODE_LIST
: return "list";
955 case EXC_DV_MODE_DATE
: return "date";
956 case EXC_DV_MODE_TIME
: return "time";
957 case EXC_DV_MODE_TEXTLEN
: return "textLength";
958 case EXC_DV_MODE_CUSTOM
: return "custom";
963 const char* lcl_GetOperatorType( sal_uInt32 nFlags
)
965 switch( nFlags
& EXC_DV_COND_MASK
)
967 case EXC_DV_COND_BETWEEN
: return "between";
968 case EXC_DV_COND_NOTBETWEEN
: return "notBetween";
969 case EXC_DV_COND_EQUAL
: return "equal";
970 case EXC_DV_COND_NOTEQUAL
: return "notEqual";
971 case EXC_DV_COND_GREATER
: return "greaterThan";
972 case EXC_DV_COND_LESS
: return "lessThan";
973 case EXC_DV_COND_EQGREATER
: return "greaterThanOrEqual";
974 case EXC_DV_COND_EQLESS
: return "lessThanOrEqual";
981 // ----------------------------------------------------------------------------
983 XclExpDV::XclExpDV( const XclExpRoot
& rRoot
, ULONG nScHandle
) :
984 XclExpRecord( EXC_ID_DV
),
987 mnScHandle( nScHandle
)
989 if( const ScValidationData
* pValData
= GetDoc().GetValidationEntry( mnScHandle
) )
991 // prompt box - empty string represented by single NUL character
992 String aTitle
, aText
;
993 bool bShowPrompt
= (pValData
->GetInput( aTitle
, aText
) == TRUE
);
995 maPromptTitle
.Assign( aTitle
);
997 maPromptTitle
.Assign( '\0' );
999 maPromptText
.Assign( aText
);
1001 maPromptText
.Assign( '\0' );
1003 // error box - empty string represented by single NUL character
1004 ScValidErrorStyle eScErrorStyle
;
1005 bool bShowError
= (pValData
->GetErrMsg( aTitle
, aText
, eScErrorStyle
) == TRUE
);
1007 maErrorTitle
.Assign( aTitle
);
1009 maErrorTitle
.Assign( '\0' );
1011 maErrorText
.Assign( aText
);
1013 maErrorText
.Assign( '\0' );
1016 switch( pValData
->GetDataMode() )
1018 case SC_VALID_ANY
: mnFlags
|= EXC_DV_MODE_ANY
; break;
1019 case SC_VALID_WHOLE
: mnFlags
|= EXC_DV_MODE_WHOLE
; break;
1020 case SC_VALID_DECIMAL
: mnFlags
|= EXC_DV_MODE_DECIMAL
; break;
1021 case SC_VALID_LIST
: mnFlags
|= EXC_DV_MODE_LIST
; break;
1022 case SC_VALID_DATE
: mnFlags
|= EXC_DV_MODE_DATE
; break;
1023 case SC_VALID_TIME
: mnFlags
|= EXC_DV_MODE_TIME
; break;
1024 case SC_VALID_TEXTLEN
: mnFlags
|= EXC_DV_MODE_TEXTLEN
; break;
1025 case SC_VALID_CUSTOM
: mnFlags
|= EXC_DV_MODE_CUSTOM
; break;
1026 default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown mode" );
1029 switch( pValData
->GetOperation() )
1032 case SC_COND_EQUAL
: mnFlags
|= EXC_DV_COND_EQUAL
; break;
1033 case SC_COND_LESS
: mnFlags
|= EXC_DV_COND_LESS
; break;
1034 case SC_COND_GREATER
: mnFlags
|= EXC_DV_COND_GREATER
; break;
1035 case SC_COND_EQLESS
: mnFlags
|= EXC_DV_COND_EQLESS
; break;
1036 case SC_COND_EQGREATER
: mnFlags
|= EXC_DV_COND_EQGREATER
; break;
1037 case SC_COND_NOTEQUAL
: mnFlags
|= EXC_DV_COND_NOTEQUAL
; break;
1038 case SC_COND_BETWEEN
: mnFlags
|= EXC_DV_COND_BETWEEN
; break;
1039 case SC_COND_NOTBETWEEN
: mnFlags
|= EXC_DV_COND_NOTBETWEEN
; break;
1040 default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown condition" );
1042 switch( eScErrorStyle
)
1044 case SC_VALERR_STOP
: mnFlags
|= EXC_DV_ERROR_STOP
; break;
1045 case SC_VALERR_WARNING
: mnFlags
|= EXC_DV_ERROR_WARNING
; break;
1046 case SC_VALERR_INFO
: mnFlags
|= EXC_DV_ERROR_INFO
; break;
1047 case SC_VALERR_MACRO
:
1048 // #111781# set INFO for validity with macro call, delete title
1049 mnFlags
|= EXC_DV_ERROR_INFO
;
1050 maErrorTitle
.Assign( '\0' ); // contains macro name
1052 default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown error style" );
1054 ::set_flag( mnFlags
, EXC_DV_IGNOREBLANK
, pValData
->IsIgnoreBlank() );
1055 ::set_flag( mnFlags
, EXC_DV_SUPPRESSDROPDOWN
, pValData
->GetListType() == ValidListType::INVISIBLE
);
1056 ::set_flag( mnFlags
, EXC_DV_SHOWPROMPT
, bShowPrompt
);
1057 ::set_flag( mnFlags
, EXC_DV_SHOWERROR
, bShowError
);
1060 XclExpFormulaCompiler
& rFmlaComp
= GetFormulaCompiler();
1061 ::std::auto_ptr
< ScTokenArray
> xScTokArr
;
1064 xScTokArr
.reset( pValData
->CreateTokenArry( 0 ) );
1065 if( xScTokArr
.get() )
1067 if( pValData
->GetDataMode() == SC_VALID_LIST
)
1070 if( XclTokenArrayHelper::GetStringList( aString
, *xScTokArr
, '\n' ) )
1072 OUStringBuffer sFormulaBuf
;
1073 sFormulaBuf
.append( (sal_Unicode
) '"' );
1074 /* Formula is a list of string tokens -> build the Excel string.
1075 Data validity is BIFF8 only (important for the XclExpString object).
1076 Excel uses the NUL character as string list separator. */
1077 mxString1
.reset( new XclExpString( EXC_STR_8BITLENGTH
) );
1078 xub_StrLen nTokenCnt
= aString
.GetTokenCount( '\n' );
1079 xub_StrLen nStringIx
= 0;
1080 for( xub_StrLen nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
1082 String
aToken( aString
.GetToken( 0, '\n', nStringIx
) );
1085 mxString1
->Append( '\0' );
1086 sFormulaBuf
.append( (sal_Unicode
) ',' );
1088 mxString1
->Append( aToken
);
1089 sFormulaBuf
.append( XclXmlUtils::ToOUString( aToken
) );
1091 ::set_flag( mnFlags
, EXC_DV_STRINGLIST
);
1093 sFormulaBuf
.append( (sal_Unicode
) '"' );
1094 msFormula1
= sFormulaBuf
.makeStringAndClear();
1098 /* All other formulas in validation are stored like conditional
1099 formatting formulas (with tRefN/tAreaN tokens as value or
1100 array class). But NOT the cell references and defined names
1101 in list validation - they are stored as reference class
1103 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
1104 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
1105 Formula compiler supports this by offering two different functions
1106 CreateDataValFormula() and CreateListValFormula(). */
1107 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_LISTVAL
, *xScTokArr
);
1108 msFormula1
= XclXmlUtils::ToOUString( GetDoc(), pValData
->GetSrcPos(), xScTokArr
.get() );
1113 // no list validation -> convert the formula
1114 mxTokArr1
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_DATAVAL
, *xScTokArr
);
1115 msFormula1
= XclXmlUtils::ToOUString( GetDoc(), pValData
->GetSrcPos(), xScTokArr
.get() );
1120 xScTokArr
.reset( pValData
->CreateTokenArry( 1 ) );
1121 if( xScTokArr
.get() )
1123 mxTokArr2
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_DATAVAL
, *xScTokArr
);
1124 msFormula2
= XclXmlUtils::ToOUString( GetDoc(), pValData
->GetSrcPos(), xScTokArr
.get() );
1129 DBG_ERRORFILE( "XclExpDV::XclExpDV - missing core data" );
1130 mnScHandle
= ULONG_MAX
;
1134 XclExpDV::~XclExpDV()
1138 void XclExpDV::InsertCellRange( const ScRange
& rRange
)
1140 maScRanges
.Join( rRange
);
1143 bool XclExpDV::Finalize()
1145 GetAddressConverter().ConvertRangeList( maXclRanges
, maScRanges
, true );
1146 return (mnScHandle
!= ULONG_MAX
) && !maXclRanges
.empty();
1149 void XclExpDV::WriteBody( XclExpStream
& rStrm
)
1151 // flags and strings
1152 rStrm
<< mnFlags
<< maPromptTitle
<< maErrorTitle
<< maPromptText
<< maErrorText
;
1153 // condition formulas
1154 if( mxString1
.get() )
1155 lclWriteDvFormula( rStrm
, *mxString1
);
1157 lclWriteDvFormula( rStrm
, mxTokArr1
.get() );
1158 lclWriteDvFormula( rStrm
, mxTokArr2
.get() );
1160 rStrm
<< maXclRanges
;
1163 void XclExpDV::SaveXml( XclExpXmlStream
& rStrm
)
1165 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1166 rWorksheet
->startElement( XML_dataValidation
,
1167 XML_allowBlank
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_IGNOREBLANK
) ),
1168 XML_error
, XESTRING_TO_PSZ( maErrorText
),
1169 // OOXTODO: XML_errorStyle,
1170 XML_errorTitle
, XESTRING_TO_PSZ( maErrorTitle
),
1171 // OOXTODO: XML_imeMode,
1172 XML_operator
, lcl_GetOperatorType( mnFlags
),
1173 XML_prompt
, XESTRING_TO_PSZ( maPromptText
),
1174 XML_promptTitle
, XESTRING_TO_PSZ( maPromptTitle
),
1175 XML_showDropDown
, XclXmlUtils::ToPsz( ! ::get_flag( mnFlags
, EXC_DV_SUPPRESSDROPDOWN
) ),
1176 XML_showErrorMessage
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_SHOWERROR
) ),
1177 XML_showInputMessage
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_DV_SHOWPROMPT
) ),
1178 XML_sqref
, XclXmlUtils::ToOString( maScRanges
).getStr(),
1179 XML_type
, lcl_GetValidationType( mnFlags
),
1181 if( msFormula1
.getLength() )
1183 rWorksheet
->startElement( XML_formula1
, FSEND
);
1184 rWorksheet
->writeEscaped( msFormula1
);
1185 rWorksheet
->endElement( XML_formula1
);
1187 if( msFormula2
.getLength() )
1189 rWorksheet
->startElement( XML_formula2
, FSEND
);
1190 rWorksheet
->writeEscaped( msFormula2
);
1191 rWorksheet
->endElement( XML_formula2
);
1193 rWorksheet
->endElement( XML_dataValidation
);
1196 // ----------------------------------------------------------------------------
1198 XclExpDval::XclExpDval( const XclExpRoot
& rRoot
) :
1199 XclExpRecord( EXC_ID_DVAL
, 18 ),
1204 XclExpDval::~XclExpDval()
1208 void XclExpDval::InsertCellRange( const ScRange
& rRange
, ULONG nScHandle
)
1210 if( GetBiff() == EXC_BIFF8
)
1212 XclExpDV
& rDVRec
= SearchOrCreateDv( nScHandle
);
1213 rDVRec
.InsertCellRange( rRange
);
1217 void XclExpDval::Save( XclExpStream
& rStrm
)
1219 // check all records
1220 size_t nPos
= maDVList
.GetSize();
1223 --nPos
; // backwards to keep nPos valid
1224 XclExpDVRef xDVRec
= maDVList
.GetRecord( nPos
);
1225 if( !xDVRec
->Finalize() )
1226 maDVList
.RemoveRecord( nPos
);
1229 // write the DVAL and the DV's
1230 if( !maDVList
.IsEmpty() )
1232 XclExpRecord::Save( rStrm
);
1233 maDVList
.Save( rStrm
);
1237 void XclExpDval::SaveXml( XclExpXmlStream
& rStrm
)
1239 if( maDVList
.IsEmpty() )
1242 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1243 rWorksheet
->startElement( XML_dataValidations
,
1244 XML_count
, OString::valueOf( (sal_Int32
) maDVList
.GetSize() ).getStr(),
1245 // OOXTODO: XML_disablePrompts,
1246 // OOXTODO: XML_xWindow,
1247 // OOXTODO: XML_yWindow,
1249 maDVList
.SaveXml( rStrm
);
1250 rWorksheet
->endElement( XML_dataValidations
);
1253 XclExpDV
& XclExpDval::SearchOrCreateDv( ULONG nScHandle
)
1255 // test last found record
1256 if( mxLastFoundDV
.get() && (mxLastFoundDV
->GetScHandle() == nScHandle
) )
1257 return *mxLastFoundDV
;
1260 size_t nCurrPos
= 0;
1261 if( !maDVList
.IsEmpty() )
1263 size_t nFirstPos
= 0;
1264 size_t nLastPos
= maDVList
.GetSize() - 1;
1266 ULONG nCurrScHandle
= ::std::numeric_limits
< ULONG
>::max();
1267 while( (nFirstPos
<= nLastPos
) && bLoop
)
1269 nCurrPos
= (nFirstPos
+ nLastPos
) / 2;
1270 mxLastFoundDV
= maDVList
.GetRecord( nCurrPos
);
1271 nCurrScHandle
= mxLastFoundDV
->GetScHandle();
1272 if( nCurrScHandle
== nScHandle
)
1274 else if( nCurrScHandle
< nScHandle
)
1275 nFirstPos
= nCurrPos
+ 1;
1277 nLastPos
= nCurrPos
- 1;
1278 else // special case for nLastPos = -1
1281 if( nCurrScHandle
== nScHandle
)
1282 return *mxLastFoundDV
;
1283 else if( nCurrScHandle
< nScHandle
)
1287 // create new DV record
1288 mxLastFoundDV
.reset( new XclExpDV( *this, nScHandle
) );
1289 maDVList
.InsertRecord( mxLastFoundDV
, nCurrPos
);
1290 return *mxLastFoundDV
;
1293 void XclExpDval::WriteBody( XclExpStream
& rStrm
)
1295 rStrm
.WriteZeroBytes( 10 );
1296 rStrm
<< EXC_DVAL_NOOBJ
<< static_cast< sal_uInt32
>( maDVList
.GetSize() );
1299 // Web Queries ================================================================
1301 XclExpWebQuery::XclExpWebQuery(
1302 const String
& rRangeName
,
1304 const String
& rSource
,
1305 sal_Int32 nRefrSecs
) :
1306 maDestRange( rRangeName
),
1308 // refresh delay time: seconds -> minutes
1309 mnRefresh( ulimit_cast
< sal_Int16
>( (nRefrSecs
+ 59L) / 60L ) ),
1310 mbEntireDoc( false )
1312 // comma separated list of HTML table names or indexes
1313 xub_StrLen nTokenCnt
= rSource
.GetTokenCount( ';' );
1314 String aNewTables
, aAppendTable
;
1315 xub_StrLen nStringIx
= 0;
1316 bool bExitLoop
= false;
1317 for( xub_StrLen nToken
= 0; (nToken
< nTokenCnt
) && !bExitLoop
; ++nToken
)
1319 String
aToken( rSource
.GetToken( 0, ';', nStringIx
) );
1320 mbEntireDoc
= ScfTools::IsHTMLDocName( aToken
);
1321 bExitLoop
= mbEntireDoc
|| ScfTools::IsHTMLTablesName( aToken
);
1322 if( !bExitLoop
&& ScfTools::GetHTMLNameFromName( aToken
, aAppendTable
) )
1323 ScGlobal::AddToken( aNewTables
, aAppendTable
, ',' );
1326 if( !bExitLoop
) // neither HTML_all nor HTML_tables found
1328 if( aNewTables
.Len() )
1329 mxQryTables
.reset( new XclExpString( aNewTables
) );
1335 XclExpWebQuery::~XclExpWebQuery()
1339 void XclExpWebQuery::Save( XclExpStream
& rStrm
)
1341 DBG_ASSERT( !mbEntireDoc
|| !mxQryTables
.get(), "XclExpWebQuery::Save - illegal mode" );
1345 rStrm
.StartRecord( EXC_ID_QSI
, 10 + maDestRange
.GetSize() );
1346 rStrm
<< EXC_QSI_DEFAULTFLAGS
1347 << sal_uInt16( 0x0010 )
1348 << sal_uInt16( 0x0012 )
1349 << sal_uInt32( 0x00000000 )
1355 ::insert_value( nFlags
, EXC_PQRYTYPE_WEBQUERY
, 0, 3 );
1356 ::set_flag( nFlags
, EXC_PQRY_WEBQUERY
);
1357 ::set_flag( nFlags
, EXC_PQRY_TABLES
, !mbEntireDoc
);
1358 rStrm
.StartRecord( EXC_ID_PQRY
, 12 );
1360 << sal_uInt16( 0x0000 )
1361 << sal_uInt16( 0x0001 );
1362 rStrm
.WriteZeroBytes( 6 );
1366 rStrm
.StartRecord( EXC_ID_WQSTRING
, maUrl
.GetSize() );
1370 // unknown record 0x0802
1371 rStrm
.StartRecord( EXC_ID_0802
, 16 + maDestRange
.GetSize() );
1372 rStrm
<< EXC_ID_0802
; // repeated record id ?!?
1373 rStrm
.WriteZeroBytes( 6 );
1374 rStrm
<< sal_uInt16( 0x0003 )
1375 << sal_uInt32( 0x00000000 )
1376 << sal_uInt16( 0x0010 )
1380 // WEBQRYSETTINGS record
1381 nFlags
= mxQryTables
.get() ? EXC_WQSETT_SPECTABLES
: EXC_WQSETT_ALL
;
1382 rStrm
.StartRecord( EXC_ID_WQSETT
, 28 );
1383 rStrm
<< EXC_ID_WQSETT
// repeated record id ?!?
1384 << sal_uInt16( 0x0000 )
1385 << sal_uInt16( 0x0004 )
1386 << sal_uInt16( 0x0000 )
1387 << EXC_WQSETT_DEFAULTFLAGS
1389 rStrm
.WriteZeroBytes( 10 );
1390 rStrm
<< mnRefresh
// refresh delay in minutes
1391 << EXC_WQSETT_FORMATFULL
1392 << sal_uInt16( 0x0000 );
1395 // WEBQRYTABLES record
1396 if( mxQryTables
.get() )
1398 rStrm
.StartRecord( EXC_ID_WQTABLES
, 4 + mxQryTables
->GetSize() );
1399 rStrm
<< EXC_ID_WQTABLES
// repeated record id ?!?
1400 << sal_uInt16( 0x0000 )
1401 << *mxQryTables
; // comma separated list of source tables
1406 // ----------------------------------------------------------------------------
1408 XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot
& rRoot
)
1410 SCTAB nScTab
= rRoot
.GetCurrScTab();
1411 SfxObjectShell
* pShell
= rRoot
.GetDocShell();
1412 if( !pShell
) return;
1413 ScfPropertySet
aModelProp( pShell
->GetModel() );
1414 if( !aModelProp
.Is() ) return;
1416 Reference
< XAreaLinks
> xAreaLinks
;
1417 aModelProp
.GetProperty( xAreaLinks
, CREATE_OUSTRING( SC_UNO_AREALINKS
) );
1418 Reference
< XIndexAccess
> xLinksIA( xAreaLinks
, UNO_QUERY
);
1419 if( !xLinksIA
.is() ) return;
1421 for( sal_Int32 nIndex
= 0, nCount
= xLinksIA
->getCount(); nIndex
< nCount
; ++nIndex
)
1423 Reference
< XAreaLink
> xAreaLink( xLinksIA
->getByIndex( nIndex
), UNO_QUERY
);
1424 if( xAreaLink
.is() )
1426 CellRangeAddress
aDestRange( xAreaLink
->getDestArea() );
1427 if( static_cast< SCTAB
>( aDestRange
.Sheet
) == nScTab
)
1429 ScfPropertySet
aLinkProp( xAreaLink
);
1431 if( aLinkProp
.GetProperty( aFilter
, CREATE_OUSTRING( SC_UNONAME_FILTER
) ) &&
1432 (aFilter
== CREATE_OUSTRING( EXC_WEBQRY_FILTER
)) )
1435 OUString
/*aFilterOpt,*/ aUrl
;
1436 sal_Int32 nRefresh
= 0;
1438 // aLinkProp.GetProperty( aFilterOpt, CREATE_OUSTRING( SC_UNONAME_FILTOPT ) );
1439 aLinkProp
.GetProperty( aUrl
, CREATE_OUSTRING( SC_UNONAME_LINKURL
) );
1440 aLinkProp
.GetProperty( nRefresh
, CREATE_OUSTRING( SC_UNONAME_REFDELAY
) );
1442 String
aAbsDoc( ScGlobal::GetAbsDocName( aUrl
, pShell
) );
1443 INetURLObject
aUrlObj( aAbsDoc
);
1444 String
aWebQueryUrl( aUrlObj
.getFSysPath( INetURLObject::FSYS_DOS
) );
1445 if( !aWebQueryUrl
.Len() )
1446 aWebQueryUrl
= aAbsDoc
;
1448 // find range or create a new range
1450 ScRange aScDestRange
;
1451 ScUnoConversion::FillScRange( aScDestRange
, aDestRange
);
1452 if( const ScRangeData
* pRangeData
= rRoot
.GetNamedRanges().GetRangeAtBlock( aScDestRange
) )
1454 aRangeName
= pRangeData
->GetName();
1458 XclExpFormulaCompiler
& rFmlaComp
= rRoot
.GetFormulaCompiler();
1459 XclExpNameManager
& rNameMgr
= rRoot
.GetNameManager();
1461 // create a new unique defined name containing the range
1462 XclTokenArrayRef xTokArr
= rFmlaComp
.CreateFormula( EXC_FMLATYPE_WQUERY
, aScDestRange
);
1463 sal_uInt16 nNameIdx
= rNameMgr
.InsertUniqueName( aUrlObj
.getBase(), xTokArr
, nScTab
);
1464 aRangeName
= rNameMgr
.GetOrigName( nNameIdx
);
1467 // create and store the web query record
1468 if( aRangeName
.Len() )
1469 AppendNewRecord( new XclExpWebQuery(
1470 aRangeName
, aWebQueryUrl
, xAreaLink
->getSourceArea(), nRefresh
) );
1477 // ============================================================================