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 <com/sun/star/i18n/XBreakIterator.hpp>
21 : #include <com/sun/star/i18n/ScriptType.hpp>
22 : #include <sfx2/objsh.hxx>
23 : #include <vcl/font.hxx>
24 : #include <tools/urlobj.hxx>
25 : #include <svl/itemset.hxx>
26 : #include <svtools/ctrltool.hxx>
27 : #include <svx/svdotext.hxx>
28 : #include <editeng/outlobj.hxx>
29 : #include "scitems.hxx"
30 : #include <editeng/fhgtitem.hxx>
31 : #include <editeng/flstitem.hxx>
32 : #include <editeng/colritem.hxx>
33 : #include <editeng/eeitem.hxx>
34 : #include <editeng/flditem.hxx>
35 : #include <editeng/escpitem.hxx>
36 : #include <editeng/svxfont.hxx>
37 :
38 : #include "document.hxx"
39 : #include "docpool.hxx"
40 : #include "cell.hxx"
41 : #include "editutil.hxx"
42 : #include "patattr.hxx"
43 : #include "xestyle.hxx"
44 : #include "fprogressbar.hxx"
45 : #include "xltracer.hxx"
46 : #include "xecontent.hxx"
47 : #include "xelink.hxx"
48 : #include "xehelper.hxx"
49 :
50 : using ::rtl::OUString;
51 : using ::com::sun::star::uno::Reference;
52 : using ::com::sun::star::i18n::XBreakIterator;
53 :
54 : // Export progress bar ========================================================
55 :
56 1 : XclExpProgressBar::XclExpProgressBar( const XclExpRoot& rRoot ) :
57 : XclExpRoot( rRoot ),
58 2 : mxProgress( new ScfProgressBar( rRoot.GetDocShell(), STR_SAVE_DOC ) ),
59 : mpSubProgress( 0 ),
60 : mpSubRowCreate( 0 ),
61 : mpSubRowFinal( 0 ),
62 : mnSegRowFinal( SCF_INV_SEGMENT ),
63 3 : mnRowCount( 0 )
64 : {
65 1 : }
66 :
67 2 : XclExpProgressBar::~XclExpProgressBar()
68 : {
69 2 : }
70 :
71 1 : void XclExpProgressBar::Initialize()
72 : {
73 1 : const ScDocument& rDoc = GetDoc();
74 1 : const XclExpTabInfo& rTabInfo = GetTabInfo();
75 1 : SCTAB nScTabCount = rTabInfo.GetScTabCount();
76 :
77 : // *** segment: creation of ROW records *** -------------------------------
78 :
79 1 : sal_Int32 nSegRowCreate = mxProgress->AddSegment( 2000 );
80 1 : mpSubRowCreate = &mxProgress->GetSegmentProgressBar( nSegRowCreate );
81 1 : maSubSegRowCreate.resize( nScTabCount, SCF_INV_SEGMENT );
82 :
83 2 : for( SCTAB nScTab = 0; nScTab < nScTabCount; ++nScTab )
84 : {
85 1 : if( rTabInfo.IsExportTab( nScTab ) )
86 : {
87 : SCCOL nLastUsedScCol;
88 : SCROW nLastUsedScRow;
89 1 : rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
90 1 : sal_Size nSegSize = static_cast< sal_Size >( nLastUsedScRow + 1 );
91 1 : maSubSegRowCreate[ nScTab ] = mpSubRowCreate->AddSegment( nSegSize );
92 : }
93 : }
94 :
95 : // *** segment: writing all ROW records *** -------------------------------
96 :
97 1 : mnSegRowFinal = mxProgress->AddSegment( 1000 );
98 : // sub progress bar and segment are created later in ActivateFinalRowsSegment()
99 1 : }
100 :
101 23 : void XclExpProgressBar::IncRowRecordCount()
102 : {
103 23 : ++mnRowCount;
104 23 : }
105 :
106 1 : void XclExpProgressBar::ActivateCreateRowsSegment()
107 : {
108 : OSL_ENSURE( (0 <= GetCurrScTab()) && (GetCurrScTab() < GetTabInfo().GetScTabCount()),
109 : "XclExpProgressBar::ActivateCreateRowsSegment - invalid sheet" );
110 1 : sal_Int32 nSeg = maSubSegRowCreate[ GetCurrScTab() ];
111 : OSL_ENSURE( nSeg != SCF_INV_SEGMENT, "XclExpProgressBar::ActivateCreateRowsSegment - invalid segment" );
112 1 : if( nSeg != SCF_INV_SEGMENT )
113 : {
114 1 : mpSubProgress = mpSubRowCreate;
115 1 : mpSubProgress->ActivateSegment( nSeg );
116 : }
117 : else
118 0 : mpSubProgress = 0;
119 1 : }
120 :
121 1 : void XclExpProgressBar::ActivateFinalRowsSegment()
122 : {
123 1 : if( !mpSubRowFinal && (mnRowCount > 0) )
124 : {
125 1 : mpSubRowFinal = &mxProgress->GetSegmentProgressBar( mnSegRowFinal );
126 1 : mpSubRowFinal->AddSegment( mnRowCount );
127 : }
128 1 : mpSubProgress = mpSubRowFinal;
129 1 : if( mpSubProgress )
130 1 : mpSubProgress->Activate();
131 1 : }
132 :
133 46 : void XclExpProgressBar::Progress()
134 : {
135 46 : if( mpSubProgress && !mpSubProgress->IsFull() )
136 45 : mpSubProgress->Progress();
137 46 : }
138 :
139 : // Calc->Excel cell address/range conversion ==================================
140 :
141 : namespace {
142 :
143 : /** Fills the passed Excel address with the passed Calc cell coordinates without checking any limits. */
144 16 : inline void lclFillAddress( XclAddress& rXclPos, SCCOL nScCol, SCROW nScRow )
145 : {
146 16 : rXclPos.mnCol = static_cast< sal_uInt16 >( nScCol );
147 16 : rXclPos.mnRow = static_cast< sal_uInt32 >( nScRow );
148 16 : }
149 :
150 : } // namespace
151 :
152 : // ----------------------------------------------------------------------------
153 :
154 1 : XclExpAddressConverter::XclExpAddressConverter( const XclExpRoot& rRoot ) :
155 1 : XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetXclMaxPos() )
156 : {
157 1 : }
158 :
159 : // cell address ---------------------------------------------------------------
160 :
161 18 : bool XclExpAddressConverter::CheckAddress( const ScAddress& rScPos, bool bWarn )
162 : {
163 : // ScAddress::operator<=() doesn't do what we want here
164 18 : bool bValidCol = (0 <= rScPos.Col()) && (rScPos.Col() <= maMaxPos.Col());
165 18 : bool bValidRow = (0 <= rScPos.Row()) && (rScPos.Row() <= maMaxPos.Row());
166 18 : bool bValidTab = (0 <= rScPos.Tab()) && (rScPos.Tab() <= maMaxPos.Tab());
167 :
168 18 : bool bValid = bValidCol && bValidRow && bValidTab;
169 18 : if( !bValid && bWarn )
170 : {
171 0 : mbColTrunc |= !bValidCol;
172 0 : mbRowTrunc |= !bValidRow;
173 0 : mbTabTrunc |= (rScPos.Tab() > maMaxPos.Tab()); // do not warn for deleted refs
174 0 : mrTracer.TraceInvalidAddress( rScPos, maMaxPos );
175 : }
176 18 : return bValid;
177 : }
178 :
179 0 : bool XclExpAddressConverter::ConvertAddress( XclAddress& rXclPos,
180 : const ScAddress& rScPos, bool bWarn )
181 : {
182 0 : bool bValid = CheckAddress( rScPos, bWarn );
183 0 : if( bValid )
184 0 : lclFillAddress( rXclPos, rScPos.Col(), rScPos.Row() );
185 0 : return bValid;
186 : }
187 :
188 0 : XclAddress XclExpAddressConverter::CreateValidAddress( const ScAddress& rScPos, bool bWarn )
189 : {
190 0 : XclAddress aXclPos( ScAddress::UNINITIALIZED );
191 0 : if( !ConvertAddress( aXclPos, rScPos, bWarn ) )
192 0 : lclFillAddress( aXclPos, ::std::min( rScPos.Col(), maMaxPos.Col() ), ::std::min( rScPos.Row(), maMaxPos.Row() ) );
193 0 : return aXclPos;
194 : }
195 :
196 : // cell range -----------------------------------------------------------------
197 :
198 0 : bool XclExpAddressConverter::CheckRange( const ScRange& rScRange, bool bWarn )
199 : {
200 0 : return CheckAddress( rScRange.aStart, bWarn ) && CheckAddress( rScRange.aEnd, bWarn );
201 : }
202 :
203 1 : bool XclExpAddressConverter::ValidateRange( ScRange& rScRange, bool bWarn )
204 : {
205 1 : rScRange.Justify();
206 :
207 : // check start position
208 1 : bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
209 1 : if( bValidStart )
210 : {
211 : // check & correct end position
212 1 : ScAddress& rScEnd = rScRange.aEnd;
213 1 : if( !CheckAddress( rScEnd, bWarn ) )
214 : {
215 0 : rScEnd.SetCol( ::std::min( rScEnd.Col(), maMaxPos.Col() ) );
216 0 : rScEnd.SetRow( ::std::min( rScEnd.Row(), maMaxPos.Row() ) );
217 0 : rScEnd.SetTab( ::std::min( rScEnd.Tab(), maMaxPos.Tab() ) );
218 : }
219 : }
220 :
221 1 : return bValidStart;
222 : }
223 :
224 8 : bool XclExpAddressConverter::ConvertRange( XclRange& rXclRange,
225 : const ScRange& rScRange, bool bWarn )
226 : {
227 : // check start position
228 8 : bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
229 8 : if( bValidStart )
230 : {
231 8 : lclFillAddress( rXclRange.maFirst, rScRange.aStart.Col(), rScRange.aStart.Row() );
232 :
233 : // check & correct end position
234 8 : SCCOL nScCol2 = rScRange.aEnd.Col();
235 8 : SCROW nScRow2 = rScRange.aEnd.Row();
236 8 : if( !CheckAddress( rScRange.aEnd, bWarn ) )
237 : {
238 0 : nScCol2 = ::std::min( nScCol2, maMaxPos.Col() );
239 0 : nScRow2 = ::std::min( nScRow2, maMaxPos.Row() );
240 : }
241 8 : lclFillAddress( rXclRange.maLast, nScCol2, nScRow2 );
242 : }
243 8 : return bValidStart;
244 : }
245 :
246 : // cell range list ------------------------------------------------------------
247 :
248 2 : void XclExpAddressConverter::ValidateRangeList( ScRangeList& rScRanges, bool bWarn )
249 : {
250 4 : for ( size_t nRange = rScRanges.size(); nRange > 0; )
251 : {
252 0 : ScRange* pScRange = rScRanges[ --nRange ];
253 0 : if( !CheckRange( *pScRange, bWarn ) )
254 0 : delete rScRanges.Remove(nRange);
255 : }
256 2 : }
257 :
258 8 : void XclExpAddressConverter::ConvertRangeList( XclRangeList& rXclRanges,
259 : const ScRangeList& rScRanges, bool bWarn )
260 : {
261 8 : rXclRanges.clear();
262 16 : for( size_t nPos = 0, nCount = rScRanges.size(); nPos < nCount; ++nPos )
263 : {
264 8 : if( const ScRange* pScRange = rScRanges[ nPos ] )
265 : {
266 8 : XclRange aXclRange( ScAddress::UNINITIALIZED );
267 8 : if( ConvertRange( aXclRange, *pScRange, bWarn ) )
268 8 : rXclRanges.push_back( aXclRange );
269 : }
270 : }
271 8 : }
272 :
273 : // EditEngine->String conversion ==============================================
274 :
275 : namespace {
276 :
277 0 : rtl::OUString lclGetUrlRepresentation( const SvxURLField& rUrlField )
278 : {
279 0 : const rtl::OUString& aRepr = rUrlField.GetRepresentation();
280 : // no representation -> use URL
281 0 : return aRepr.isEmpty() ? rUrlField.GetURL() : aRepr;
282 : }
283 :
284 : } // namespace
285 :
286 : // ----------------------------------------------------------------------------
287 :
288 0 : XclExpHyperlinkHelper::XclExpHyperlinkHelper( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
289 : XclExpRoot( rRoot ),
290 : maScPos( rScPos ),
291 0 : mbMultipleUrls( false )
292 : {
293 0 : }
294 :
295 0 : XclExpHyperlinkHelper::~XclExpHyperlinkHelper()
296 : {
297 0 : }
298 :
299 0 : rtl::OUString XclExpHyperlinkHelper::ProcessUrlField( const SvxURLField& rUrlField )
300 : {
301 0 : rtl::OUString aUrlRepr;
302 :
303 0 : if( GetBiff() == EXC_BIFF8 ) // no HLINK records in BIFF2-BIFF7
304 : {
305 : // there was/is already a HLINK record
306 0 : mbMultipleUrls = mxLinkRec;
307 :
308 0 : mxLinkRec.reset( new XclExpHyperlink( GetRoot(), rUrlField, maScPos ) );
309 :
310 0 : if( const String* pRepr = mxLinkRec->GetRepr() )
311 0 : aUrlRepr = *pRepr;
312 :
313 : // add URL to note text
314 0 : maUrlList = ScGlobal::addToken( maUrlList, rUrlField.GetURL(), '\n' );
315 : }
316 :
317 : // no hyperlink representation from Excel HLINK record -> use it from text field
318 0 : return aUrlRepr.isEmpty() ? lclGetUrlRepresentation(rUrlField) : aUrlRepr;
319 : }
320 :
321 0 : bool XclExpHyperlinkHelper::HasLinkRecord() const
322 : {
323 0 : return !mbMultipleUrls && mxLinkRec;
324 : }
325 :
326 0 : XclExpHyperlinkHelper::XclExpHyperlinkRef XclExpHyperlinkHelper::GetLinkRecord()
327 : {
328 0 : if( HasLinkRecord() )
329 0 : return mxLinkRec;
330 0 : return XclExpHyperlinkRef();
331 : }
332 :
333 : // ----------------------------------------------------------------------------
334 :
335 : namespace {
336 :
337 : /** Creates a new formatted string from the passed unformatted string.
338 :
339 : Creates a Unicode string or a byte string, depending on the current BIFF
340 : version contained in the passed XclExpRoot object. May create a formatted
341 : string object, if the text contains different script types.
342 :
343 : @param pCellAttr
344 : Cell attributes used for font formatting.
345 : @param nFlags
346 : Modifiers for string export.
347 : @param nMaxLen
348 : The maximum number of characters to store in this string.
349 : @return
350 : The new string object.
351 : */
352 8 : XclExpStringRef lclCreateFormattedString(
353 : const XclExpRoot& rRoot, const String& rText, const ScPatternAttr* pCellAttr,
354 : XclStrFlags nFlags, sal_uInt16 nMaxLen )
355 : {
356 : /* Create an empty Excel string object with correctly initialized BIFF mode,
357 : because this function only uses Append() functions that require this. */
358 8 : XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
359 :
360 : // script type handling
361 8 : Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
362 : namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
363 : // #i63255# get script type for leading weak characters
364 8 : sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rText );
365 :
366 : // font buffer and cell item set
367 8 : XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
368 8 : const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
369 :
370 : // process all script portions
371 8 : OUString aOUText( rText );
372 8 : sal_Int32 nPortionPos = 0;
373 8 : sal_Int32 nTextLen = aOUText.getLength();
374 24 : while( nPortionPos < nTextLen )
375 : {
376 : // get script type and end position of next script portion
377 8 : sal_Int16 nScript = xBreakIt->getScriptType( aOUText, nPortionPos );
378 8 : sal_Int32 nPortionEnd = xBreakIt->endOfScript( aOUText, nPortionPos, nScript );
379 :
380 : // reuse previous script for following weak portions
381 8 : if( nScript == ApiScriptType::WEAK )
382 0 : nScript = nLastScript;
383 :
384 : // construct font from current text portion
385 8 : SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, rItemSet, nScript ) );
386 :
387 : // Excel start position of this portion
388 8 : sal_uInt16 nXclPortionStart = xString->Len();
389 : // add portion text to Excel string
390 8 : XclExpStringHelper::AppendString( *xString, rRoot, aOUText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
391 8 : if( nXclPortionStart < xString->Len() )
392 : {
393 : // insert font into buffer
394 8 : sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
395 : // insert font index into format run vector
396 8 : xString->AppendFormat( nXclPortionStart, nFontIdx );
397 : }
398 :
399 : // go to next script portion
400 8 : nLastScript = nScript;
401 8 : nPortionPos = nPortionEnd;
402 8 : }
403 :
404 8 : return xString;
405 : }
406 :
407 : /** Creates a new formatted string from an edit engine text object.
408 :
409 : Creates a Unicode string or a byte string, depending on the current BIFF
410 : version contained in the passed XclExpRoot object.
411 :
412 : @param rEE
413 : The edit engine in use. The text object must already be set.
414 : @param nFlags
415 : Modifiers for string export.
416 : @param nMaxLen
417 : The maximum number of characters to store in this string.
418 : @return
419 : The new string object.
420 : */
421 0 : XclExpStringRef lclCreateFormattedString(
422 : const XclExpRoot& rRoot, EditEngine& rEE, XclExpHyperlinkHelper* pLinkHelper,
423 : XclStrFlags nFlags, sal_uInt16 nMaxLen )
424 : {
425 : /* Create an empty Excel string object with correctly initialized BIFF mode,
426 : because this function only uses Append() functions that require this. */
427 0 : XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
428 :
429 : // font buffer and helper item set for edit engine -> Calc item conversion
430 0 : XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
431 0 : SfxItemSet aItemSet( *rRoot.GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
432 :
433 : // script type handling
434 0 : Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
435 : namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
436 : // #i63255# get script type for leading weak characters
437 0 : sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rEE.GetText() );
438 :
439 : // process all paragraphs
440 0 : sal_uInt16 nParaCount = rEE.GetParagraphCount();
441 0 : for( sal_uInt16 nPara = 0; nPara < nParaCount; ++nPara )
442 : {
443 0 : ESelection aSel( nPara, 0 );
444 0 : String aParaText( rEE.GetText( nPara ) );
445 :
446 0 : std::vector<sal_uInt16> aPosList;
447 0 : rEE.GetPortions( nPara, aPosList );
448 :
449 : // process all portions in the paragraph
450 0 : for( std::vector<sal_uInt16>::const_iterator it(aPosList.begin()); it != aPosList.end(); ++it )
451 : {
452 0 : aSel.nEndPos = static_cast< xub_StrLen >( *it );
453 0 : String aXclPortionText( aParaText, aSel.nStartPos, aSel.nEndPos - aSel.nStartPos );
454 :
455 0 : aItemSet.ClearItem();
456 0 : SfxItemSet aEditSet( rEE.GetAttribs( aSel ) );
457 0 : ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
458 :
459 : // get escapement value
460 0 : short nEsc = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT ).GetEsc();
461 :
462 : // process text fields
463 0 : bool bIsHyperlink = false;
464 0 : if( aSel.nStartPos + 1 == aSel.nEndPos )
465 : {
466 : // test if the character is a text field
467 : const SfxPoolItem* pItem;
468 0 : if( aEditSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SFX_ITEM_SET )
469 : {
470 0 : const SvxFieldData* pField = static_cast< const SvxFieldItem* >( pItem )->GetField();
471 0 : if( const SvxURLField* pUrlField = PTR_CAST( SvxURLField, pField ) )
472 : {
473 : // convert URL field to string representation
474 : aXclPortionText = pLinkHelper ?
475 : pLinkHelper->ProcessUrlField( *pUrlField ) :
476 0 : lclGetUrlRepresentation( *pUrlField );
477 0 : bIsHyperlink = true;
478 : }
479 : else
480 : {
481 : OSL_FAIL( "lclCreateFormattedString - unknown text field" );
482 0 : aXclPortionText.Erase();
483 : }
484 : }
485 : }
486 :
487 : // Excel start position of this portion
488 0 : sal_uInt16 nXclPortionStart = xString->Len();
489 : // add portion text to Excel string
490 0 : XclExpStringHelper::AppendString( *xString, rRoot, aXclPortionText );
491 0 : if( (nXclPortionStart < xString->Len()) || (aParaText.Len() == 0) )
492 : {
493 : /* Construct font from current edit engine text portion. Edit engine
494 : creates different portions for different script types, no need to loop. */
495 0 : sal_Int16 nScript = xBreakIt->getScriptType( aXclPortionText, 0 );
496 0 : if( nScript == ApiScriptType::WEAK )
497 0 : nScript = nLastScript;
498 0 : SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, aItemSet, nScript ) );
499 0 : nLastScript = nScript;
500 :
501 : // add escapement
502 0 : aFont.SetEscapement( nEsc );
503 : // modify automatic font color for hyperlinks
504 0 : if( bIsHyperlink && (GETITEM( aItemSet, SvxColorItem, ATTR_FONT_COLOR ).GetValue().GetColor() == COL_AUTO) )
505 0 : aFont.SetColor( Color( COL_LIGHTBLUE ) );
506 :
507 : // insert font into buffer
508 0 : sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
509 : // insert font index into format run vector
510 0 : xString->AppendFormat( nXclPortionStart, nFontIdx );
511 : }
512 :
513 0 : aSel.nStartPos = aSel.nEndPos;
514 0 : }
515 :
516 : // add trailing newline (important for correct character index calculation)
517 0 : if( nPara + 1 < nParaCount )
518 0 : XclExpStringHelper::AppendChar( *xString, rRoot, '\n' );
519 0 : }
520 :
521 0 : return xString;
522 : }
523 :
524 : } // namespace
525 :
526 : // ----------------------------------------------------------------------------
527 :
528 8 : XclExpStringRef XclExpStringHelper::CreateString(
529 : const XclExpRoot& rRoot, const String& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
530 : {
531 8 : XclExpStringRef xString( new XclExpString );
532 8 : if( rRoot.GetBiff() == EXC_BIFF8 )
533 8 : xString->Assign( rString, nFlags, nMaxLen );
534 : else
535 0 : xString->AssignByte( rString, rRoot.GetTextEncoding(), nFlags, nMaxLen );
536 8 : return xString;
537 : }
538 :
539 0 : XclExpStringRef XclExpStringHelper::CreateString(
540 : const XclExpRoot& rRoot, sal_Unicode cChar, XclStrFlags nFlags, sal_uInt16 nMaxLen )
541 : {
542 0 : XclExpStringRef xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
543 0 : AppendChar( *xString, rRoot, cChar );
544 0 : return xString;
545 : }
546 :
547 8 : void XclExpStringHelper::AppendString( XclExpString& rXclString, const XclExpRoot& rRoot, const String& rString )
548 : {
549 8 : if( rRoot.GetBiff() == EXC_BIFF8 )
550 8 : rXclString.Append( rString );
551 : else
552 0 : rXclString.AppendByte( rString, rRoot.GetTextEncoding() );
553 8 : }
554 :
555 0 : void XclExpStringHelper::AppendChar( XclExpString& rXclString, const XclExpRoot& rRoot, sal_Unicode cChar )
556 : {
557 0 : if( rRoot.GetBiff() == EXC_BIFF8 )
558 0 : rXclString.Append( rtl::OUString(cChar) );
559 : else
560 0 : rXclString.AppendByte( cChar, rRoot.GetTextEncoding() );
561 0 : }
562 :
563 8 : XclExpStringRef XclExpStringHelper::CreateCellString(
564 : const XclExpRoot& rRoot, const ScStringCell& rStringCell, const ScPatternAttr* pCellAttr,
565 : XclStrFlags nFlags, sal_uInt16 nMaxLen )
566 : {
567 8 : rtl::OUString aCellText = rStringCell.GetString();
568 8 : return lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
569 : }
570 :
571 0 : XclExpStringRef XclExpStringHelper::CreateCellString(
572 : const XclExpRoot& rRoot, const ScEditCell& rEditCell, const ScPatternAttr* pCellAttr,
573 : XclExpHyperlinkHelper& rLinkHelper, XclStrFlags nFlags, sal_uInt16 nMaxLen )
574 : {
575 0 : XclExpStringRef xString;
576 0 : if( const EditTextObject* pEditObj = rEditCell.GetData() )
577 : {
578 : // formatted cell
579 0 : ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
580 0 : sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
581 0 : rEE.SetUpdateMode( sal_True );
582 : // default items
583 0 : const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
584 0 : SfxItemSet* pEEItemSet = new SfxItemSet( rEE.GetEmptyItemSet() );
585 0 : ScPatternAttr::FillToEditItemSet( *pEEItemSet, rItemSet );
586 0 : rEE.SetDefaults( pEEItemSet ); // edit engine takes ownership
587 : // create the string
588 0 : rEE.SetText( *pEditObj );
589 0 : xString = lclCreateFormattedString( rRoot, rEE, &rLinkHelper, nFlags, nMaxLen );
590 0 : rEE.SetUpdateMode( bOldUpdateMode );
591 : }
592 : else
593 : {
594 : // unformatted cell
595 0 : String aCellText = rEditCell.GetString();
596 0 : xString = lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
597 : }
598 0 : return xString;
599 : }
600 :
601 0 : XclExpStringRef XclExpStringHelper::CreateString(
602 : const XclExpRoot& rRoot, const SdrTextObj& rTextObj,
603 : XclStrFlags nFlags, sal_uInt16 nMaxLen )
604 : {
605 0 : XclExpStringRef xString;
606 0 : if( const OutlinerParaObject* pParaObj = rTextObj.GetOutlinerParaObject() )
607 : {
608 0 : EditEngine& rEE = rRoot.GetDrawEditEngine();
609 0 : sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
610 0 : rEE.SetUpdateMode( sal_True );
611 : // create the string
612 0 : rEE.SetText( pParaObj->GetTextObject() );
613 0 : xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
614 0 : rEE.SetUpdateMode( bOldUpdateMode );
615 : // limit formats - TODO: BIFF dependent
616 0 : if( !xString->IsEmpty() )
617 : {
618 0 : xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
619 0 : xString->AppendTrailingFormat( EXC_FONT_APP );
620 : }
621 : }
622 : else
623 : {
624 : OSL_FAIL( "XclExpStringHelper::CreateString - textbox without para object" );
625 : // create BIFF dependent empty Excel string
626 0 : xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
627 : }
628 0 : return xString;
629 : }
630 :
631 0 : XclExpStringRef XclExpStringHelper::CreateString(
632 : const XclExpRoot& rRoot, const EditTextObject& rEditObj,
633 : XclStrFlags nFlags, sal_uInt16 nMaxLen )
634 : {
635 0 : XclExpStringRef xString;
636 0 : EditEngine& rEE = rRoot.GetDrawEditEngine();
637 0 : sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
638 0 : rEE.SetUpdateMode( sal_True );
639 0 : rEE.SetText( rEditObj );
640 0 : xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
641 0 : rEE.SetUpdateMode( bOldUpdateMode );
642 : // limit formats - TODO: BIFF dependent
643 0 : if( !xString->IsEmpty() )
644 : {
645 0 : xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
646 0 : xString->AppendTrailingFormat( EXC_FONT_APP );
647 : }
648 0 : return xString;
649 : }
650 :
651 8 : sal_Int16 XclExpStringHelper::GetLeadingScriptType( const XclExpRoot& rRoot, const String& rString )
652 : {
653 : namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
654 8 : Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
655 8 : OUString aOUString( rString );
656 8 : sal_Int32 nStrPos = 0;
657 8 : sal_Int32 nStrLen = aOUString.getLength();
658 8 : sal_Int16 nScript = ApiScriptType::WEAK;
659 24 : while( (nStrPos < nStrLen) && (nScript == ApiScriptType::WEAK) )
660 : {
661 8 : nScript = xBreakIt->getScriptType( aOUString, nStrPos );
662 8 : nStrPos = xBreakIt->endOfScript( aOUString, nStrPos, nScript );
663 : }
664 8 : return (nScript == ApiScriptType::WEAK) ? rRoot.GetDefApiScript() : nScript;
665 : }
666 :
667 : // Header/footer conversion ===================================================
668 :
669 1 : XclExpHFConverter::XclExpHFConverter( const XclExpRoot& rRoot ) :
670 : XclExpRoot( rRoot ),
671 1 : mrEE( rRoot.GetHFEditEngine() ),
672 2 : mnTotalHeight( 0 )
673 : {
674 1 : }
675 :
676 0 : void XclExpHFConverter::GenerateString(
677 : const EditTextObject* pLeftObj,
678 : const EditTextObject* pCenterObj,
679 : const EditTextObject* pRightObj )
680 : {
681 0 : maHFString.Erase();
682 0 : mnTotalHeight = 0;
683 0 : AppendPortion( pLeftObj, 'L' );
684 0 : AppendPortion( pCenterObj, 'C' );
685 0 : AppendPortion( pRightObj, 'R' );
686 0 : }
687 :
688 0 : void XclExpHFConverter::AppendPortion( const EditTextObject* pTextObj, sal_Unicode cPortionCode )
689 : {
690 0 : if( !pTextObj ) return;
691 :
692 0 : String aText;
693 0 : sal_Int32 nHeight = 0;
694 0 : SfxItemSet aItemSet( *GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
695 :
696 : // edit engine
697 0 : sal_Bool bOldUpdateMode = mrEE.GetUpdateMode();
698 0 : mrEE.SetUpdateMode( sal_True );
699 0 : mrEE.SetText( *pTextObj );
700 :
701 : // font information
702 0 : XclFontData aFontData, aNewData;
703 0 : if( const XclExpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
704 : {
705 0 : aFontData = pFirstFont->GetFontData();
706 0 : (aFontData.mnHeight += 10) /= 20; // using pt here, not twips
707 : }
708 : else
709 0 : aFontData.mnHeight = 10;
710 :
711 0 : const FontList* pFontList = 0;
712 0 : if( SfxObjectShell* pDocShell = GetDocShell() )
713 : {
714 0 : if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
715 0 : pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
716 0 : pFontList = pInfoItem->GetFontList();
717 : }
718 :
719 0 : sal_uInt16 nParaCount = mrEE.GetParagraphCount();
720 0 : for( sal_uInt16 nPara = 0; nPara < nParaCount; ++nPara )
721 : {
722 0 : ESelection aSel( nPara, 0 );
723 0 : String aParaText;
724 0 : sal_Int32 nParaHeight = 0;
725 0 : std::vector<sal_uInt16> aPosList;
726 0 : mrEE.GetPortions( nPara, aPosList );
727 :
728 0 : for( std::vector<sal_uInt16>::const_iterator it( aPosList.begin() ); it != aPosList.end(); ++it )
729 : {
730 0 : aSel.nEndPos = static_cast< xub_StrLen >( *it );
731 0 : if( aSel.nStartPos < aSel.nEndPos )
732 : {
733 :
734 : // --- font attributes ---
735 :
736 0 : Font aFont;
737 0 : aItemSet.ClearItem();
738 0 : SfxItemSet aEditSet( mrEE.GetAttribs( aSel ) );
739 0 : ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
740 0 : ScPatternAttr::GetFont( aFont, aItemSet, SC_AUTOCOL_RAW );
741 :
742 : // font name and style
743 0 : aNewData.maName = XclTools::GetXclFontName( aFont.GetName() );
744 0 : aNewData.mnWeight = (aFont.GetWeight() > WEIGHT_NORMAL) ? EXC_FONTWGHT_BOLD : EXC_FONTWGHT_NORMAL;
745 0 : aNewData.mbItalic = (aFont.GetItalic() != ITALIC_NONE);
746 0 : bool bNewFont = !(aFontData.maName == aNewData.maName);
747 : bool bNewStyle = (aFontData.mnWeight != aNewData.mnWeight) ||
748 0 : (aFontData.mbItalic != aNewData.mbItalic);
749 0 : if( bNewFont || (bNewStyle && pFontList) )
750 : {
751 0 : aParaText.AppendAscii( "&\"" ).Append( aNewData.maName );
752 0 : if( pFontList )
753 : {
754 : FontInfo aFontInfo( pFontList->Get(
755 : aNewData.maName,
756 : (aNewData.mnWeight > EXC_FONTWGHT_NORMAL) ? WEIGHT_BOLD : WEIGHT_NORMAL,
757 0 : aNewData.mbItalic ? ITALIC_NORMAL : ITALIC_NONE ) );
758 0 : aNewData.maStyle = pFontList->GetStyleName( aFontInfo );
759 0 : if( aNewData.maStyle.Len() )
760 0 : aParaText.Append( ',' ).Append( aNewData.maStyle );
761 : }
762 0 : aParaText.Append( '"' );
763 : }
764 :
765 : // height
766 : // is calculated wrong in ScPatternAttr::GetFromEditItemSet, because already in twips and not 100thmm
767 : // -> get it directly from edit engine item set
768 0 : aNewData.mnHeight = ulimit_cast< sal_uInt16 >( GETITEM( aEditSet, SvxFontHeightItem, EE_CHAR_FONTHEIGHT ).GetHeight() );
769 0 : (aNewData.mnHeight += 10) /= 20;
770 0 : bool bFontHtChanged = (aFontData.mnHeight != aNewData.mnHeight);
771 0 : if( bFontHtChanged )
772 0 : aParaText.Append( '&' ).Append( String::CreateFromInt32( aNewData.mnHeight ) );
773 : // update maximum paragraph height, convert to twips
774 0 : nParaHeight = ::std::max< sal_Int32 >( nParaHeight, aNewData.mnHeight * 20 );
775 :
776 : // underline
777 0 : aNewData.mnUnderline = EXC_FONTUNDERL_NONE;
778 0 : switch( aFont.GetUnderline() )
779 : {
780 0 : case UNDERLINE_NONE: aNewData.mnUnderline = EXC_FONTUNDERL_NONE; break;
781 0 : case UNDERLINE_SINGLE: aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE; break;
782 0 : case UNDERLINE_DOUBLE: aNewData.mnUnderline = EXC_FONTUNDERL_DOUBLE; break;
783 0 : default: aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE;
784 : }
785 0 : if( aFontData.mnUnderline != aNewData.mnUnderline )
786 : {
787 : sal_uInt8 nTmpUnderl = (aNewData.mnUnderline == EXC_FONTUNDERL_NONE) ?
788 0 : aFontData.mnUnderline : aNewData.mnUnderline;
789 0 : aParaText.AppendAscii( (nTmpUnderl == EXC_FONTUNDERL_SINGLE) ? "&U" : "&E" );
790 : }
791 :
792 : // strikeout
793 0 : aNewData.mbStrikeout = (aFont.GetStrikeout() != STRIKEOUT_NONE);
794 0 : if( aFontData.mbStrikeout != aNewData.mbStrikeout )
795 0 : aParaText.AppendAscii( "&S" );
796 :
797 : // super/sub script
798 0 : const SvxEscapementItem& rEscapeItem = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT );
799 0 : aNewData.SetScEscapement( rEscapeItem.GetEsc() );
800 0 : if( aFontData.mnEscapem != aNewData.mnEscapem )
801 : {
802 0 : switch(aNewData.mnEscapem)
803 : {
804 : // close the previous super/sub script.
805 0 : case EXC_FONTESC_NONE: aParaText.AppendAscii( (aFontData.mnEscapem == EXC_FONTESC_SUPER) ? "&X" : "&Y" ); break;
806 0 : case EXC_FONTESC_SUPER: aParaText.AppendAscii( "&X" ); break;
807 0 : case EXC_FONTESC_SUB: aParaText.AppendAscii( "&Y" ); break;
808 0 : default: break;
809 : }
810 : }
811 :
812 0 : aFontData = aNewData;
813 :
814 : // --- text content or text fields ---
815 :
816 : const SfxPoolItem* pItem;
817 0 : if( (aSel.nStartPos + 1 == aSel.nEndPos) && // fields are single characters
818 0 : (aEditSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SFX_ITEM_SET) )
819 : {
820 0 : if( const SvxFieldData* pFieldData = static_cast< const SvxFieldItem* >( pItem )->GetField() )
821 : {
822 0 : if( pFieldData->ISA( SvxPageField ) )
823 0 : aParaText.AppendAscii( "&P" );
824 0 : else if( pFieldData->ISA( SvxPagesField ) )
825 0 : aParaText.AppendAscii( "&N" );
826 0 : else if( pFieldData->ISA( SvxDateField ) )
827 0 : aParaText.AppendAscii( "&D" );
828 0 : else if( pFieldData->ISA( SvxTimeField ) || pFieldData->ISA( SvxExtTimeField ) )
829 0 : aParaText.AppendAscii( "&T" );
830 0 : else if( pFieldData->ISA( SvxTableField ) )
831 0 : aParaText.AppendAscii( "&A" );
832 0 : else if( pFieldData->ISA( SvxFileField ) ) // title -> file name
833 0 : aParaText.AppendAscii( "&F" );
834 0 : else if( const SvxExtFileField* pFileField = PTR_CAST( SvxExtFileField, pFieldData ) )
835 : {
836 0 : switch( pFileField->GetFormat() )
837 : {
838 : case SVXFILEFORMAT_NAME_EXT:
839 : case SVXFILEFORMAT_NAME:
840 0 : aParaText.AppendAscii( "&F" );
841 0 : break;
842 : case SVXFILEFORMAT_PATH:
843 0 : aParaText.AppendAscii( "&Z" );
844 0 : break;
845 : case SVXFILEFORMAT_FULLPATH:
846 0 : aParaText.AppendAscii( "&Z&F" );
847 0 : break;
848 : default:
849 : OSL_FAIL( "XclExpHFConverter::AppendPortion - unknown file field" );
850 : }
851 : }
852 : }
853 : }
854 : else
855 : {
856 0 : String aPortionText( mrEE.GetText( aSel ) );
857 0 : aPortionText.SearchAndReplaceAll( rtl::OUString('&'), rtl::OUString("&&") );
858 : // #i17440# space between font height and numbers in text
859 0 : if( bFontHtChanged && aParaText.Len() && aPortionText.Len() )
860 : {
861 0 : sal_Unicode cLast = aParaText.GetChar( aParaText.Len() - 1 );
862 0 : sal_Unicode cFirst = aPortionText.GetChar( 0 );
863 0 : if( ('0' <= cLast) && (cLast <= '9') && ('0' <= cFirst) && (cFirst <= '9') )
864 0 : aParaText.Append( ' ' );
865 : }
866 0 : aParaText.Append( aPortionText );
867 0 : }
868 : }
869 :
870 0 : aSel.nStartPos = aSel.nEndPos;
871 : }
872 :
873 0 : aText = ScGlobal::addToken( aText, aParaText, '\n' );
874 0 : if( nParaHeight == 0 )
875 0 : nParaHeight = aFontData.mnHeight * 20; // points -> twips
876 0 : nHeight += nParaHeight;
877 0 : }
878 :
879 0 : mrEE.SetUpdateMode( bOldUpdateMode );
880 :
881 0 : if( aText.Len() )
882 : {
883 0 : maHFString.Append( '&' ).Append( cPortionCode ).Append( aText );
884 0 : mnTotalHeight = ::std::max( mnTotalHeight, nHeight );
885 0 : }
886 : }
887 :
888 : // URL conversion =============================================================
889 :
890 : namespace {
891 :
892 : /** Encodes special parts of the URL, i.e. directory separators and volume names.
893 : @param pTableName Pointer to a table name to be encoded in this URL, or 0. */
894 0 : rtl::OUString lclEncodeDosUrl(
895 : XclBiff eBiff, const rtl::OUString& rUrl, const rtl::OUString& rBase, const rtl::OUString* pTableName)
896 : {
897 0 : rtl::OUStringBuffer aBuf;
898 :
899 0 : if (!rUrl.isEmpty())
900 : {
901 0 : rtl::OUString aOldUrl = rUrl;
902 0 : aBuf.append(EXC_URLSTART_ENCODED);
903 :
904 0 : if ( aOldUrl.getLength() > 2 && aOldUrl.copy(0,2) == "\\\\" )
905 : {
906 : // UNC
907 0 : aBuf.append(EXC_URL_DOSDRIVE).append(sal_Unicode('@'));
908 0 : aOldUrl = aOldUrl.copy(2);
909 : }
910 0 : else if ( aOldUrl.getLength() > 2 && aOldUrl.copy(1,2) == ":\\" )
911 : {
912 : // drive letter
913 0 : sal_Unicode cThisDrive = rBase.isEmpty() ? ' ' : rBase.getStr()[0];
914 0 : sal_Unicode cDrive = aOldUrl.getStr()[0];
915 0 : if (cThisDrive == cDrive)
916 : // This document and the referenced document are under the same drive.
917 0 : aBuf.append(EXC_URL_DRIVEROOT);
918 : else
919 0 : aBuf.append(EXC_URL_DOSDRIVE).append(cDrive);
920 0 : aOldUrl = aOldUrl.copy(3);
921 : }
922 :
923 : // directories
924 0 : sal_Int32 nPos = -1;
925 0 : while((nPos = aOldUrl.indexOf('\\')) != -1)
926 : {
927 0 : if ( aOldUrl.copy(0,2) == ".." )
928 : // parent dir (NOTE: the MS-XLS spec doesn't mention this, and
929 : // Excel seems confused by this token).
930 0 : aBuf.append(EXC_URL_PARENTDIR);
931 : else
932 0 : aBuf.append(aOldUrl.copy(0,nPos)).append(EXC_URL_SUBDIR);
933 :
934 0 : aOldUrl = aOldUrl.copy(nPos + 1);
935 : }
936 :
937 : // file name
938 0 : if (pTableName) // enclose file name in brackets if table name follows
939 0 : aBuf.append(sal_Unicode('[')).append(aOldUrl).append(sal_Unicode(']'));
940 : else
941 0 : aBuf.append(aOldUrl);
942 : }
943 : else // empty URL -> self reference
944 : {
945 0 : switch( eBiff )
946 : {
947 : case EXC_BIFF5:
948 0 : aBuf.append(pTableName ? EXC_URLSTART_SELFENCODED : EXC_URLSTART_SELF);
949 0 : break;
950 : case EXC_BIFF8:
951 : DBG_ASSERT( pTableName, "lclEncodeDosUrl - sheet name required for BIFF8" );
952 0 : aBuf.append(EXC_URLSTART_SELF);
953 0 : break;
954 : default:
955 : DBG_ERROR_BIFF();
956 : }
957 : }
958 :
959 : // table name
960 0 : if (pTableName)
961 0 : aBuf.append(*pTableName);
962 :
963 0 : return aBuf.makeStringAndClear();
964 : }
965 :
966 : } // namespace
967 :
968 : // ----------------------------------------------------------------------------
969 :
970 0 : rtl::OUString XclExpUrlHelper::EncodeUrl( const XclExpRoot& rRoot, const rtl::OUString& rAbsUrl, const rtl::OUString* pTableName )
971 : {
972 0 : rtl::OUString aDosUrl = INetURLObject(rAbsUrl).getFSysPath(INetURLObject::FSYS_DOS);
973 0 : rtl::OUString aDosBase = INetURLObject(rRoot.GetBasePath()).getFSysPath(INetURLObject::FSYS_DOS);
974 0 : return lclEncodeDosUrl(rRoot.GetBiff(), aDosUrl, aDosBase, pTableName);
975 : }
976 :
977 0 : rtl::OUString XclExpUrlHelper::EncodeDde( const rtl::OUString& rApplic, const rtl::OUString& rTopic )
978 : {
979 0 : rtl::OUStringBuffer aBuf;
980 0 : aBuf.append(rApplic).append(EXC_DDE_DELIM).append(rTopic);
981 0 : return aBuf.makeStringAndClear();
982 : }
983 :
984 : // Cached Value Lists =========================================================
985 :
986 0 : XclExpCachedMatrix::XclExpCachedMatrix( const ScMatrix& rMatrix )
987 0 : : mrMatrix( rMatrix )
988 : {
989 0 : mrMatrix.IncRef();
990 0 : }
991 0 : XclExpCachedMatrix::~XclExpCachedMatrix()
992 : {
993 0 : mrMatrix.DecRef();
994 0 : }
995 :
996 0 : void XclExpCachedMatrix::GetDimensions( SCSIZE & nCols, SCSIZE & nRows ) const
997 : {
998 0 : mrMatrix.GetDimensions( nCols, nRows );
999 :
1000 : OSL_ENSURE( nCols && nRows, "XclExpCachedMatrix::GetDimensions - empty matrix" );
1001 : OSL_ENSURE( nCols <= 256, "XclExpCachedMatrix::GetDimensions - too many columns" );
1002 0 : }
1003 :
1004 0 : sal_Size XclExpCachedMatrix::GetSize() const
1005 : {
1006 : SCSIZE nCols, nRows;
1007 :
1008 0 : GetDimensions( nCols, nRows );
1009 :
1010 : /* The returned size may be wrong if the matrix contains strings. The only
1011 : effect is that the export stream has to update a wrong record size which is
1012 : faster than to iterate through all cached values and calculate their sizes. */
1013 0 : return 3 + 9 * (nCols * nRows);
1014 : }
1015 :
1016 0 : void XclExpCachedMatrix::Save( XclExpStream& rStrm ) const
1017 : {
1018 : SCSIZE nCols, nRows;
1019 :
1020 0 : GetDimensions( nCols, nRows );
1021 :
1022 0 : if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
1023 : // in BIFF2-BIFF7: 256 columns represented by 0 columns
1024 0 : rStrm << static_cast< sal_uInt8 >( nCols ) << static_cast< sal_uInt16 >( nRows );
1025 : else
1026 : // in BIFF8: columns and rows decreaed by 1
1027 0 : rStrm << static_cast< sal_uInt8 >( nCols - 1 ) << static_cast< sal_uInt16 >( nRows - 1 );
1028 :
1029 0 : for( SCSIZE nRow = 0; nRow < nRows; ++nRow )
1030 : {
1031 0 : for( SCSIZE nCol = 0; nCol < nCols; ++nCol )
1032 : {
1033 0 : ScMatrixValue nMatVal = mrMatrix.Get( nCol, nRow );
1034 :
1035 0 : if( SC_MATVAL_EMPTY == nMatVal.nType )
1036 : {
1037 0 : rStrm.SetSliceSize( 9 );
1038 0 : rStrm << EXC_CACHEDVAL_EMPTY;
1039 0 : rStrm.WriteZeroBytes( 8 );
1040 : }
1041 0 : else if( ScMatrix::IsNonValueType( nMatVal.nType ) )
1042 : {
1043 0 : XclExpString aStr( nMatVal.GetString(), EXC_STR_DEFAULT );
1044 0 : rStrm.SetSliceSize( 6 );
1045 0 : rStrm << EXC_CACHEDVAL_STRING << aStr;
1046 : }
1047 0 : else if( SC_MATVAL_BOOLEAN == nMatVal.nType )
1048 : {
1049 0 : sal_Int8 nBool = nMatVal.GetBoolean();
1050 0 : rStrm.SetSliceSize( 9 );
1051 0 : rStrm << EXC_CACHEDVAL_BOOL << nBool;
1052 0 : rStrm.WriteZeroBytes( 7 );
1053 : }
1054 0 : else if( sal_uInt16 nScError = nMatVal.GetError() )
1055 : {
1056 0 : sal_Int8 nError ( XclTools::GetXclErrorCode( nScError ) );
1057 0 : rStrm.SetSliceSize( 9 );
1058 0 : rStrm << EXC_CACHEDVAL_ERROR << nError;
1059 0 : rStrm.WriteZeroBytes( 7 );
1060 : }
1061 : else
1062 : {
1063 0 : rStrm.SetSliceSize( 9 );
1064 0 : rStrm << EXC_CACHEDVAL_DOUBLE << nMatVal.fVal;
1065 : }
1066 0 : }
1067 : }
1068 9 : }
1069 :
1070 : // ============================================================================
1071 :
1072 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|