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