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