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