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