1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
38 #include "document.hxx"
39 #include "docpool.hxx"
40 #include "formulacell.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"
48 #include "xehelper.hxx"
50 using ::com::sun::star::uno::Reference
;
51 using ::com::sun::star::i18n::XBreakIterator
;
53 // Export progress bar ========================================================
55 XclExpProgressBar::XclExpProgressBar( const XclExpRoot
& rRoot
) :
57 mxProgress( new ScfProgressBar( rRoot
.GetDocShell(), STR_SAVE_DOC
) ),
61 mnSegRowFinal( SCF_INV_SEGMENT
),
66 XclExpProgressBar::~XclExpProgressBar()
70 void XclExpProgressBar::Initialize()
72 const ScDocument
& rDoc
= GetDoc();
73 const XclExpTabInfo
& rTabInfo
= GetTabInfo();
74 SCTAB nScTabCount
= rTabInfo
.GetScTabCount();
76 // *** segment: creation of ROW records *** -------------------------------
78 sal_Int32 nSegRowCreate
= mxProgress
->AddSegment( 2000 );
79 mpSubRowCreate
= &mxProgress
->GetSegmentProgressBar( nSegRowCreate
);
80 maSubSegRowCreate
.resize( nScTabCount
, SCF_INV_SEGMENT
);
82 for( SCTAB nScTab
= 0; nScTab
< nScTabCount
; ++nScTab
)
84 if( rTabInfo
.IsExportTab( nScTab
) )
88 rDoc
.GetTableArea( nScTab
, nLastUsedScCol
, nLastUsedScRow
);
89 sal_Size nSegSize
= static_cast< sal_Size
>( nLastUsedScRow
+ 1 );
90 maSubSegRowCreate
[ nScTab
] = mpSubRowCreate
->AddSegment( nSegSize
);
94 // *** segment: writing all ROW records *** -------------------------------
96 mnSegRowFinal
= mxProgress
->AddSegment( 1000 );
97 // sub progress bar and segment are created later in ActivateFinalRowsSegment()
100 void XclExpProgressBar::IncRowRecordCount()
105 void XclExpProgressBar::ActivateCreateRowsSegment()
107 OSL_ENSURE( (0 <= GetCurrScTab()) && (GetCurrScTab() < GetTabInfo().GetScTabCount()),
108 "XclExpProgressBar::ActivateCreateRowsSegment - invalid sheet" );
109 sal_Int32 nSeg
= maSubSegRowCreate
[ GetCurrScTab() ];
110 OSL_ENSURE( nSeg
!= SCF_INV_SEGMENT
, "XclExpProgressBar::ActivateCreateRowsSegment - invalid segment" );
111 if( nSeg
!= SCF_INV_SEGMENT
)
113 mpSubProgress
= mpSubRowCreate
;
114 mpSubProgress
->ActivateSegment( nSeg
);
120 void XclExpProgressBar::ActivateFinalRowsSegment()
122 if( !mpSubRowFinal
&& (mnRowCount
> 0) )
124 mpSubRowFinal
= &mxProgress
->GetSegmentProgressBar( mnSegRowFinal
);
125 mpSubRowFinal
->AddSegment( mnRowCount
);
127 mpSubProgress
= mpSubRowFinal
;
129 mpSubProgress
->Activate();
132 void XclExpProgressBar::Progress()
134 if( mpSubProgress
&& !mpSubProgress
->IsFull() )
135 mpSubProgress
->Progress();
138 // Calc->Excel cell address/range conversion ==================================
142 /** Fills the passed Excel address with the passed Calc cell coordinates without checking any limits. */
143 inline void lclFillAddress( XclAddress
& rXclPos
, SCCOL nScCol
, SCROW nScRow
)
145 rXclPos
.mnCol
= static_cast< sal_uInt16
>( nScCol
);
146 rXclPos
.mnRow
= static_cast< sal_uInt32
>( nScRow
);
151 // ----------------------------------------------------------------------------
153 XclExpAddressConverter::XclExpAddressConverter( const XclExpRoot
& rRoot
) :
154 XclAddressConverterBase( rRoot
.GetTracer(), rRoot
.GetXclMaxPos() )
158 // cell address ---------------------------------------------------------------
160 bool XclExpAddressConverter::CheckAddress( const ScAddress
& rScPos
, bool bWarn
)
162 // ScAddress::operator<=() doesn't do what we want here
163 bool bValidCol
= (0 <= rScPos
.Col()) && (rScPos
.Col() <= maMaxPos
.Col());
164 bool bValidRow
= (0 <= rScPos
.Row()) && (rScPos
.Row() <= maMaxPos
.Row());
165 bool bValidTab
= (0 <= rScPos
.Tab()) && (rScPos
.Tab() <= maMaxPos
.Tab());
167 bool bValid
= bValidCol
&& bValidRow
&& bValidTab
;
168 if( !bValid
&& bWarn
)
170 mbColTrunc
|= !bValidCol
;
171 mbRowTrunc
|= !bValidRow
;
172 mbTabTrunc
|= (rScPos
.Tab() > maMaxPos
.Tab()); // do not warn for deleted refs
173 mrTracer
.TraceInvalidAddress( rScPos
, maMaxPos
);
178 bool XclExpAddressConverter::ConvertAddress( XclAddress
& rXclPos
,
179 const ScAddress
& rScPos
, bool bWarn
)
181 bool bValid
= CheckAddress( rScPos
, bWarn
);
183 lclFillAddress( rXclPos
, rScPos
.Col(), rScPos
.Row() );
187 XclAddress
XclExpAddressConverter::CreateValidAddress( const ScAddress
& rScPos
, bool bWarn
)
189 XclAddress
aXclPos( ScAddress::UNINITIALIZED
);
190 if( !ConvertAddress( aXclPos
, rScPos
, bWarn
) )
191 lclFillAddress( aXclPos
, ::std::min( rScPos
.Col(), maMaxPos
.Col() ), ::std::min( rScPos
.Row(), maMaxPos
.Row() ) );
195 // cell range -----------------------------------------------------------------
197 bool XclExpAddressConverter::CheckRange( const ScRange
& rScRange
, bool bWarn
)
199 return CheckAddress( rScRange
.aStart
, bWarn
) && CheckAddress( rScRange
.aEnd
, bWarn
);
202 bool XclExpAddressConverter::ValidateRange( ScRange
& rScRange
, bool bWarn
)
206 // check start position
207 bool bValidStart
= CheckAddress( rScRange
.aStart
, bWarn
);
210 // check & correct end position
211 ScAddress
& rScEnd
= rScRange
.aEnd
;
212 if( !CheckAddress( rScEnd
, bWarn
) )
214 rScEnd
.SetCol( ::std::min( rScEnd
.Col(), maMaxPos
.Col() ) );
215 rScEnd
.SetRow( ::std::min( rScEnd
.Row(), maMaxPos
.Row() ) );
216 rScEnd
.SetTab( ::std::min( rScEnd
.Tab(), maMaxPos
.Tab() ) );
223 bool XclExpAddressConverter::ConvertRange( XclRange
& rXclRange
,
224 const ScRange
& rScRange
, bool bWarn
)
226 // check start position
227 bool bValidStart
= CheckAddress( rScRange
.aStart
, bWarn
);
230 lclFillAddress( rXclRange
.maFirst
, rScRange
.aStart
.Col(), rScRange
.aStart
.Row() );
232 // check & correct end position
233 SCCOL nScCol2
= rScRange
.aEnd
.Col();
234 SCROW nScRow2
= rScRange
.aEnd
.Row();
235 if( !CheckAddress( rScRange
.aEnd
, bWarn
) )
237 nScCol2
= ::std::min( nScCol2
, maMaxPos
.Col() );
238 nScRow2
= ::std::min( nScRow2
, maMaxPos
.Row() );
240 lclFillAddress( rXclRange
.maLast
, nScCol2
, nScRow2
);
245 // cell range list ------------------------------------------------------------
247 void XclExpAddressConverter::ValidateRangeList( ScRangeList
& rScRanges
, bool bWarn
)
249 for ( size_t nRange
= rScRanges
.size(); nRange
> 0; )
251 ScRange
* pScRange
= rScRanges
[ --nRange
];
252 if( !CheckRange( *pScRange
, bWarn
) )
253 delete rScRanges
.Remove(nRange
);
257 void XclExpAddressConverter::ConvertRangeList( XclRangeList
& rXclRanges
,
258 const ScRangeList
& rScRanges
, bool bWarn
)
261 for( size_t nPos
= 0, nCount
= rScRanges
.size(); nPos
< nCount
; ++nPos
)
263 if( const ScRange
* pScRange
= rScRanges
[ nPos
] )
265 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
266 if( ConvertRange( aXclRange
, *pScRange
, bWarn
) )
267 rXclRanges
.push_back( aXclRange
);
272 // EditEngine->String conversion ==============================================
276 OUString
lclGetUrlRepresentation( const SvxURLField
& rUrlField
)
278 const OUString
& aRepr
= rUrlField
.GetRepresentation();
279 // no representation -> use URL
280 return aRepr
.isEmpty() ? rUrlField
.GetURL() : aRepr
;
285 // ----------------------------------------------------------------------------
287 XclExpHyperlinkHelper::XclExpHyperlinkHelper( const XclExpRoot
& rRoot
, const ScAddress
& rScPos
) :
290 mbMultipleUrls( false )
294 XclExpHyperlinkHelper::~XclExpHyperlinkHelper()
298 OUString
XclExpHyperlinkHelper::ProcessUrlField( const SvxURLField
& rUrlField
)
302 if( GetBiff() == EXC_BIFF8
) // no HLINK records in BIFF2-BIFF7
304 // there was/is already a HLINK record
305 mbMultipleUrls
= static_cast< bool >(mxLinkRec
);
307 mxLinkRec
.reset( new XclExpHyperlink( GetRoot(), rUrlField
, maScPos
) );
309 if( const String
* pRepr
= mxLinkRec
->GetRepr() )
312 // add URL to note text
313 maUrlList
= ScGlobal::addToken( maUrlList
, rUrlField
.GetURL(), '\n' );
316 // no hyperlink representation from Excel HLINK record -> use it from text field
317 return aUrlRepr
.isEmpty() ? lclGetUrlRepresentation(rUrlField
) : aUrlRepr
;
320 bool XclExpHyperlinkHelper::HasLinkRecord() const
322 return !mbMultipleUrls
&& mxLinkRec
;
325 XclExpHyperlinkHelper::XclExpHyperlinkRef
XclExpHyperlinkHelper::GetLinkRecord()
327 if( HasLinkRecord() )
329 return XclExpHyperlinkRef();
332 // ----------------------------------------------------------------------------
336 /** Creates a new formatted string from the passed unformatted string.
338 Creates a Unicode string or a byte string, depending on the current BIFF
339 version contained in the passed XclExpRoot object. May create a formatted
340 string object, if the text contains different script types.
343 Cell attributes used for font formatting.
345 Modifiers for string export.
347 The maximum number of characters to store in this string.
349 The new string object.
351 XclExpStringRef
lclCreateFormattedString(
352 const XclExpRoot
& rRoot
, const String
& rText
, const ScPatternAttr
* pCellAttr
,
353 XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
355 /* Create an empty Excel string object with correctly initialized BIFF mode,
356 because this function only uses Append() functions that require this. */
357 XclExpStringRef xString
= XclExpStringHelper::CreateString( rRoot
, EMPTY_STRING
, nFlags
, nMaxLen
);
359 // script type handling
360 Reference
< XBreakIterator
> xBreakIt
= rRoot
.GetDoc().GetBreakIterator();
361 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
362 // #i63255# get script type for leading weak characters
363 sal_Int16 nLastScript
= XclExpStringHelper::GetLeadingScriptType( rRoot
, rText
);
365 // font buffer and cell item set
366 XclExpFontBuffer
& rFontBuffer
= rRoot
.GetFontBuffer();
367 const SfxItemSet
& rItemSet
= pCellAttr
? pCellAttr
->GetItemSet() : rRoot
.GetDoc().GetDefPattern()->GetItemSet();
369 // process all script portions
370 OUString
aOUText( rText
);
371 sal_Int32 nPortionPos
= 0;
372 sal_Int32 nTextLen
= aOUText
.getLength();
373 while( nPortionPos
< nTextLen
)
375 // get script type and end position of next script portion
376 sal_Int16 nScript
= xBreakIt
->getScriptType( aOUText
, nPortionPos
);
377 sal_Int32 nPortionEnd
= xBreakIt
->endOfScript( aOUText
, nPortionPos
, nScript
);
379 // reuse previous script for following weak portions
380 if( nScript
== ApiScriptType::WEAK
)
381 nScript
= nLastScript
;
383 // construct font from current text portion
384 SvxFont
aFont( XclExpFontHelper::GetFontFromItemSet( rRoot
, rItemSet
, nScript
) );
386 // Excel start position of this portion
387 sal_uInt16 nXclPortionStart
= xString
->Len();
388 // add portion text to Excel string
389 XclExpStringHelper::AppendString( *xString
, rRoot
, aOUText
.copy( nPortionPos
, nPortionEnd
- nPortionPos
) );
390 if( nXclPortionStart
< xString
->Len() )
392 // insert font into buffer
393 sal_uInt16 nFontIdx
= rFontBuffer
.Insert( aFont
, EXC_COLOR_CELLTEXT
);
394 // insert font index into format run vector
395 xString
->AppendFormat( nXclPortionStart
, nFontIdx
);
398 // go to next script portion
399 nLastScript
= nScript
;
400 nPortionPos
= nPortionEnd
;
406 /** Creates a new formatted string from an edit engine text object.
408 Creates a Unicode string or a byte string, depending on the current BIFF
409 version contained in the passed XclExpRoot object.
412 The edit engine in use. The text object must already be set.
414 Modifiers for string export.
416 The maximum number of characters to store in this string.
418 The new string object.
420 XclExpStringRef
lclCreateFormattedString(
421 const XclExpRoot
& rRoot
, EditEngine
& rEE
, XclExpHyperlinkHelper
* pLinkHelper
,
422 XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
424 /* Create an empty Excel string object with correctly initialized BIFF mode,
425 because this function only uses Append() functions that require this. */
426 XclExpStringRef xString
= XclExpStringHelper::CreateString( rRoot
, EMPTY_STRING
, nFlags
, nMaxLen
);
428 // font buffer and helper item set for edit engine -> Calc item conversion
429 XclExpFontBuffer
& rFontBuffer
= rRoot
.GetFontBuffer();
430 SfxItemSet
aItemSet( *rRoot
.GetDoc().GetPool(), ATTR_PATTERN_START
, ATTR_PATTERN_END
);
432 // script type handling
433 Reference
< XBreakIterator
> xBreakIt
= rRoot
.GetDoc().GetBreakIterator();
434 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
435 // #i63255# get script type for leading weak characters
436 sal_Int16 nLastScript
= XclExpStringHelper::GetLeadingScriptType( rRoot
, rEE
.GetText() );
438 // process all paragraphs
439 sal_Int32 nParaCount
= rEE
.GetParagraphCount();
440 for( sal_Int32 nPara
= 0; nPara
< nParaCount
; ++nPara
)
442 ESelection
aSel( nPara
, 0 );
443 String
aParaText( rEE
.GetText( nPara
) );
445 std::vector
<sal_uInt16
> aPosList
;
446 rEE
.GetPortions( nPara
, aPosList
);
448 // process all portions in the paragraph
449 for( std::vector
<sal_uInt16
>::const_iterator
it(aPosList
.begin()); it
!= aPosList
.end(); ++it
)
451 aSel
.nEndPos
= static_cast< xub_StrLen
>( *it
);
452 String
aXclPortionText( aParaText
, aSel
.nStartPos
, aSel
.nEndPos
- aSel
.nStartPos
);
454 aItemSet
.ClearItem();
455 SfxItemSet
aEditSet( rEE
.GetAttribs( aSel
) );
456 ScPatternAttr::GetFromEditItemSet( aItemSet
, aEditSet
);
458 // get escapement value
459 short nEsc
= GETITEM( aEditSet
, SvxEscapementItem
, EE_CHAR_ESCAPEMENT
).GetEsc();
461 // process text fields
462 bool bIsHyperlink
= false;
463 if( aSel
.nStartPos
+ 1 == aSel
.nEndPos
)
465 // test if the character is a text field
466 const SfxPoolItem
* pItem
;
467 if( aEditSet
.GetItemState( EE_FEATURE_FIELD
, false, &pItem
) == SFX_ITEM_SET
)
469 const SvxFieldData
* pField
= static_cast< const SvxFieldItem
* >( pItem
)->GetField();
470 if( const SvxURLField
* pUrlField
= PTR_CAST( SvxURLField
, pField
) )
472 // convert URL field to string representation
473 aXclPortionText
= pLinkHelper
?
474 pLinkHelper
->ProcessUrlField( *pUrlField
) :
475 lclGetUrlRepresentation( *pUrlField
);
480 OSL_FAIL( "lclCreateFormattedString - unknown text field" );
481 aXclPortionText
.Erase();
486 // Excel start position of this portion
487 sal_uInt16 nXclPortionStart
= xString
->Len();
488 // add portion text to Excel string
489 XclExpStringHelper::AppendString( *xString
, rRoot
, aXclPortionText
);
490 if( (nXclPortionStart
< xString
->Len()) || (aParaText
.Len() == 0) )
492 /* Construct font from current edit engine text portion. Edit engine
493 creates different portions for different script types, no need to loop. */
494 sal_Int16 nScript
= xBreakIt
->getScriptType( aXclPortionText
, 0 );
495 if( nScript
== ApiScriptType::WEAK
)
496 nScript
= nLastScript
;
497 SvxFont
aFont( XclExpFontHelper::GetFontFromItemSet( rRoot
, aItemSet
, nScript
) );
498 nLastScript
= nScript
;
501 aFont
.SetEscapement( nEsc
);
502 // modify automatic font color for hyperlinks
503 if( bIsHyperlink
&& (GETITEM( aItemSet
, SvxColorItem
, ATTR_FONT_COLOR
).GetValue().GetColor() == COL_AUTO
) )
504 aFont
.SetColor( Color( COL_LIGHTBLUE
) );
506 // insert font into buffer
507 sal_uInt16 nFontIdx
= rFontBuffer
.Insert( aFont
, EXC_COLOR_CELLTEXT
);
508 // insert font index into format run vector
509 xString
->AppendFormat( nXclPortionStart
, nFontIdx
);
512 aSel
.nStartPos
= aSel
.nEndPos
;
515 // add trailing newline (important for correct character index calculation)
516 if( nPara
+ 1 < nParaCount
)
517 XclExpStringHelper::AppendChar( *xString
, rRoot
, '\n' );
525 // ----------------------------------------------------------------------------
527 XclExpStringRef
XclExpStringHelper::CreateString(
528 const XclExpRoot
& rRoot
, const String
& rString
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
530 XclExpStringRef
xString( new XclExpString
);
531 if( rRoot
.GetBiff() == EXC_BIFF8
)
532 xString
->Assign( rString
, nFlags
, nMaxLen
);
534 xString
->AssignByte( rString
, rRoot
.GetTextEncoding(), nFlags
, nMaxLen
);
538 XclExpStringRef
XclExpStringHelper::CreateString(
539 const XclExpRoot
& rRoot
, sal_Unicode cChar
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
541 XclExpStringRef xString
= CreateString( rRoot
, EMPTY_STRING
, nFlags
, nMaxLen
);
542 AppendChar( *xString
, rRoot
, cChar
);
546 void XclExpStringHelper::AppendString( XclExpString
& rXclString
, const XclExpRoot
& rRoot
, const String
& rString
)
548 if( rRoot
.GetBiff() == EXC_BIFF8
)
549 rXclString
.Append( rString
);
551 rXclString
.AppendByte( rString
, rRoot
.GetTextEncoding() );
554 void XclExpStringHelper::AppendChar( XclExpString
& rXclString
, const XclExpRoot
& rRoot
, sal_Unicode cChar
)
556 if( rRoot
.GetBiff() == EXC_BIFF8
)
557 rXclString
.Append( OUString(cChar
) );
559 rXclString
.AppendByte( cChar
, rRoot
.GetTextEncoding() );
562 XclExpStringRef
XclExpStringHelper::CreateCellString(
563 const XclExpRoot
& rRoot
, const OUString
& rString
, const ScPatternAttr
* pCellAttr
,
564 XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
566 return lclCreateFormattedString(rRoot
, rString
, pCellAttr
, nFlags
, nMaxLen
);
569 XclExpStringRef
XclExpStringHelper::CreateCellString(
570 const XclExpRoot
& rRoot
, const EditTextObject
& rEditText
, const ScPatternAttr
* pCellAttr
,
571 XclExpHyperlinkHelper
& rLinkHelper
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
573 XclExpStringRef xString
;
576 ScEditEngineDefaulter
& rEE
= rRoot
.GetEditEngine();
577 sal_Bool bOldUpdateMode
= rEE
.GetUpdateMode();
578 rEE
.SetUpdateMode( sal_True
);
581 const SfxItemSet
& rItemSet
= pCellAttr
? pCellAttr
->GetItemSet() : rRoot
.GetDoc().GetDefPattern()->GetItemSet();
582 SfxItemSet
* pEEItemSet
= new SfxItemSet( rEE
.GetEmptyItemSet() );
583 ScPatternAttr::FillToEditItemSet( *pEEItemSet
, rItemSet
);
584 rEE
.SetDefaults( pEEItemSet
); // edit engine takes ownership
587 rEE
.SetText(rEditText
);
588 xString
= lclCreateFormattedString( rRoot
, rEE
, &rLinkHelper
, nFlags
, nMaxLen
);
589 rEE
.SetUpdateMode( bOldUpdateMode
);
594 XclExpStringRef
XclExpStringHelper::CreateString(
595 const XclExpRoot
& rRoot
, const SdrTextObj
& rTextObj
,
596 XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
598 XclExpStringRef xString
;
599 if( const OutlinerParaObject
* pParaObj
= rTextObj
.GetOutlinerParaObject() )
601 EditEngine
& rEE
= rRoot
.GetDrawEditEngine();
602 sal_Bool bOldUpdateMode
= rEE
.GetUpdateMode();
603 rEE
.SetUpdateMode( sal_True
);
605 rEE
.SetText( pParaObj
->GetTextObject() );
606 xString
= lclCreateFormattedString( rRoot
, rEE
, 0, nFlags
, nMaxLen
);
607 rEE
.SetUpdateMode( bOldUpdateMode
);
608 // limit formats - TODO: BIFF dependent
609 if( !xString
->IsEmpty() )
611 xString
->LimitFormatCount( EXC_MAXRECSIZE_BIFF8
/ 8 - 1 );
612 xString
->AppendTrailingFormat( EXC_FONT_APP
);
617 OSL_FAIL( "XclExpStringHelper::CreateString - textbox without para object" );
618 // create BIFF dependent empty Excel string
619 xString
= CreateString( rRoot
, EMPTY_STRING
, nFlags
, nMaxLen
);
624 XclExpStringRef
XclExpStringHelper::CreateString(
625 const XclExpRoot
& rRoot
, const EditTextObject
& rEditObj
,
626 XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
628 XclExpStringRef xString
;
629 EditEngine
& rEE
= rRoot
.GetDrawEditEngine();
630 sal_Bool bOldUpdateMode
= rEE
.GetUpdateMode();
631 rEE
.SetUpdateMode( sal_True
);
632 rEE
.SetText( rEditObj
);
633 xString
= lclCreateFormattedString( rRoot
, rEE
, 0, nFlags
, nMaxLen
);
634 rEE
.SetUpdateMode( bOldUpdateMode
);
635 // limit formats - TODO: BIFF dependent
636 if( !xString
->IsEmpty() )
638 xString
->LimitFormatCount( EXC_MAXRECSIZE_BIFF8
/ 8 - 1 );
639 xString
->AppendTrailingFormat( EXC_FONT_APP
);
644 sal_Int16
XclExpStringHelper::GetLeadingScriptType( const XclExpRoot
& rRoot
, const String
& rString
)
646 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
647 Reference
< XBreakIterator
> xBreakIt
= rRoot
.GetDoc().GetBreakIterator();
648 OUString
aOUString( rString
);
649 sal_Int32 nStrPos
= 0;
650 sal_Int32 nStrLen
= aOUString
.getLength();
651 sal_Int16 nScript
= ApiScriptType::WEAK
;
652 while( (nStrPos
< nStrLen
) && (nScript
== ApiScriptType::WEAK
) )
654 nScript
= xBreakIt
->getScriptType( aOUString
, nStrPos
);
655 nStrPos
= xBreakIt
->endOfScript( aOUString
, nStrPos
, nScript
);
657 return (nScript
== ApiScriptType::WEAK
) ? rRoot
.GetDefApiScript() : nScript
;
660 // Header/footer conversion ===================================================
662 XclExpHFConverter::XclExpHFConverter( const XclExpRoot
& rRoot
) :
664 mrEE( rRoot
.GetHFEditEngine() ),
669 void XclExpHFConverter::GenerateString(
670 const EditTextObject
* pLeftObj
,
671 const EditTextObject
* pCenterObj
,
672 const EditTextObject
* pRightObj
)
676 AppendPortion( pLeftObj
, 'L' );
677 AppendPortion( pCenterObj
, 'C' );
678 AppendPortion( pRightObj
, 'R' );
681 void XclExpHFConverter::AppendPortion( const EditTextObject
* pTextObj
, sal_Unicode cPortionCode
)
683 if( !pTextObj
) return;
686 sal_Int32 nHeight
= 0;
687 SfxItemSet
aItemSet( *GetDoc().GetPool(), ATTR_PATTERN_START
, ATTR_PATTERN_END
);
690 sal_Bool bOldUpdateMode
= mrEE
.GetUpdateMode();
691 mrEE
.SetUpdateMode( sal_True
);
692 mrEE
.SetText( *pTextObj
);
695 XclFontData aFontData
, aNewData
;
696 if( const XclExpFont
* pFirstFont
= GetFontBuffer().GetFont( EXC_FONT_APP
) )
698 aFontData
= pFirstFont
->GetFontData();
699 (aFontData
.mnHeight
+= 10) /= 20; // using pt here, not twips
702 aFontData
.mnHeight
= 10;
704 const FontList
* pFontList
= 0;
705 if( SfxObjectShell
* pDocShell
= GetDocShell() )
707 if( const SvxFontListItem
* pInfoItem
= static_cast< const SvxFontListItem
* >(
708 pDocShell
->GetItem( SID_ATTR_CHAR_FONTLIST
) ) )
709 pFontList
= pInfoItem
->GetFontList();
712 sal_Int32 nParaCount
= mrEE
.GetParagraphCount();
713 for( sal_Int32 nPara
= 0; nPara
< nParaCount
; ++nPara
)
715 ESelection
aSel( nPara
, 0 );
717 sal_Int32 nParaHeight
= 0;
718 std::vector
<sal_uInt16
> aPosList
;
719 mrEE
.GetPortions( nPara
, aPosList
);
721 for( std::vector
<sal_uInt16
>::const_iterator
it( aPosList
.begin() ); it
!= aPosList
.end(); ++it
)
723 aSel
.nEndPos
= static_cast< xub_StrLen
>( *it
);
724 if( aSel
.nStartPos
< aSel
.nEndPos
)
727 // --- font attributes ---
730 aItemSet
.ClearItem();
731 SfxItemSet
aEditSet( mrEE
.GetAttribs( aSel
) );
732 ScPatternAttr::GetFromEditItemSet( aItemSet
, aEditSet
);
733 ScPatternAttr::GetFont( aFont
, aItemSet
, SC_AUTOCOL_RAW
);
735 // font name and style
736 aNewData
.maName
= XclTools::GetXclFontName( aFont
.GetName() );
737 aNewData
.mnWeight
= (aFont
.GetWeight() > WEIGHT_NORMAL
) ? EXC_FONTWGHT_BOLD
: EXC_FONTWGHT_NORMAL
;
738 aNewData
.mbItalic
= (aFont
.GetItalic() != ITALIC_NONE
);
739 bool bNewFont
= !(aFontData
.maName
== aNewData
.maName
);
740 bool bNewStyle
= (aFontData
.mnWeight
!= aNewData
.mnWeight
) ||
741 (aFontData
.mbItalic
!= aNewData
.mbItalic
);
742 if( bNewFont
|| (bNewStyle
&& pFontList
) )
744 aParaText
.AppendAscii( "&\"" ).Append( aNewData
.maName
);
747 FontInfo
aFontInfo( pFontList
->Get(
749 (aNewData
.mnWeight
> EXC_FONTWGHT_NORMAL
) ? WEIGHT_BOLD
: WEIGHT_NORMAL
,
750 aNewData
.mbItalic
? ITALIC_NORMAL
: ITALIC_NONE
) );
751 aNewData
.maStyle
= pFontList
->GetStyleName( aFontInfo
);
752 if( aNewData
.maStyle
.Len() )
753 aParaText
.Append( ',' ).Append( aNewData
.maStyle
);
755 aParaText
.Append( '"' );
759 // is calculated wrong in ScPatternAttr::GetFromEditItemSet, because already in twips and not 100thmm
760 // -> get it directly from edit engine item set
761 aNewData
.mnHeight
= ulimit_cast
< sal_uInt16
>( GETITEM( aEditSet
, SvxFontHeightItem
, EE_CHAR_FONTHEIGHT
).GetHeight() );
762 (aNewData
.mnHeight
+= 10) /= 20;
763 bool bFontHtChanged
= (aFontData
.mnHeight
!= aNewData
.mnHeight
);
765 aParaText
.Append( '&' ).Append( OUString::number( aNewData
.mnHeight
) );
766 // update maximum paragraph height, convert to twips
767 nParaHeight
= ::std::max
< sal_Int32
>( nParaHeight
, aNewData
.mnHeight
* 20 );
770 aNewData
.mnUnderline
= EXC_FONTUNDERL_NONE
;
771 switch( aFont
.GetUnderline() )
773 case UNDERLINE_NONE
: aNewData
.mnUnderline
= EXC_FONTUNDERL_NONE
; break;
774 case UNDERLINE_SINGLE
: aNewData
.mnUnderline
= EXC_FONTUNDERL_SINGLE
; break;
775 case UNDERLINE_DOUBLE
: aNewData
.mnUnderline
= EXC_FONTUNDERL_DOUBLE
; break;
776 default: aNewData
.mnUnderline
= EXC_FONTUNDERL_SINGLE
;
778 if( aFontData
.mnUnderline
!= aNewData
.mnUnderline
)
780 sal_uInt8 nTmpUnderl
= (aNewData
.mnUnderline
== EXC_FONTUNDERL_NONE
) ?
781 aFontData
.mnUnderline
: aNewData
.mnUnderline
;
782 aParaText
.AppendAscii( (nTmpUnderl
== EXC_FONTUNDERL_SINGLE
) ? "&U" : "&E" );
786 aNewData
.mbStrikeout
= (aFont
.GetStrikeout() != STRIKEOUT_NONE
);
787 if( aFontData
.mbStrikeout
!= aNewData
.mbStrikeout
)
788 aParaText
.AppendAscii( "&S" );
791 const SvxEscapementItem
& rEscapeItem
= GETITEM( aEditSet
, SvxEscapementItem
, EE_CHAR_ESCAPEMENT
);
792 aNewData
.SetScEscapement( rEscapeItem
.GetEsc() );
793 if( aFontData
.mnEscapem
!= aNewData
.mnEscapem
)
795 switch(aNewData
.mnEscapem
)
797 // close the previous super/sub script.
798 case EXC_FONTESC_NONE
: aParaText
.AppendAscii( (aFontData
.mnEscapem
== EXC_FONTESC_SUPER
) ? "&X" : "&Y" ); break;
799 case EXC_FONTESC_SUPER
: aParaText
.AppendAscii( "&X" ); break;
800 case EXC_FONTESC_SUB
: aParaText
.AppendAscii( "&Y" ); break;
805 aFontData
= aNewData
;
807 // --- text content or text fields ---
809 const SfxPoolItem
* pItem
;
810 if( (aSel
.nStartPos
+ 1 == aSel
.nEndPos
) && // fields are single characters
811 (aEditSet
.GetItemState( EE_FEATURE_FIELD
, false, &pItem
) == SFX_ITEM_SET
) )
813 if( const SvxFieldData
* pFieldData
= static_cast< const SvxFieldItem
* >( pItem
)->GetField() )
815 if( pFieldData
->ISA( SvxPageField
) )
816 aParaText
.AppendAscii( "&P" );
817 else if( pFieldData
->ISA( SvxPagesField
) )
818 aParaText
.AppendAscii( "&N" );
819 else if( pFieldData
->ISA( SvxDateField
) )
820 aParaText
.AppendAscii( "&D" );
821 else if( pFieldData
->ISA( SvxTimeField
) || pFieldData
->ISA( SvxExtTimeField
) )
822 aParaText
.AppendAscii( "&T" );
823 else if( pFieldData
->ISA( SvxTableField
) )
824 aParaText
.AppendAscii( "&A" );
825 else if( pFieldData
->ISA( SvxFileField
) ) // title -> file name
826 aParaText
.AppendAscii( "&F" );
827 else if( const SvxExtFileField
* pFileField
= PTR_CAST( SvxExtFileField
, pFieldData
) )
829 switch( pFileField
->GetFormat() )
831 case SVXFILEFORMAT_NAME_EXT
:
832 case SVXFILEFORMAT_NAME
:
833 aParaText
.AppendAscii( "&F" );
835 case SVXFILEFORMAT_PATH
:
836 aParaText
.AppendAscii( "&Z" );
838 case SVXFILEFORMAT_FULLPATH
:
839 aParaText
.AppendAscii( "&Z&F" );
842 OSL_FAIL( "XclExpHFConverter::AppendPortion - unknown file field" );
849 String
aPortionText( mrEE
.GetText( aSel
) );
850 aPortionText
.SearchAndReplaceAll( OUString('&'), OUString("&&") );
851 // #i17440# space between font height and numbers in text
852 if( bFontHtChanged
&& aParaText
.Len() && aPortionText
.Len() )
854 sal_Unicode cLast
= aParaText
.GetChar( aParaText
.Len() - 1 );
855 sal_Unicode cFirst
= aPortionText
.GetChar( 0 );
856 if( ('0' <= cLast
) && (cLast
<= '9') && ('0' <= cFirst
) && (cFirst
<= '9') )
857 aParaText
.Append( ' ' );
859 aParaText
.Append( aPortionText
);
863 aSel
.nStartPos
= aSel
.nEndPos
;
866 aText
= ScGlobal::addToken( aText
, aParaText
, '\n' );
867 if( nParaHeight
== 0 )
868 nParaHeight
= aFontData
.mnHeight
* 20; // points -> twips
869 nHeight
+= nParaHeight
;
872 mrEE
.SetUpdateMode( bOldUpdateMode
);
876 maHFString
.Append( '&' ).Append( cPortionCode
).Append( aText
);
877 mnTotalHeight
= ::std::max( mnTotalHeight
, nHeight
);
881 // URL conversion =============================================================
885 /** Encodes special parts of the URL, i.e. directory separators and volume names.
886 @param pTableName Pointer to a table name to be encoded in this URL, or 0. */
887 OUString
lclEncodeDosUrl(
888 XclBiff eBiff
, const OUString
& rUrl
, const OUString
& rBase
, const OUString
* pTableName
)
894 OUString aOldUrl
= rUrl
;
895 aBuf
.append(EXC_URLSTART_ENCODED
);
897 if ( aOldUrl
.getLength() > 2 && aOldUrl
.copy(0,2) == "\\\\" )
900 aBuf
.append(EXC_URL_DOSDRIVE
).append(sal_Unicode('@'));
901 aOldUrl
= aOldUrl
.copy(2);
903 else if ( aOldUrl
.getLength() > 2 && aOldUrl
.copy(1,2) == ":\\" )
906 sal_Unicode cThisDrive
= rBase
.isEmpty() ? ' ' : rBase
.getStr()[0];
907 sal_Unicode cDrive
= aOldUrl
.getStr()[0];
908 if (cThisDrive
== cDrive
)
909 // This document and the referenced document are under the same drive.
910 aBuf
.append(EXC_URL_DRIVEROOT
);
912 aBuf
.append(EXC_URL_DOSDRIVE
).append(cDrive
);
913 aOldUrl
= aOldUrl
.copy(3);
918 while((nPos
= aOldUrl
.indexOf('\\')) != -1)
920 if ( aOldUrl
.copy(0,2) == ".." )
921 // parent dir (NOTE: the MS-XLS spec doesn't mention this, and
922 // Excel seems confused by this token).
923 aBuf
.append(EXC_URL_PARENTDIR
);
925 aBuf
.append(aOldUrl
.copy(0,nPos
)).append(EXC_URL_SUBDIR
);
927 aOldUrl
= aOldUrl
.copy(nPos
+ 1);
931 if (pTableName
) // enclose file name in brackets if table name follows
932 aBuf
.append(sal_Unicode('[')).append(aOldUrl
).append(sal_Unicode(']'));
934 aBuf
.append(aOldUrl
);
936 else // empty URL -> self reference
941 aBuf
.append(pTableName
? EXC_URLSTART_SELFENCODED
: EXC_URLSTART_SELF
);
944 DBG_ASSERT( pTableName
, "lclEncodeDosUrl - sheet name required for BIFF8" );
945 aBuf
.append(EXC_URLSTART_SELF
);
954 aBuf
.append(*pTableName
);
956 return aBuf
.makeStringAndClear();
961 // ----------------------------------------------------------------------------
963 OUString
XclExpUrlHelper::EncodeUrl( const XclExpRoot
& rRoot
, const OUString
& rAbsUrl
, const OUString
* pTableName
)
965 OUString aDosUrl
= INetURLObject(rAbsUrl
).getFSysPath(INetURLObject::FSYS_DOS
);
966 OUString aDosBase
= INetURLObject(rRoot
.GetBasePath()).getFSysPath(INetURLObject::FSYS_DOS
);
967 return lclEncodeDosUrl(rRoot
.GetBiff(), aDosUrl
, aDosBase
, pTableName
);
970 OUString
XclExpUrlHelper::EncodeDde( const OUString
& rApplic
, const OUString
& rTopic
)
973 aBuf
.append(rApplic
).append(EXC_DDE_DELIM
).append(rTopic
);
974 return aBuf
.makeStringAndClear();
977 // Cached Value Lists =========================================================
979 XclExpCachedMatrix::XclExpCachedMatrix( const ScMatrix
& rMatrix
)
980 : mrMatrix( rMatrix
)
984 XclExpCachedMatrix::~XclExpCachedMatrix()
989 void XclExpCachedMatrix::GetDimensions( SCSIZE
& nCols
, SCSIZE
& nRows
) const
991 mrMatrix
.GetDimensions( nCols
, nRows
);
993 OSL_ENSURE( nCols
&& nRows
, "XclExpCachedMatrix::GetDimensions - empty matrix" );
994 OSL_ENSURE( nCols
<= 256, "XclExpCachedMatrix::GetDimensions - too many columns" );
997 sal_Size
XclExpCachedMatrix::GetSize() const
1001 GetDimensions( nCols
, nRows
);
1003 /* The returned size may be wrong if the matrix contains strings. The only
1004 effect is that the export stream has to update a wrong record size which is
1005 faster than to iterate through all cached values and calculate their sizes. */
1006 return 3 + 9 * (nCols
* nRows
);
1009 void XclExpCachedMatrix::Save( XclExpStream
& rStrm
) const
1011 SCSIZE nCols
, nRows
;
1013 GetDimensions( nCols
, nRows
);
1015 if( rStrm
.GetRoot().GetBiff() <= EXC_BIFF5
)
1016 // in BIFF2-BIFF7: 256 columns represented by 0 columns
1017 rStrm
<< static_cast< sal_uInt8
>( nCols
) << static_cast< sal_uInt16
>( nRows
);
1019 // in BIFF8: columns and rows decreaed by 1
1020 rStrm
<< static_cast< sal_uInt8
>( nCols
- 1 ) << static_cast< sal_uInt16
>( nRows
- 1 );
1022 for( SCSIZE nRow
= 0; nRow
< nRows
; ++nRow
)
1024 for( SCSIZE nCol
= 0; nCol
< nCols
; ++nCol
)
1026 ScMatrixValue nMatVal
= mrMatrix
.Get( nCol
, nRow
);
1028 if( SC_MATVAL_EMPTY
== nMatVal
.nType
)
1030 rStrm
.SetSliceSize( 9 );
1031 rStrm
<< EXC_CACHEDVAL_EMPTY
;
1032 rStrm
.WriteZeroBytes( 8 );
1034 else if( ScMatrix::IsNonValueType( nMatVal
.nType
) )
1036 XclExpString
aStr( nMatVal
.GetString(), EXC_STR_DEFAULT
);
1037 rStrm
.SetSliceSize( 6 );
1038 rStrm
<< EXC_CACHEDVAL_STRING
<< aStr
;
1040 else if( SC_MATVAL_BOOLEAN
== nMatVal
.nType
)
1042 sal_Int8 nBool
= nMatVal
.GetBoolean();
1043 rStrm
.SetSliceSize( 9 );
1044 rStrm
<< EXC_CACHEDVAL_BOOL
<< nBool
;
1045 rStrm
.WriteZeroBytes( 7 );
1047 else if( sal_uInt16 nScError
= nMatVal
.GetError() )
1049 sal_Int8
nError ( XclTools::GetXclErrorCode( nScError
) );
1050 rStrm
.SetSliceSize( 9 );
1051 rStrm
<< EXC_CACHEDVAL_ERROR
<< nError
;
1052 rStrm
.WriteZeroBytes( 7 );
1056 rStrm
.SetSliceSize( 9 );
1057 rStrm
<< EXC_CACHEDVAL_DOUBLE
<< nMatVal
.fVal
;
1063 // ============================================================================
1065 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */