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 .
21 #include <xistyle.hxx>
22 #include <sfx2/objsh.hxx>
23 #include <svtools/ctrltool.hxx>
24 #include <editeng/editobj.hxx>
25 #include <scitems.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/wghtitem.hxx>
29 #include <editeng/udlnitem.hxx>
30 #include <editeng/postitem.hxx>
31 #include <editeng/crossedoutitem.hxx>
32 #include <editeng/contouritem.hxx>
33 #include <editeng/shdditem.hxx>
34 #include <editeng/escapementitem.hxx>
35 #include <svx/algitem.hxx>
36 #include <editeng/borderline.hxx>
37 #include <editeng/boxitem.hxx>
38 #include <editeng/lineitem.hxx>
39 #include <svx/rotmodit.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/frmdiritem.hxx>
43 #include <editeng/eeitem.hxx>
44 #include <editeng/flstitem.hxx>
45 #include <editeng/justifyitem.hxx>
46 #include <editeng/editids.hrc>
47 #include <sal/macros.h>
48 #include <sal/log.hxx>
49 #include <tools/UnitConversion.hxx>
50 #include <vcl/fontcharmap.hxx>
51 #include <vcl/outdev.hxx>
52 #include <document.hxx>
53 #include <documentimport.hxx>
54 #include <docpool.hxx>
56 #include <patattr.hxx>
57 #include <stlpool.hxx>
58 #include <stlsheet.hxx>
59 #include <globstr.hrc>
60 #include <scresid.hxx>
61 #include <attarray.hxx>
62 #include <xladdress.hxx>
63 #include <xlcontent.hxx>
64 #include <xltracer.hxx>
65 #include <xltools.hxx>
66 #include <xistream.hxx>
67 #include <xicontent.hxx>
70 #include <colrowst.hxx>
72 #include <string_view>
75 #include <cppuhelper/implbase.hxx>
76 #include <com/sun/star/container/XIndexAccess.hpp>
77 #include <com/sun/star/beans/XPropertySet.hpp>
78 #include <com/sun/star/frame/XModel.hpp>
79 #include <svl/numformat.hxx>
82 using namespace ::com::sun::star
;
84 typedef ::cppu::WeakImplHelper
< container::XIndexAccess
> XIndexAccess_BASE
;
85 typedef ::std::vector
< Color
> ColorVec
;
89 class PaletteIndex
: public XIndexAccess_BASE
92 explicit PaletteIndex( ColorVec
&& rColorTable
) : maColor( std::move(rColorTable
) ) {}
94 // Methods XIndexAccess
95 virtual ::sal_Int32 SAL_CALL
getCount() override
97 return maColor
.size();
100 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) override
102 //--Index; // apparently the palette is already 1 based
103 return uno::makeAny( sal_Int32( maColor
[ Index
] ) );
106 // Methods XElementAccess
107 virtual uno::Type SAL_CALL
getElementType() override
109 return ::cppu::UnoType
<sal_Int32
>::get();
111 virtual sal_Bool SAL_CALL
hasElements() override
113 return (!maColor
.empty());
123 XclImpPalette::ExportPalette()
125 SfxObjectShell
* pDocShell
= mrRoot
.GetDocShell();
129 // copy values in color palette
130 sal_Int16 nColors
= maColorTable
.size();
132 aColors
.resize( nColors
);
133 for( sal_uInt16 nIndex
= 0; nIndex
< nColors
; ++nIndex
)
134 aColors
[ nIndex
] = GetColor( nIndex
);
136 uno::Reference
< beans::XPropertySet
> xProps( pDocShell
->GetModel(), uno::UNO_QUERY
);
139 uno::Reference
< container::XIndexAccess
> xIndex( new PaletteIndex( std::move(aColors
) ) );
140 xProps
->setPropertyValue( "ColorPalette", uno::makeAny( xIndex
) );
144 // PALETTE record - color information =========================================
146 XclImpPalette::XclImpPalette( const XclImpRoot
& rRoot
) :
147 XclDefaultPalette( rRoot
), mrRoot( rRoot
)
151 void XclImpPalette::Initialize()
153 maColorTable
.clear();
156 Color
XclImpPalette::GetColor( sal_uInt16 nXclIndex
) const
158 if( nXclIndex
>= EXC_COLOR_USEROFFSET
)
160 sal_uInt32 nIx
= nXclIndex
- EXC_COLOR_USEROFFSET
;
161 if( nIx
< maColorTable
.size() )
162 return maColorTable
[ nIx
];
164 return GetDefColor( nXclIndex
);
167 void XclImpPalette::ReadPalette( XclImpStream
& rStrm
)
170 nCount
= rStrm
.ReaduInt16();
172 const size_t nMinRecordSize
= 4;
173 const size_t nMaxRecords
= rStrm
.GetRecLeft() / nMinRecordSize
;
174 if (nCount
> nMaxRecords
)
176 SAL_WARN("sc", "Parsing error: " << nMaxRecords
<<
177 " max possible entries, but " << nCount
<< " claimed, truncating");
178 nCount
= nMaxRecords
;
181 maColorTable
.resize( nCount
);
183 for( sal_uInt16 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
186 maColorTable
[ nIndex
] = aColor
;
191 // FONT record - font information =============================================
192 XclImpFont::XclImpFont( const XclImpRoot
& rRoot
) :
194 mbHasCharSet( false ),
199 SetAllUsedFlags( false );
202 XclImpFont::XclImpFont( const XclImpRoot
& rRoot
, const XclFontData
& rFontData
) :
205 SetFontData( rFontData
, false );
208 void XclImpFont::SetAllUsedFlags( bool bUsed
)
210 mbFontNameUsed
= mbHeightUsed
= mbColorUsed
= mbWeightUsed
= mbEscapemUsed
=
211 mbUnderlUsed
= mbItalicUsed
= mbStrikeUsed
= mbOutlineUsed
= mbShadowUsed
= bUsed
;
214 void XclImpFont::SetFontData( const XclFontData
& rFontData
, bool bHasCharSet
)
217 mbHasCharSet
= bHasCharSet
;
218 if( !maData
.maStyle
.isEmpty() )
220 if( SfxObjectShell
* pDocShell
= GetDocShell() )
222 if( const SvxFontListItem
* pInfoItem
= static_cast< const SvxFontListItem
* >(
223 pDocShell
->GetItem( SID_ATTR_CHAR_FONTLIST
) ) )
225 if( const FontList
* pFontList
= pInfoItem
->GetFontList() )
227 FontMetric
aFontMetric( pFontList
->Get( maData
.maName
, maData
.maStyle
) );
228 maData
.SetScWeight( aFontMetric
.GetWeight() );
229 maData
.SetScPosture( aFontMetric
.GetItalic() );
233 maData
.maStyle
.clear();
236 SetAllUsedFlags( true );
239 rtl_TextEncoding
XclImpFont::GetFontEncoding() const
241 // #i63105# use text encoding from FONT record
242 // #i67768# BIFF2-BIFF4 FONT records do not contain character set
243 rtl_TextEncoding eFontEnc
= mbHasCharSet
? maData
.GetFontEncoding() : GetTextEncoding();
244 return (eFontEnc
== RTL_TEXTENCODING_DONTKNOW
) ? GetTextEncoding() : eFontEnc
;
247 void XclImpFont::ReadFont( XclImpStream
& rStrm
)
252 ReadFontData2( rStrm
);
253 ReadFontName2( rStrm
);
257 ReadFontData2( rStrm
);
258 ReadFontColor( rStrm
);
259 ReadFontName2( rStrm
);
262 ReadFontData5( rStrm
);
263 ReadFontName2( rStrm
);
266 ReadFontData5( rStrm
);
267 ReadFontName8( rStrm
);
274 SetAllUsedFlags( true );
277 void XclImpFont::ReadEfont( XclImpStream
& rStrm
)
279 ReadFontColor( rStrm
);
282 void XclImpFont::ReadCFFontBlock( XclImpStream
& rStrm
)
284 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8
);
285 if( GetBiff() != EXC_BIFF8
)
289 sal_uInt32 nHeight
= rStrm
.ReaduInt32();
290 sal_uInt32 nStyle
= rStrm
.ReaduInt32();
291 sal_uInt16 nWeight
= rStrm
.ReaduInt16();
292 rStrm
.Ignore( 2 ); //nEscapem
293 sal_uInt8 nUnderl
= rStrm
.ReaduInt8();
295 sal_uInt32 nColor
= rStrm
.ReaduInt32();
297 sal_uInt32 nFontFlags1
= rStrm
.ReaduInt32();
298 rStrm
.Ignore( 4 ); //nFontFlags2
299 sal_uInt32 nFontFlags3
= rStrm
.ReaduInt32();
302 if( (mbHeightUsed
= (nHeight
<= 0x7FFF)) )
303 maData
.mnHeight
= static_cast< sal_uInt16
>( nHeight
);
304 if( (mbWeightUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STYLE
) && (nWeight
< 0x7FFF)) )
305 maData
.mnWeight
= nWeight
;
306 if( (mbItalicUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STYLE
)) )
307 maData
.mbItalic
= ::get_flag( nStyle
, EXC_CF_FONT_STYLE
);
308 if( (mbUnderlUsed
= !::get_flag( nFontFlags3
, EXC_CF_FONT_UNDERL
) && (nUnderl
<= 0x7F)) )
309 maData
.mnUnderline
= nUnderl
;
310 if( (mbColorUsed
= (nColor
<= 0x7FFF)) )
311 maData
.maColor
= GetPalette().GetColor( static_cast< sal_uInt16
>( nColor
) );
312 if( (mbStrikeUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STRIKEOUT
)) )
313 maData
.mbStrikeout
= ::get_flag( nStyle
, EXC_CF_FONT_STRIKEOUT
);
316 void XclImpFont::FillToItemSet( SfxItemSet
& rItemSet
, XclFontItemType eType
, bool bSkipPoolDefs
) const
318 // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
319 bool bEE
= eType
!= XclFontItemType::Cell
;
321 // item = the item to put into the item set
322 // sc_which = the Calc Which-ID of the item
323 // ee_which = the edit engine Which-ID of the item
324 #define PUTITEM( item, sc_which, ee_which ) \
325 ScfTools::PutItem( rItemSet, item, (bEE ? (static_cast<sal_uInt16>(ee_which)) : (sc_which)), bSkipPoolDefs )
330 rtl_TextEncoding eFontEnc
= maData
.GetFontEncoding();
331 rtl_TextEncoding eTempTextEnc
= (bEE
&& (eFontEnc
== GetTextEncoding())) ?
332 ScfTools::GetSystemTextEncoding() : eFontEnc
;
334 //add corresponding pitch for FontFamily
335 FontPitch ePitch
= PITCH_DONTKNOW
;
336 FontFamily eFtFamily
= maData
.GetScFamily( GetTextEncoding() );
337 switch( eFtFamily
) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx
339 case FAMILY_ROMAN
: ePitch
= PITCH_VARIABLE
; break;
340 case FAMILY_SWISS
: ePitch
= PITCH_VARIABLE
; break;
341 case FAMILY_MODERN
: ePitch
= PITCH_FIXED
; break;
344 SvxFontItem
aFontItem( eFtFamily
, maData
.maName
, OUString(), ePitch
, eTempTextEnc
, ATTR_FONT
);
346 // set only for valid script types
348 PUTITEM( aFontItem
, ATTR_FONT
, EE_CHAR_FONTINFO
);
350 PUTITEM( aFontItem
, ATTR_CJK_FONT
, EE_CHAR_FONTINFO_CJK
);
352 PUTITEM( aFontItem
, ATTR_CTL_FONT
, EE_CHAR_FONTINFO_CTL
);
355 // Font height (for all script types)
358 sal_Int32 nHeight
= maData
.mnHeight
;
359 if( bEE
&& (eType
!= XclFontItemType::HeaderFooter
) ) // do not convert header/footer height
360 nHeight
= convertTwipToMm100(nHeight
);
362 SvxFontHeightItem
aHeightItem( nHeight
, 100, ATTR_FONT_HEIGHT
);
363 PUTITEM( aHeightItem
, ATTR_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT
);
364 PUTITEM( aHeightItem
, ATTR_CJK_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT_CJK
);
365 PUTITEM( aHeightItem
, ATTR_CTL_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT_CTL
);
368 // Font color - pass AUTO_COL to item
370 PUTITEM( SvxColorItem( maData
.maColor
, ATTR_FONT_COLOR
), ATTR_FONT_COLOR
, EE_CHAR_COLOR
);
372 // Font weight (for all script types)
375 SvxWeightItem
aWeightItem( maData
.GetScWeight(), ATTR_FONT_WEIGHT
);
376 PUTITEM( aWeightItem
, ATTR_FONT_WEIGHT
, EE_CHAR_WEIGHT
);
377 PUTITEM( aWeightItem
, ATTR_CJK_FONT_WEIGHT
, EE_CHAR_WEIGHT_CJK
);
378 PUTITEM( aWeightItem
, ATTR_CTL_FONT_WEIGHT
, EE_CHAR_WEIGHT_CTL
);
384 SvxUnderlineItem
aUnderlItem( maData
.GetScUnderline(), ATTR_FONT_UNDERLINE
);
385 PUTITEM( aUnderlItem
, ATTR_FONT_UNDERLINE
, EE_CHAR_UNDERLINE
);
388 // Font posture (for all script types)
391 SvxPostureItem
aPostItem( maData
.GetScPosture(), ATTR_FONT_POSTURE
);
392 PUTITEM( aPostItem
, ATTR_FONT_POSTURE
, EE_CHAR_ITALIC
);
393 PUTITEM( aPostItem
, ATTR_CJK_FONT_POSTURE
, EE_CHAR_ITALIC_CJK
);
394 PUTITEM( aPostItem
, ATTR_CTL_FONT_POSTURE
, EE_CHAR_ITALIC_CTL
);
397 // Boolean attributes crossed out, contoured, shadowed
399 PUTITEM( SvxCrossedOutItem( maData
.GetScStrikeout(), ATTR_FONT_CROSSEDOUT
), ATTR_FONT_CROSSEDOUT
, EE_CHAR_STRIKEOUT
);
401 PUTITEM( SvxContourItem( maData
.mbOutline
, ATTR_FONT_CONTOUR
), ATTR_FONT_CONTOUR
, EE_CHAR_OUTLINE
);
403 PUTITEM( SvxShadowedItem( maData
.mbShadow
, ATTR_FONT_SHADOWED
), ATTR_FONT_SHADOWED
, EE_CHAR_SHADOW
);
405 // Super-/subscript: only on edit engine objects
406 if( mbEscapemUsed
&& bEE
)
407 rItemSet
.Put( SvxEscapementItem( maData
.GetScEscapement(), EE_CHAR_ESCAPEMENT
) );
412 void XclImpFont::WriteFontProperties( ScfPropertySet
& rPropSet
,
413 XclFontPropSetType eType
, const Color
* pFontColor
) const
415 GetFontPropSetHelper().WriteFontProperties(
416 rPropSet
, eType
, maData
, mbHasWstrn
, mbHasAsian
, mbHasCmplx
, pFontColor
);
419 void XclImpFont::ReadFontData2( XclImpStream
& rStrm
)
422 maData
.mnHeight
= rStrm
.ReaduInt16();
423 nFlags
= rStrm
.ReaduInt16();
425 maData
.mnWeight
= ::get_flagvalue( nFlags
, EXC_FONTATTR_BOLD
, EXC_FONTWGHT_BOLD
, EXC_FONTWGHT_NORMAL
);
426 maData
.mnUnderline
= ::get_flagvalue( nFlags
, EXC_FONTATTR_UNDERLINE
, EXC_FONTUNDERL_SINGLE
, EXC_FONTUNDERL_NONE
);
427 maData
.mbItalic
= ::get_flag( nFlags
, EXC_FONTATTR_ITALIC
);
428 maData
.mbStrikeout
= ::get_flag( nFlags
, EXC_FONTATTR_STRIKEOUT
);
429 maData
.mbOutline
= ::get_flag( nFlags
, EXC_FONTATTR_OUTLINE
);
430 maData
.mbShadow
= ::get_flag( nFlags
, EXC_FONTATTR_SHADOW
);
431 mbHasCharSet
= false;
434 void XclImpFont::ReadFontData5( XclImpStream
& rStrm
)
438 maData
.mnHeight
= rStrm
.ReaduInt16();
439 nFlags
= rStrm
.ReaduInt16();
440 ReadFontColor( rStrm
);
441 maData
.mnWeight
= rStrm
.ReaduInt16();
442 maData
.mnEscapem
= rStrm
.ReaduInt16();
443 maData
.mnUnderline
= rStrm
.ReaduInt8();
444 maData
.mnFamily
= rStrm
.ReaduInt8();
445 maData
.mnCharSet
= rStrm
.ReaduInt8();
448 maData
.mbItalic
= ::get_flag( nFlags
, EXC_FONTATTR_ITALIC
);
449 maData
.mbStrikeout
= ::get_flag( nFlags
, EXC_FONTATTR_STRIKEOUT
);
450 maData
.mbOutline
= ::get_flag( nFlags
, EXC_FONTATTR_OUTLINE
);
451 maData
.mbShadow
= ::get_flag( nFlags
, EXC_FONTATTR_SHADOW
);
452 mbHasCharSet
= maData
.mnCharSet
!= 0;
455 void XclImpFont::ReadFontColor( XclImpStream
& rStrm
)
457 maData
.maColor
= GetPalette().GetColor( rStrm
.ReaduInt16() );
460 void XclImpFont::ReadFontName2( XclImpStream
& rStrm
)
462 maData
.maName
= rStrm
.ReadByteString( false );
465 void XclImpFont::ReadFontName8( XclImpStream
& rStrm
)
467 maData
.maName
= rStrm
.ReadUniString( rStrm
.ReaduInt8() );
470 void XclImpFont::GuessScriptType()
473 mbHasAsian
= mbHasCmplx
= false;
475 // find the script types for which the font contains characters
476 OutputDevice
* pPrinter
= GetPrinter();
480 vcl::Font
aFont( maData
.maName
, Size( 0, 10 ) );
481 FontCharMapRef xFontCharMap
;
483 pPrinter
->SetFont( aFont
);
484 if( !pPrinter
->GetFontCharMap( xFontCharMap
) )
489 xFontCharMap
->HasChar( 0x3041 ) || // 3040-309F: Hiragana
490 xFontCharMap
->HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
491 xFontCharMap
->HasChar( 0x3111 ) || // 3100-312F: Bopomofo
492 xFontCharMap
->HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
493 xFontCharMap
->HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
494 xFontCharMap
->HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
495 xFontCharMap
->HasChar( 0x4E01 ) || // 4E00-9FFF: CJK Unified Ideographs
496 xFontCharMap
->HasChar( 0x7E01 ) || // 4E00-9FFF: CJK Unified Ideographs
497 xFontCharMap
->HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
498 xFontCharMap
->HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
499 xFontCharMap
->HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
500 xFontCharMap
->HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
501 xFontCharMap
->HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
504 xFontCharMap
->HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
505 xFontCharMap
->HasChar( 0x0631 ) || // 0600-06FF: Arabic
506 xFontCharMap
->HasChar( 0x0721 ) || // 0700-074F: Syriac
507 xFontCharMap
->HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
508 xFontCharMap
->HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
509 xFontCharMap
->HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
510 xFontCharMap
->HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
511 xFontCharMap
->HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
513 mbHasWstrn
= (!mbHasAsian
&& !mbHasCmplx
) || xFontCharMap
->HasChar( 'A' );
516 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot
& rRoot
) :
523 // default font for form controls without own font information
524 XclFontData aCtrlFontData
;
531 aCtrlFontData
.maName
= "Helv";
532 aCtrlFontData
.mnHeight
= 160;
533 aCtrlFontData
.mnWeight
= EXC_FONTWGHT_BOLD
;
536 aCtrlFontData
.maName
= "Tahoma";
537 aCtrlFontData
.mnHeight
= 160;
538 aCtrlFontData
.mnWeight
= EXC_FONTWGHT_NORMAL
;
543 maCtrlFont
.SetFontData( aCtrlFontData
, false );
546 void XclImpFontBuffer::Initialize()
550 // application font for column width calculation, later filled with first font from font list
551 XclFontData aAppFontData
;
552 aAppFontData
.maName
= "Arial";
553 aAppFontData
.mnHeight
= 200;
554 aAppFontData
.mnWeight
= EXC_FONTWGHT_NORMAL
;
555 UpdateAppFont( aAppFontData
, false );
558 const XclImpFont
* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex
) const
560 /* Font with index 4 is not stored in an Excel file, but used e.g. by
561 BIFF5 form pushbutton objects. It is the bold default font.
562 This also means that entries above 4 are out by one in the list. */
569 // Font ID is zero-based when it's less than 4.
570 return nFontIndex
>= maFontList
.size() ? nullptr : &maFontList
[nFontIndex
];
573 // Font ID is greater than 4. It is now 1-based.
574 return nFontIndex
> maFontList
.size() ? nullptr : &maFontList
[nFontIndex
-1];
577 void XclImpFontBuffer::ReadFont( XclImpStream
& rStrm
)
579 maFontList
.emplace_back( GetRoot() );
580 XclImpFont
& rFont
= maFontList
.back();
581 rFont
.ReadFont( rStrm
);
583 if( maFontList
.size() == 1 )
585 UpdateAppFont( rFont
.GetFontData(), rFont
.HasCharSet() );
589 void XclImpFontBuffer::ReadEfont( XclImpStream
& rStrm
)
591 if( !maFontList
.empty() )
592 maFontList
.back().ReadEfont( rStrm
);
595 void XclImpFontBuffer::FillToItemSet(
596 SfxItemSet
& rItemSet
, XclFontItemType eType
,
597 sal_uInt16 nFontIdx
, bool bSkipPoolDefs
) const
599 if( const XclImpFont
* pFont
= GetFont( nFontIdx
) )
600 pFont
->FillToItemSet( rItemSet
, eType
, bSkipPoolDefs
);
603 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet
& rPropSet
,
604 XclFontPropSetType eType
, sal_uInt16 nFontIdx
, const Color
* pFontColor
) const
606 if( const XclImpFont
* pFont
= GetFont( nFontIdx
) )
607 pFont
->WriteFontProperties( rPropSet
, eType
, pFontColor
);
610 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet
& rPropSet
) const
612 maCtrlFont
.WriteFontProperties( rPropSet
, EXC_FONTPROPSET_CONTROL
);
615 void XclImpFontBuffer::UpdateAppFont( const XclFontData
& rFontData
, bool bHasCharSet
)
617 maAppFont
= rFontData
;
618 // #i3006# Calculate the width of '0' from first font and current printer.
619 SetCharWidth( maAppFont
);
621 // font 4 is bold font 0
622 XclFontData
aFont4Data( maAppFont
);
623 aFont4Data
.mnWeight
= EXC_FONTWGHT_BOLD
;
624 maFont4
.SetFontData( aFont4Data
, bHasCharSet
);
627 // FORMAT record - number formats =============================================
629 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot
& rRoot
) :
630 XclNumFmtBuffer( rRoot
),
636 void XclImpNumFmtBuffer::Initialize()
640 InitializeImport(); // base class
643 void XclImpNumFmtBuffer::ReadFormat( XclImpStream
& rStrm
)
650 aFormat
= rStrm
.ReadByteString( false );
654 rStrm
.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
655 aFormat
= rStrm
.ReadByteString( false );
659 mnNextXclIdx
= rStrm
.ReaduInt16();
660 aFormat
= rStrm
.ReadByteString( false );
664 mnNextXclIdx
= rStrm
.ReaduInt16();
665 aFormat
= rStrm
.ReadUniString();
673 if( mnNextXclIdx
< 0xFFFF )
675 InsertFormat( mnNextXclIdx
, aFormat
);
680 sal_uInt16
XclImpNumFmtBuffer::ReadCFFormat( XclImpStream
& rStrm
, bool bIFmt
)
682 // internal number format ?
687 nIndex
= rStrm
.ReaduInt8();
692 OUString aFormat
= rStrm
.ReadUniString();
693 InsertFormat( mnNextXclIdx
, aFormat
);
695 return mnNextXclIdx
- 1;
699 void XclImpNumFmtBuffer::CreateScFormats()
701 OSL_ENSURE( maIndexMap
.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
703 SvNumberFormatter
& rFormatter
= GetFormatter();
704 for( const auto& [rXclNumFmt
, rNumFmt
] : GetFormatMap() )
706 // insert/convert the Excel number format
708 if( !rNumFmt
.maFormat
.isEmpty() )
710 OUString
aFormat( rNumFmt
.maFormat
);
712 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
713 rFormatter
.PutandConvertEntry( aFormat
, nCheckPos
,
714 nType
, nKey
, LANGUAGE_ENGLISH_US
, rNumFmt
.meLanguage
, false);
717 nKey
= rFormatter
.GetFormatIndex( rNumFmt
.meOffset
, rNumFmt
.meLanguage
);
719 // insert the resulting format key into the Excel->Calc index map
720 maIndexMap
[ rXclNumFmt
] = nKey
;
724 sal_uInt32
XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt
) const
726 XclImpIndexMap::const_iterator aIt
= maIndexMap
.find( nXclNumFmt
);
727 return (aIt
!= maIndexMap
.end()) ? aIt
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
;
730 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet
& rItemSet
, sal_uInt16 nXclNumFmt
, bool bSkipPoolDefs
) const
732 sal_uInt32 nScNumFmt
= GetScFormat( nXclNumFmt
);
733 if( nScNumFmt
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
734 nScNumFmt
= GetStdScNumFmt();
735 FillScFmtToItemSet( rItemSet
, nScNumFmt
, bSkipPoolDefs
);
738 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet
& rItemSet
, sal_uInt32 nScNumFmt
, bool bSkipPoolDefs
) const
740 OSL_ENSURE( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
741 ScfTools::PutItem( rItemSet
, SfxUInt32Item( ATTR_VALUE_FORMAT
, nScNumFmt
), bSkipPoolDefs
);
742 if( rItemSet
.GetItemState( ATTR_VALUE_FORMAT
, false ) == SfxItemState::SET
)
743 ScGlobal::AddLanguage( rItemSet
, GetFormatter() );
746 // XF, STYLE record - Cell formatting =========================================
748 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt
)
750 mbLocked
= ::get_flag( nNumFmt
, EXC_XF2_LOCKED
);
751 mbHidden
= ::get_flag( nNumFmt
, EXC_XF2_HIDDEN
);
754 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt
)
756 mbLocked
= ::get_flag( nProt
, EXC_XF_LOCKED
);
757 mbHidden
= ::get_flag( nProt
, EXC_XF_HIDDEN
);
760 void XclImpCellProt::FillToItemSet( SfxItemSet
& rItemSet
, bool bSkipPoolDefs
) const
762 ScfTools::PutItem( rItemSet
, ScProtectionAttr( mbLocked
, mbHidden
), bSkipPoolDefs
);
765 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags
)
767 mnHorAlign
= ::extract_value
< sal_uInt8
>( nFlags
, 0, 3 );
770 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign
)
772 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
773 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
); // new in BIFF3
776 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign
)
778 FillFromXF3( nAlign
);
779 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 2 ); // new in BIFF4
780 mnOrient
= ::extract_value
< sal_uInt8
>( nAlign
, 6, 2 ); // new in BIFF4
783 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign
)
785 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
786 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
787 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
);
788 mnOrient
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 2 );
791 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign
, sal_uInt16 nMiscAttrib
)
793 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
794 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
795 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
);
796 mnRotation
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 8 ); // new in BIFF8
797 mnIndent
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 0, 4 ); // new in BIFF8
798 mbShrink
= ::get_flag( nMiscAttrib
, EXC_XF8_SHRINK
); // new in BIFF8
799 mnTextDir
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 6, 2 ); // new in BIFF8
802 void XclImpCellAlign::FillFromCF( sal_uInt16 nAlign
, sal_uInt16 nMiscAttrib
)
804 mnHorAlign
= extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
805 mbLineBreak
= get_flag
< sal_uInt8
>( nAlign
, EXC_XF_LINEBREAK
);
806 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
807 mnRotation
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 8 );
808 mnIndent
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 0, 4 );
809 mbShrink
= ::get_flag( nMiscAttrib
, EXC_XF8_SHRINK
);
810 mnTextDir
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 6, 2 );
813 void XclImpCellAlign::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpFont
* pFont
, bool bSkipPoolDefs
) const
815 // horizontal alignment
816 ScfTools::PutItem( rItemSet
, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY
), bSkipPoolDefs
);
817 ScfTools::PutItem( rItemSet
, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD
), bSkipPoolDefs
);
819 // text wrap (#i74508# always if vertical alignment is justified or distributed)
820 bool bLineBreak
= mbLineBreak
|| (mnVerAlign
== EXC_XF_VER_JUSTIFY
) || (mnVerAlign
== EXC_XF_VER_DISTRIB
);
821 ScfTools::PutItem( rItemSet
, ScLineBreakCell( bLineBreak
), bSkipPoolDefs
);
823 // vertical alignment
824 ScfTools::PutItem( rItemSet
, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY
), bSkipPoolDefs
);
825 ScfTools::PutItem( rItemSet
, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD
), bSkipPoolDefs
);
828 sal_uInt16 nScIndent
= mnIndent
* 200; // 1 Excel unit == 10 pt == 200 twips
829 ScfTools::PutItem( rItemSet
, ScIndentItem( nScIndent
), bSkipPoolDefs
);
832 ScfTools::PutItem( rItemSet
, ScShrinkToFitCell( mbShrink
), bSkipPoolDefs
);
834 // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
835 sal_uInt8 nXclRot
= (mnOrient
== EXC_ORIENT_NONE
) ? mnRotation
: XclTools::GetXclRotFromOrient( mnOrient
);
836 bool bStacked
= (nXclRot
== EXC_ROT_STACKED
);
837 ScfTools::PutItem( rItemSet
, ScVerticalStackCell( bStacked
), bSkipPoolDefs
);
838 // set an angle in the range from -90 to 90 degrees
839 Degree100 nAngle
= XclTools::GetScRotation( nXclRot
, 0_deg100
);
840 ScfTools::PutItem( rItemSet
, ScRotateValueItem( nAngle
), bSkipPoolDefs
);
841 // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
842 bool bAsianVert
= bStacked
&& pFont
&& pFont
->HasAsianChars();
843 ScfTools::PutItem( rItemSet
, SfxBoolItem( ATTR_VERTICAL_ASIAN
, bAsianVert
), bSkipPoolDefs
);
845 // CTL text direction
846 ScfTools::PutItem( rItemSet
, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR
), bSkipPoolDefs
);
849 XclImpCellBorder::XclImpCellBorder()
851 SetUsedFlags( false, false );
854 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed
, bool bDiagUsed
)
856 mbLeftUsed
= mbRightUsed
= mbTopUsed
= mbBottomUsed
= bOuterUsed
;
857 mbDiagUsed
= bDiagUsed
;
860 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags
)
862 mnLeftLine
= ::get_flagvalue( nFlags
, EXC_XF2_LEFTLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
863 mnRightLine
= ::get_flagvalue( nFlags
, EXC_XF2_RIGHTLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
864 mnTopLine
= ::get_flagvalue( nFlags
, EXC_XF2_TOPLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
865 mnBottomLine
= ::get_flagvalue( nFlags
, EXC_XF2_BOTTOMLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
866 mnLeftColor
= mnRightColor
= mnTopColor
= mnBottomColor
= EXC_COLOR_BIFF2_BLACK
;
867 SetUsedFlags( true, false );
870 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder
)
872 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder
, 0, 3 );
873 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder
, 8, 3 );
874 mnBottomLine
= ::extract_value
< sal_uInt8
>( nBorder
, 16, 3 );
875 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder
, 24, 3 );
876 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder
, 3, 5 );
877 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder
, 11, 5 );
878 mnBottomColor
= ::extract_value
< sal_uInt16
>( nBorder
, 19, 5 );
879 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder
, 27, 5 );
880 SetUsedFlags( true, false );
883 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder
, sal_uInt32 nArea
)
885 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder
, 0, 3 );
886 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder
, 3, 3 );
887 mnBottomLine
= ::extract_value
< sal_uInt8
>( nArea
, 22, 3 );
888 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder
, 6, 3 );
889 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder
, 9, 7 );
890 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder
, 16, 7 );
891 mnBottomColor
= ::extract_value
< sal_uInt16
>( nArea
, 25, 7 );
892 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder
, 23, 7 );
893 SetUsedFlags( true, false );
896 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1
, sal_uInt32 nBorder2
)
898 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 0, 4 );
899 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 4, 4 );
900 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 8, 4 );
901 mnBottomLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 12, 4 );
902 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder1
, 16, 7 );
903 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder1
, 23, 7 );
904 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 0, 7 );
905 mnBottomColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 7, 7 );
906 mbDiagTLtoBR
= ::get_flag( nBorder1
, EXC_XF_DIAGONAL_TL_TO_BR
);
907 mbDiagBLtoTR
= ::get_flag( nBorder1
, EXC_XF_DIAGONAL_BL_TO_TR
);
908 if( mbDiagTLtoBR
|| mbDiagBLtoTR
)
910 mnDiagLine
= ::extract_value
< sal_uInt8
>( nBorder2
, 21, 4 );
911 mnDiagColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 14, 7 );
913 SetUsedFlags( true, true );
916 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle
, sal_uInt32 nLineColor
, sal_uInt32 nFlags
)
918 mnLeftLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 0, 4 );
919 mnRightLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 4, 4 );
920 mnTopLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 8, 4 );
921 mnBottomLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 12, 4 );
922 mnLeftColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 0, 7 );
923 mnRightColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 7, 7 );
924 mnTopColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 16, 7 );
925 mnBottomColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 23, 7 );
926 mbLeftUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_LEFT
);
927 mbRightUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_RIGHT
);
928 mbTopUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_TOP
);
929 mbBottomUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_BOTTOM
);
933 bool XclImpCellBorder::HasAnyOuterBorder() const
936 (mbLeftUsed
&& (mnLeftLine
!= EXC_LINE_NONE
)) ||
937 (mbRightUsed
&& (mnRightLine
!= EXC_LINE_NONE
)) ||
938 (mbTopUsed
&& (mnTopLine
!= EXC_LINE_NONE
)) ||
939 (mbBottomUsed
&& (mnBottomLine
!= EXC_LINE_NONE
));
944 /** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
945 bool lclConvertBorderLine( ::editeng::SvxBorderLine
& rLine
, const XclImpPalette
& rPalette
, sal_uInt8 nXclLine
, sal_uInt16 nXclColor
)
947 static const sal_uInt16 ppnLineParam
[][ 4 ] =
950 { 0, table::BorderLineStyle::SOLID
}, // 0 = none
951 { EXC_BORDER_THIN
, table::BorderLineStyle::SOLID
}, // 1 = thin
952 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::SOLID
}, // 2 = medium
953 { EXC_BORDER_THIN
, table::BorderLineStyle::FINE_DASHED
}, // 3 = dashed
954 { EXC_BORDER_THIN
, table::BorderLineStyle::DOTTED
}, // 4 = dotted
955 { EXC_BORDER_THICK
, table::BorderLineStyle::SOLID
}, // 5 = thick
956 { EXC_BORDER_THICK
, table::BorderLineStyle::DOUBLE_THIN
}, // 6 = double
957 { EXC_BORDER_HAIR
, table::BorderLineStyle::SOLID
}, // 7 = hair
958 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASHED
}, // 8 = med dash
959 { EXC_BORDER_THIN
, table::BorderLineStyle::DASH_DOT
}, // 9 = thin dashdot
960 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT
}, // A = med dashdot
961 { EXC_BORDER_THIN
, table::BorderLineStyle::DASH_DOT_DOT
}, // B = thin dashdotdot
962 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT_DOT
}, // C = med dashdotdot
963 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT
} // D = med slant dashdot
966 if( nXclLine
== EXC_LINE_NONE
)
968 if( nXclLine
>= SAL_N_ELEMENTS( ppnLineParam
) )
969 nXclLine
= EXC_LINE_THIN
;
971 rLine
.SetColor( rPalette
.GetColor( nXclColor
) );
972 rLine
.SetWidth( ppnLineParam
[ nXclLine
][ 0 ] );
973 rLine
.SetBorderLineStyle( static_cast< SvxBorderLineStyle
>(
974 ppnLineParam
[ nXclLine
][ 1 ]) );
980 void XclImpCellBorder::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpPalette
& rPalette
, bool bSkipPoolDefs
) const
982 if( mbLeftUsed
|| mbRightUsed
|| mbTopUsed
|| mbBottomUsed
)
984 SvxBoxItem
aBoxItem( ATTR_BORDER
);
985 ::editeng::SvxBorderLine aLine
;
986 if( mbLeftUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnLeftLine
, mnLeftColor
) )
987 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::LEFT
);
988 if( mbRightUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnRightLine
, mnRightColor
) )
989 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::RIGHT
);
990 if( mbTopUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnTopLine
, mnTopColor
) )
991 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::TOP
);
992 if( mbBottomUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnBottomLine
, mnBottomColor
) )
993 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::BOTTOM
);
994 ScfTools::PutItem( rItemSet
, aBoxItem
, bSkipPoolDefs
);
999 SvxLineItem
aTLBRItem( ATTR_BORDER_TLBR
);
1000 SvxLineItem
aBLTRItem( ATTR_BORDER_BLTR
);
1001 ::editeng::SvxBorderLine aLine
;
1002 if( lclConvertBorderLine( aLine
, rPalette
, mnDiagLine
, mnDiagColor
) )
1005 aTLBRItem
.SetLine( &aLine
);
1007 aBLTRItem
.SetLine( &aLine
);
1009 ScfTools::PutItem( rItemSet
, aTLBRItem
, bSkipPoolDefs
);
1010 ScfTools::PutItem( rItemSet
, aBLTRItem
, bSkipPoolDefs
);
1013 XclImpCellArea::XclImpCellArea()
1015 SetUsedFlags( false );
1018 void XclImpCellArea::SetUsedFlags( bool bUsed
)
1020 mbForeUsed
= mbBackUsed
= mbPattUsed
= bUsed
;
1023 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags
)
1025 mnPattern
= ::get_flagvalue( nFlags
, EXC_XF2_BACKGROUND
, EXC_PATT_12_5_PERC
, EXC_PATT_NONE
);
1026 mnForeColor
= EXC_COLOR_BIFF2_BLACK
;
1027 mnBackColor
= EXC_COLOR_BIFF2_WHITE
;
1028 SetUsedFlags( true );
1031 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea
)
1033 mnPattern
= ::extract_value
< sal_uInt8
>( nArea
, 0, 6 );
1034 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 6, 5 );
1035 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 11, 5 );
1036 SetUsedFlags( true );
1039 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea
)
1041 mnPattern
= ::extract_value
< sal_uInt8
>( nArea
, 16, 6 );
1042 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 0, 7 );
1043 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 7, 7 );
1044 SetUsedFlags( true );
1047 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2
, sal_uInt16 nArea
)
1049 mnPattern
= ::extract_value
< sal_uInt8
>( nBorder2
, 26, 6 );
1050 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 0, 7 );
1051 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 7, 7 );
1052 SetUsedFlags( true );
1055 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern
, sal_uInt16 nColor
, sal_uInt32 nFlags
)
1057 mnForeColor
= ::extract_value
< sal_uInt16
>( nColor
, 0, 7 );
1058 mnBackColor
= ::extract_value
< sal_uInt16
>( nColor
, 7, 7 );
1059 mnPattern
= ::extract_value
< sal_uInt8
>( nPattern
, 10, 6 );
1060 mbForeUsed
= !::get_flag( nFlags
, EXC_CF_AREA_FGCOLOR
);
1061 mbBackUsed
= !::get_flag( nFlags
, EXC_CF_AREA_BGCOLOR
);
1062 mbPattUsed
= !::get_flag( nFlags
, EXC_CF_AREA_PATTERN
);
1064 if( mbBackUsed
&& (!mbPattUsed
|| (mnPattern
== EXC_PATT_SOLID
)) )
1066 mnForeColor
= mnBackColor
;
1067 mnPattern
= EXC_PATT_SOLID
;
1068 mbForeUsed
= mbPattUsed
= true;
1070 else if( !mbBackUsed
&& mbPattUsed
&& (mnPattern
== EXC_PATT_SOLID
) )
1076 void XclImpCellArea::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpPalette
& rPalette
, bool bSkipPoolDefs
) const
1078 if( !mbPattUsed
) // colors may be both unused in cond. formats
1081 SvxBrushItem
aBrushItem( ATTR_BACKGROUND
);
1083 // do not use IsTransparent() - old Calc filter writes transparency with different color indexes
1084 if( mnPattern
== EXC_PATT_NONE
)
1086 aBrushItem
.SetColor( COL_TRANSPARENT
);
1090 Color
aFore( rPalette
.GetColor( mbForeUsed
? mnForeColor
: EXC_COLOR_WINDOWTEXT
) );
1091 Color
aBack( rPalette
.GetColor( mbBackUsed
? mnBackColor
: EXC_COLOR_WINDOWBACK
) );
1092 aBrushItem
.SetColor( XclTools::GetPatternColor( aFore
, aBack
, mnPattern
) );
1095 ScfTools::PutItem( rItemSet
, aBrushItem
, bSkipPoolDefs
);
1098 XclImpXF::XclImpXF( const XclImpRoot
& rRoot
) :
1099 XclXFBase( true ), // default is cell XF
1100 XclImpRoot( rRoot
),
1101 mpStyleSheet( nullptr ),
1107 XclImpXF::~XclImpXF()
1111 void XclImpXF::ReadXF2( XclImpStream
& rStrm
)
1113 sal_uInt8 nReadFont
, nReadNumFmt
, nFlags
;
1114 nReadFont
= rStrm
.ReaduInt8();
1116 nReadNumFmt
= rStrm
.ReaduInt8();
1117 nFlags
= rStrm
.ReaduInt8();
1119 // XF type always cell, no parent, used flags always true
1120 SetAllUsedFlags( true );
1123 maProtection
.FillFromXF2( nReadNumFmt
);
1124 mnXclFont
= nReadFont
;
1125 mnXclNumFmt
= nReadNumFmt
& EXC_XF2_VALFMT_MASK
;
1126 maAlignment
.FillFromXF2( nFlags
);
1127 maBorder
.FillFromXF2( nFlags
);
1128 maArea
.FillFromXF2( nFlags
);
1131 void XclImpXF::ReadXF3( XclImpStream
& rStrm
)
1134 sal_uInt16 nTypeProt
, nAlign
, nArea
;
1135 sal_uInt8 nReadFont
, nReadNumFmt
;
1136 nReadFont
= rStrm
.ReaduInt8();
1137 nReadNumFmt
= rStrm
.ReaduInt8();
1138 nTypeProt
= rStrm
.ReaduInt16();
1139 nAlign
= rStrm
.ReaduInt16();
1140 nArea
= rStrm
.ReaduInt16();
1141 nBorder
= rStrm
.ReaduInt32();
1143 // XF type/parent, attribute used flags
1144 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
); // new in BIFF3
1145 mnParent
= ::extract_value
< sal_uInt16
>( nAlign
, 4, 12 ); // new in BIFF3
1146 SetUsedFlags( ::extract_value
< sal_uInt8
>( nTypeProt
, 10, 6 ) );
1149 maProtection
.FillFromXF3( nTypeProt
);
1150 mnXclFont
= nReadFont
;
1151 mnXclNumFmt
= nReadNumFmt
;
1152 maAlignment
.FillFromXF3( nAlign
);
1153 maBorder
.FillFromXF3( nBorder
);
1154 maArea
.FillFromXF3( nArea
); // new in BIFF3
1157 void XclImpXF::ReadXF4( XclImpStream
& rStrm
)
1160 sal_uInt16 nTypeProt
, nAlign
, nArea
;
1161 sal_uInt8 nReadFont
, nReadNumFmt
;
1162 nReadFont
= rStrm
.ReaduInt8();
1163 nReadNumFmt
= rStrm
.ReaduInt8();
1164 nTypeProt
= rStrm
.ReaduInt16();
1165 nAlign
= rStrm
.ReaduInt16();
1166 nArea
= rStrm
.ReaduInt16();
1167 nBorder
= rStrm
.ReaduInt32();
1169 // XF type/parent, attribute used flags
1170 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1171 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1172 SetUsedFlags( ::extract_value
< sal_uInt8
>( nAlign
, 10, 6 ) );
1175 maProtection
.FillFromXF3( nTypeProt
);
1176 mnXclFont
= nReadFont
;
1177 mnXclNumFmt
= nReadNumFmt
;
1178 maAlignment
.FillFromXF4( nAlign
);
1179 maBorder
.FillFromXF3( nBorder
);
1180 maArea
.FillFromXF3( nArea
);
1183 void XclImpXF::ReadXF5( XclImpStream
& rStrm
)
1185 sal_uInt32 nArea
, nBorder
;
1186 sal_uInt16 nTypeProt
, nAlign
;
1187 mnXclFont
= rStrm
.ReaduInt16();
1188 mnXclNumFmt
= rStrm
.ReaduInt16();
1189 nTypeProt
= rStrm
.ReaduInt16();
1190 nAlign
= rStrm
.ReaduInt16();
1191 nArea
= rStrm
.ReaduInt32();
1192 nBorder
= rStrm
.ReaduInt32();
1194 // XF type/parent, attribute used flags
1195 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1196 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1197 SetUsedFlags( ::extract_value
< sal_uInt8
>( nAlign
, 10, 6 ) );
1200 maProtection
.FillFromXF3( nTypeProt
);
1201 maAlignment
.FillFromXF5( nAlign
);
1202 maBorder
.FillFromXF5( nBorder
, nArea
);
1203 maArea
.FillFromXF5( nArea
);
1206 void XclImpXF::ReadXF8( XclImpStream
& rStrm
)
1208 sal_uInt32 nBorder1
, nBorder2
;
1209 sal_uInt16 nTypeProt
, nAlign
, nMiscAttrib
, nArea
;
1210 mnXclFont
= rStrm
.ReaduInt16();
1211 mnXclNumFmt
= rStrm
.ReaduInt16();
1212 nTypeProt
= rStrm
.ReaduInt16();
1213 nAlign
= rStrm
.ReaduInt16();
1214 nMiscAttrib
= rStrm
.ReaduInt16();
1215 nBorder1
= rStrm
.ReaduInt32();
1216 nBorder2
= rStrm
.ReaduInt32( );
1217 nArea
= rStrm
.ReaduInt16();
1219 // XF type/parent, attribute used flags
1220 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1221 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1222 SetUsedFlags( ::extract_value
< sal_uInt8
>( nMiscAttrib
, 10, 6 ) );
1225 maProtection
.FillFromXF3( nTypeProt
);
1226 maAlignment
.FillFromXF8( nAlign
, nMiscAttrib
);
1227 maBorder
.FillFromXF8( nBorder1
, nBorder2
);
1228 maArea
.FillFromXF8( nBorder2
, nArea
);
1231 void XclImpXF::ReadXF( XclImpStream
& rStrm
)
1235 case EXC_BIFF2
: ReadXF2( rStrm
); break;
1236 case EXC_BIFF3
: ReadXF3( rStrm
); break;
1237 case EXC_BIFF4
: ReadXF4( rStrm
); break;
1238 case EXC_BIFF5
: ReadXF5( rStrm
); break;
1239 case EXC_BIFF8
: ReadXF8( rStrm
); break;
1240 default: DBG_ERROR_BIFF();
1244 const ScPatternAttr
& XclImpXF::CreatePattern( bool bSkipPoolDefs
)
1249 // create new pattern attribute set
1250 mpPattern
.reset( new ScPatternAttr( GetDoc().GetPool() ) );
1251 SfxItemSet
& rItemSet
= mpPattern
->GetItemSet();
1252 XclImpXF
* pParentXF
= IsCellXF() ? GetXFBuffer().GetXF( mnParent
) : nullptr;
1254 // parent cell style
1255 if( IsCellXF() && !mpStyleSheet
)
1257 mpStyleSheet
= GetXFBuffer().CreateStyleSheet( mnParent
);
1259 /* Enables mb***Used flags, if the formatting attributes differ from
1260 the passed XF record. In cell XFs Excel uses the cell attributes,
1261 if they differ from the parent style XF.
1262 ...or if the respective flag is not set in parent style XF. */
1266 mbProtUsed
= !pParentXF
->mbProtUsed
|| !(maProtection
== pParentXF
->maProtection
);
1268 mbFontUsed
= !pParentXF
->mbFontUsed
|| (mnXclFont
!= pParentXF
->mnXclFont
);
1270 mbFmtUsed
= !pParentXF
->mbFmtUsed
|| (mnXclNumFmt
!= pParentXF
->mnXclNumFmt
);
1272 mbAlignUsed
= !pParentXF
->mbAlignUsed
|| !(maAlignment
== pParentXF
->maAlignment
);
1274 mbBorderUsed
= !pParentXF
->mbBorderUsed
|| !(maBorder
== pParentXF
->maBorder
);
1276 mbAreaUsed
= !pParentXF
->mbAreaUsed
|| !(maArea
== pParentXF
->maArea
);
1282 maProtection
.FillToItemSet( rItemSet
, bSkipPoolDefs
);
1286 GetFontBuffer().FillToItemSet( rItemSet
, XclFontItemType::Cell
, mnXclFont
, bSkipPoolDefs
);
1291 GetNumFmtBuffer().FillToItemSet( rItemSet
, mnXclNumFmt
, bSkipPoolDefs
);
1292 // Trace occurrences of Windows date formats
1293 GetTracer().TraceDates( mnXclNumFmt
);
1298 maAlignment
.FillToItemSet( rItemSet
, GetFontBuffer().GetFont( mnXclFont
), bSkipPoolDefs
);
1303 maBorder
.FillToItemSet( rItemSet
, GetPalette(), bSkipPoolDefs
);
1304 GetTracer().TraceBorderLineStyle(maBorder
.mnLeftLine
> EXC_LINE_HAIR
||
1305 maBorder
.mnRightLine
> EXC_LINE_HAIR
|| maBorder
.mnTopLine
> EXC_LINE_HAIR
||
1306 maBorder
.mnBottomLine
> EXC_LINE_HAIR
);
1312 maArea
.FillToItemSet( rItemSet
, GetPalette(), bSkipPoolDefs
);
1313 GetTracer().TraceFillPattern(maArea
.mnPattern
!= EXC_PATT_NONE
&&
1314 maArea
.mnPattern
!= EXC_PATT_SOLID
);
1317 /* #i38709# Decide which rotation reference mode to use. If any outer
1318 border line of the cell is set (either explicitly or via cell style),
1319 and the cell contents are rotated, set rotation reference to bottom of
1320 cell. This causes the borders to be painted rotated with the text. */
1321 if( mbAlignUsed
|| mbBorderUsed
)
1323 SvxRotateMode eRotateMode
= SVX_ROTATE_MODE_STANDARD
;
1324 const XclImpCellAlign
* pAlign
= mbAlignUsed
? &maAlignment
: (pParentXF
? &pParentXF
->maAlignment
: nullptr);
1325 const XclImpCellBorder
* pBorder
= mbBorderUsed
? &maBorder
: (pParentXF
? &pParentXF
->maBorder
: nullptr);
1326 if( pAlign
&& pBorder
&& (0 < pAlign
->mnRotation
) && (pAlign
->mnRotation
<= 180) && pBorder
->HasAnyOuterBorder() )
1327 eRotateMode
= SVX_ROTATE_MODE_BOTTOM
;
1328 ScfTools::PutItem( rItemSet
, SvxRotateModeItem( eRotateMode
, ATTR_ROTATE_MODE
), bSkipPoolDefs
);
1331 // Excel's cell margins are different from Calc's default margins.
1332 SvxMarginItem
aItem(40, 40, 40, 40, ATTR_MARGIN
);
1333 ScfTools::PutItem(rItemSet
, aItem
, bSkipPoolDefs
);
1338 void XclImpXF::ApplyPatternToAttrVector(
1339 std::vector
<ScAttrEntry
>& rAttrs
, SCROW nRow1
, SCROW nRow2
, sal_uInt32 nForceScNumFmt
)
1341 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1343 ScPatternAttr
& rPat
= *mpPattern
;
1345 // insert into document
1346 ScDocument
& rDoc
= GetDoc();
1352 // Apply style sheet. Don't clear the direct formats.
1353 rPat
.SetStyleSheet(mpStyleSheet
, false);
1357 // When the cell format is not associated with any style, use the
1358 // 'Default' style. Some buggy XLS docs generated by apps other
1359 // than Excel (such as 1C) may not have any built-in styles at
1361 ScStyleSheetPool
* pStylePool
= rDoc
.GetStyleSheetPool();
1364 ScStyleSheet
* pStyleSheet
= static_cast<ScStyleSheet
*>(
1366 ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
));
1369 rPat
.SetStyleSheet(pStyleSheet
, false);
1375 if (nForceScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1377 ScPatternAttr
aNumPat(rDoc
.GetPool());
1378 GetNumFmtBuffer().FillScFmtToItemSet(aNumPat
.GetItemSet(), nForceScNumFmt
);
1379 rPat
.GetItemSet().Put(aNumPat
.GetItemSet());
1382 // Make sure we skip unnamed styles.
1383 if (!rPat
.GetStyleName())
1386 // Check for a gap between the last entry and this one.
1387 bool bHasGap
= false;
1388 if (rAttrs
.empty() && nRow1
> 0)
1389 // First attribute range doesn't start at row 0.
1392 if (!rAttrs
.empty() && rAttrs
.back().nEndRow
+ 1 < nRow1
)
1397 // Fill this gap with the default pattern.
1399 aEntry
.nEndRow
= nRow1
- 1;
1400 aEntry
.pPattern
= rDoc
.GetDefPattern();
1401 rAttrs
.push_back(aEntry
);
1405 aEntry
.nEndRow
= nRow2
;
1406 aEntry
.pPattern
= &rDoc
.GetPool()->Put(rPat
);
1407 rAttrs
.push_back(aEntry
);
1410 void XclImpXF::ApplyPattern(
1411 SCCOL nScCol1
, SCROW nScRow1
, SCCOL nScCol2
, SCROW nScRow2
,
1414 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1415 const ScPatternAttr
& rPattern
= CreatePattern();
1417 // insert into document
1418 ScDocument
& rDoc
= GetDoc();
1419 if( IsCellXF() && mpStyleSheet
)
1420 rDoc
.ApplyStyleAreaTab( nScCol1
, nScRow1
, nScCol2
, nScRow2
, nScTab
, *mpStyleSheet
);
1421 if( HasUsedFlags() )
1422 rDoc
.ApplyPatternAreaTab( nScCol1
, nScRow1
, nScCol2
, nScRow2
, nScTab
, rPattern
);
1426 /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot
& rRoot
,
1427 const ScAddress
& rScPos
, sal_uInt8 nFlags1
, sal_uInt8 nFlags2
, sal_uInt8 nFlags3
)
1429 /* Create an XF object and let it do the work. We will have access to its
1430 private members here. */
1431 XclImpXF
aXF( rRoot
);
1433 // no used flags available in BIFF2 (always true)
1434 aXF
.SetAllUsedFlags( true );
1436 // set the attributes
1437 aXF
.maProtection
.FillFromXF2( nFlags1
);
1438 aXF
.maAlignment
.FillFromXF2( nFlags3
);
1439 aXF
.maBorder
.FillFromXF2( nFlags3
);
1440 aXF
.maArea
.FillFromXF2( nFlags3
);
1441 aXF
.mnXclNumFmt
= ::extract_value
< sal_uInt16
>( nFlags2
, 0, 6 );
1442 aXF
.mnXclFont
= ::extract_value
< sal_uInt16
>( nFlags2
, 6, 2 );
1444 // write the attributes to the cell
1445 aXF
.ApplyPattern( rScPos
.Col(), rScPos
.Row(), rScPos
.Col(), rScPos
.Row(), rScPos
.Tab() );
1448 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags
)
1450 /* Notes about finding the mb***Used flags:
1451 - In cell XFs a *set* bit means a used attribute.
1452 - In style XFs a *cleared* bit means a used attribute.
1453 The mb***Used members always store true, if the attribute is used.
1454 The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1455 both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1457 mbProtUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_PROT
));
1458 mbFontUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_FONT
));
1459 mbFmtUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_VALFMT
));
1460 mbAlignUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_ALIGN
));
1461 mbBorderUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_BORDER
));
1462 mbAreaUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_AREA
));
1465 XclImpStyle::XclImpStyle( const XclImpRoot
& rRoot
) :
1466 XclImpRoot( rRoot
),
1467 mnXfId( EXC_XF_NOTFOUND
),
1468 mnBuiltinId( EXC_STYLE_USERDEF
),
1469 mnLevel( EXC_STYLE_NOLEVEL
),
1473 mpStyleSheet( nullptr )
1477 void XclImpStyle::ReadStyle( XclImpStream
& rStrm
)
1479 OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3
);
1481 sal_uInt16 nXFIndex
;
1482 nXFIndex
= rStrm
.ReaduInt16();
1483 mnXfId
= nXFIndex
& EXC_STYLE_XFMASK
;
1484 mbBuiltin
= ::get_flag( nXFIndex
, EXC_STYLE_BUILTIN
);
1488 mnBuiltinId
= rStrm
.ReaduInt8();
1489 mnLevel
= rStrm
.ReaduInt8();
1493 maName
= (GetBiff() <= EXC_BIFF5
) ? rStrm
.ReadByteString( false ) : rStrm
.ReadUniString();
1494 // #i103281# check if this is a new built-in style introduced in XL2007
1495 if( (GetBiff() == EXC_BIFF8
) && (rStrm
.GetNextRecId() == EXC_ID_STYLEEXT
) && rStrm
.StartNextRecord() )
1497 sal_uInt8 nExtFlags
;
1499 nExtFlags
= rStrm
.ReaduInt8();
1500 mbBuiltin
= ::get_flag( nExtFlags
, EXC_STYLEEXT_BUILTIN
);
1501 mbCustom
= ::get_flag( nExtFlags
, EXC_STYLEEXT_CUSTOM
);
1502 mbHidden
= ::get_flag( nExtFlags
, EXC_STYLEEXT_HIDDEN
);
1505 rStrm
.Ignore( 1 ); // category
1506 mnBuiltinId
= rStrm
.ReaduInt8();
1507 mnLevel
= rStrm
.ReaduInt8();
1513 ScStyleSheet
* XclImpStyle::CreateStyleSheet()
1515 // #i1624# #i1768# ignore unnamed user styles
1516 if( !mpStyleSheet
&& (!maFinalName
.isEmpty()) )
1518 bool bCreatePattern
= false;
1519 XclImpXF
* pXF
= GetXFBuffer().GetXF( mnXfId
);
1521 bool bDefStyle
= mbBuiltin
&& (mnBuiltinId
== EXC_STYLE_NORMAL
);
1524 // set all flags to true to get all items in XclImpXF::CreatePattern()
1525 if( pXF
) pXF
->SetAllUsedFlags( true );
1526 // use existing "Default" style sheet
1527 mpStyleSheet
= static_cast< ScStyleSheet
* >( GetStyleSheetPool().Find(
1528 ScResId( STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
) );
1529 OSL_ENSURE( mpStyleSheet
, "XclImpStyle::CreateStyleSheet - Default style not found" );
1530 bCreatePattern
= true;
1534 /* #i103281# do not create another style sheet of the same name,
1535 if it exists already. This is needed to prevent that styles
1536 pasted from clipboard get duplicated over and over. */
1537 mpStyleSheet
= static_cast< ScStyleSheet
* >( GetStyleSheetPool().Find( maFinalName
, SfxStyleFamily::Para
) );
1540 mpStyleSheet
= &static_cast< ScStyleSheet
& >( GetStyleSheetPool().Make( maFinalName
, SfxStyleFamily::Para
, SfxStyleSearchBits::UserDefined
) );
1541 bCreatePattern
= true;
1545 // bDefStyle==true omits default pool items in CreatePattern()
1546 if( bCreatePattern
&& mpStyleSheet
&& pXF
)
1547 mpStyleSheet
->GetItemSet().Put( pXF
->CreatePattern( bDefStyle
).GetItemSet() );
1549 return mpStyleSheet
;
1552 void XclImpStyle::CreateUserStyle( const OUString
& rFinalName
)
1554 maFinalName
= rFinalName
;
1555 if( !IsBuiltin() || mbCustom
)
1559 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot
& rRoot
) :
1564 void XclImpXFBuffer::Initialize()
1567 maBuiltinStyles
.clear();
1568 maUserStyles
.clear();
1569 maStylesByXf
.clear();
1572 void XclImpXFBuffer::ReadXF( XclImpStream
& rStrm
)
1574 std::unique_ptr
<XclImpXF
> xXF
= std::make_unique
<XclImpXF
>(GetRoot());
1576 maXFList
.emplace_back(std::move(xXF
));
1579 void XclImpXFBuffer::ReadStyle( XclImpStream
& rStrm
)
1581 std::unique_ptr
<XclImpStyle
> xStyle(std::make_unique
<XclImpStyle
>(GetRoot()));
1582 xStyle
->ReadStyle(rStrm
);
1583 XclImpStyleList
& rStyleList
= (xStyle
->IsBuiltin() ? maBuiltinStyles
: maUserStyles
);
1584 rStyleList
.emplace_back(std::move(xStyle
));
1585 XclImpStyle
* pStyle
= rStyleList
.back().get();
1586 OSL_ENSURE( maStylesByXf
.count( pStyle
->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1587 maStylesByXf
[ pStyle
->GetXfId() ] = pStyle
;
1590 sal_uInt16
XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex
) const
1592 const XclImpXF
* pXF
= GetXF( nXFIndex
);
1593 return pXF
? pXF
->GetFontIndex() : EXC_FONT_NOTFOUND
;
1596 const XclImpFont
* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex
) const
1598 return GetFontBuffer().GetFont( GetFontIndex( nXFIndex
) );
1603 /** Functor for case-insensitive string comparison, usable in maps etc. */
1604 struct IgnoreCaseCompare
1606 bool operator()( const OUString
& rName1
, std::u16string_view rName2
) const
1607 { return rName1
.compareToIgnoreAsciiCase( rName2
) < 0; }
1612 void XclImpXFBuffer::CreateUserStyles()
1614 // calculate final names of all styles
1615 std::map
< OUString
, XclImpStyle
*, IgnoreCaseCompare
> aCellStyles
;
1616 std::vector
< XclImpStyle
* > aConflictNameStyles
;
1618 /* First, reserve style names that are built-in in Calc. This causes that
1619 imported cell styles get different unused names and thus do not try to
1620 overwrite these built-in styles. For BIFF4 workbooks (which contain a
1621 separate list of cell styles per sheet), reserve all existing styles if
1622 current sheet is not the first sheet (this styles buffer will be
1623 initialized again for every new sheet). This will create unique names
1624 for styles in different sheets with the same name. Assuming that the
1625 BIFF4W import filter is never used to import from clipboard... */
1626 bool bReserveAll
= (GetBiff() == EXC_BIFF4
) && (GetCurrScTab() > 0);
1627 SfxStyleSheetIterator
aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para
);
1628 OUString aStandardName
= ScResId( STR_STYLENAME_STANDARD
);
1629 for( SfxStyleSheetBase
* pStyleSheet
= aStyleIter
.First(); pStyleSheet
; pStyleSheet
= aStyleIter
.Next() )
1630 if( (pStyleSheet
->GetName() != aStandardName
) && (bReserveAll
|| !pStyleSheet
->IsUserDefined()) )
1631 if( aCellStyles
.count( pStyleSheet
->GetName() ) == 0 )
1632 aCellStyles
[ pStyleSheet
->GetName() ] = nullptr;
1634 /* Calculate names of built-in styles. Store styles with reserved names
1635 in the aConflictNameStyles list. */
1636 for( const auto& rxStyle
: maBuiltinStyles
)
1638 OUString aStyleName
= XclTools::GetBuiltInStyleName( rxStyle
->GetBuiltinId(), rxStyle
->GetName(), rxStyle
->GetLevel() );
1639 OSL_ENSURE( bReserveAll
|| (aCellStyles
.count( aStyleName
) == 0),
1640 "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1641 if( aCellStyles
.count( aStyleName
) > 0 )
1642 aConflictNameStyles
.push_back( rxStyle
.get() );
1644 aCellStyles
[ aStyleName
] = rxStyle
.get();
1647 /* Calculate names of user defined styles. Store styles with reserved
1648 names in the aConflictNameStyles list. */
1649 for( const auto& rxStyle
: maUserStyles
)
1651 // #i1624# #i1768# ignore unnamed user styles
1652 if( !rxStyle
->GetName().isEmpty() )
1654 if( aCellStyles
.count( rxStyle
->GetName() ) > 0 )
1655 aConflictNameStyles
.push_back( rxStyle
.get() );
1657 aCellStyles
[ rxStyle
->GetName() ] = rxStyle
.get();
1661 // find unused names for all styles with conflicting names
1662 for( XclImpStyle
* pStyle
: aConflictNameStyles
)
1664 OUString aUnusedName
;
1665 sal_Int32 nIndex
= 0;
1668 aUnusedName
= pStyle
->GetName() + " " + OUString::number( ++nIndex
);
1670 while( aCellStyles
.count( aUnusedName
) > 0 );
1671 aCellStyles
[ aUnusedName
] = pStyle
;
1674 // set final names and create user-defined and modified built-in cell styles
1675 for( auto& [rStyleName
, rpStyle
] : aCellStyles
)
1677 rpStyle
->CreateUserStyle( rStyleName
);
1680 ScStyleSheet
* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex
)
1682 XclImpStyleMap::iterator aIt
= maStylesByXf
.find( nXFIndex
);
1683 return (aIt
== maStylesByXf
.end()) ? nullptr : aIt
->second
->CreateStyleSheet();
1686 // Buffer for XF indexes in cells =============================================
1688 bool XclImpXFRange::Expand( SCROW nScRow
, const XclImpXFIndex
& rXFIndex
)
1690 if( maXFIndex
!= rXFIndex
)
1693 if( mnScRow2
+ 1 == nScRow
)
1698 if( mnScRow1
> 0 && (mnScRow1
- 1 == nScRow
) )
1707 bool XclImpXFRange::Expand( const XclImpXFRange
& rNextRange
)
1709 OSL_ENSURE( mnScRow2
< rNextRange
.mnScRow1
, "XclImpXFRange::Expand - rows out of order" );
1710 if( (maXFIndex
== rNextRange
.maXFIndex
) && (mnScRow2
+ 1 == rNextRange
.mnScRow1
) )
1712 mnScRow2
= rNextRange
.mnScRow2
;
1718 void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex
& rXFIndex
, const XclImpRoot
& rRoot
)
1720 // List should be empty when inserting the default column format.
1721 // Later explicit SetXF() calls will break up this range.
1722 OSL_ENSURE( maIndexList
.empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
1724 // insert a complete row range with one insert.
1725 maIndexList
.push_back( std::make_unique
<XclImpXFRange
>( 0, rRoot
.GetDoc().MaxRow(), rXFIndex
) );
1728 void XclImpXFRangeColumn::SetXF( SCROW nScRow
, const XclImpXFIndex
& rXFIndex
)
1730 XclImpXFRange
* pPrevRange
;
1731 XclImpXFRange
* pNextRange
;
1732 sal_uLong nNextIndex
;
1734 Find( pPrevRange
, pNextRange
, nNextIndex
, nScRow
);
1737 // try to overwrite XF (if row is contained in) or try to expand range
1740 if( pPrevRange
->Contains( nScRow
) ) // overwrite old XF
1742 if( rXFIndex
== pPrevRange
->maXFIndex
)
1745 SCROW nFirstScRow
= pPrevRange
->mnScRow1
;
1746 SCROW nLastScRow
= pPrevRange
->mnScRow2
;
1747 sal_uLong nIndex
= nNextIndex
- 1;
1748 XclImpXFRange
* pThisRange
= pPrevRange
;
1749 pPrevRange
= (nIndex
> 0 && nIndex
<= maIndexList
.size()) ? maIndexList
[ nIndex
- 1 ].get() : nullptr;
1751 if( nFirstScRow
== nLastScRow
) // replace solely XF
1753 pThisRange
->maXFIndex
= rXFIndex
;
1754 TryConcatPrev( nNextIndex
); // try to concat. next with this
1755 TryConcatPrev( nIndex
); // try to concat. this with previous
1757 else if( nFirstScRow
== nScRow
) // replace first XF
1759 ++(pThisRange
->mnScRow1
);
1760 // try to concatenate with previous of this
1761 if( !pPrevRange
|| !pPrevRange
->Expand( nScRow
, rXFIndex
) )
1762 Insert( new XclImpXFRange( nScRow
, rXFIndex
), nIndex
);
1764 else if( nLastScRow
== nScRow
) // replace last XF
1766 --(pThisRange
->mnScRow2
);
1767 if( !pNextRange
|| !pNextRange
->Expand( nScRow
, rXFIndex
) )
1768 Insert( new XclImpXFRange( nScRow
, rXFIndex
), nNextIndex
);
1770 else // insert in the middle of the range
1772 pThisRange
->mnScRow1
= nScRow
+ 1;
1773 // List::Insert() moves entries towards end of list, so insert twice at nIndex
1774 Insert( new XclImpXFRange( nScRow
, rXFIndex
), nIndex
);
1775 Insert( new XclImpXFRange( nFirstScRow
, nScRow
- 1, pThisRange
->maXFIndex
), nIndex
);
1779 else if( pPrevRange
->Expand( nScRow
, rXFIndex
) ) // try to expand
1781 TryConcatPrev( nNextIndex
); // try to concatenate next with expanded
1786 // try to expand next range
1787 if( pNextRange
&& pNextRange
->Expand( nScRow
, rXFIndex
) )
1791 Insert( new XclImpXFRange( nScRow
, rXFIndex
), nNextIndex
);
1794 void XclImpXFRangeColumn::Insert(XclImpXFRange
* pXFRange
, sal_uLong nIndex
)
1796 maIndexList
.insert( maIndexList
.begin() + nIndex
, std::unique_ptr
<XclImpXFRange
>(pXFRange
) );
1799 void XclImpXFRangeColumn::Find(
1800 XclImpXFRange
*& rpPrevRange
, XclImpXFRange
*& rpNextRange
,
1801 sal_uLong
& rnNextIndex
, SCROW nScRow
)
1804 // test whether list is empty
1805 if( maIndexList
.empty() )
1807 rpPrevRange
= rpNextRange
= nullptr;
1812 rpPrevRange
= maIndexList
.front().get();
1813 rpNextRange
= maIndexList
.back().get();
1815 // test whether row is at end of list (contained in or behind last range)
1816 // rpPrevRange will contain a possible existing row
1817 if( rpNextRange
->mnScRow1
<= nScRow
)
1819 rpPrevRange
= rpNextRange
;
1820 rpNextRange
= nullptr;
1821 rnNextIndex
= maIndexList
.size();
1825 // test whether row is at beginning of list (really before first range)
1826 if( nScRow
< rpPrevRange
->mnScRow1
)
1828 rpNextRange
= rpPrevRange
;
1829 rpPrevRange
= nullptr;
1834 // loop: find range entries before and after new row
1835 // break the loop if there is no more range between first and last -or-
1836 // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
1837 sal_uLong nPrevIndex
= 0;
1838 sal_uLong nMidIndex
;
1839 rnNextIndex
= maIndexList
.size() - 1;
1840 XclImpXFRange
* pMidRange
;
1841 while( ((rnNextIndex
- nPrevIndex
) > 1) && (rpPrevRange
->mnScRow2
< nScRow
) )
1843 nMidIndex
= (nPrevIndex
+ rnNextIndex
) / 2;
1844 pMidRange
= maIndexList
[nMidIndex
].get();
1845 OSL_ENSURE( pMidRange
, "XclImpXFRangeColumn::Find - missing XF index range" );
1846 if( nScRow
< pMidRange
->mnScRow1
) // row is really before pMidRange
1848 rpNextRange
= pMidRange
;
1849 rnNextIndex
= nMidIndex
;
1851 else // row is in or after pMidRange
1853 rpPrevRange
= pMidRange
;
1854 nPrevIndex
= nMidIndex
;
1858 // find next rpNextRange if rpPrevRange contains nScRow
1859 if( nScRow
<= rpPrevRange
->mnScRow2
)
1861 rnNextIndex
= nPrevIndex
+ 1;
1862 rpNextRange
= maIndexList
[rnNextIndex
].get();
1866 void XclImpXFRangeColumn::TryConcatPrev( sal_uLong nIndex
)
1868 if( !nIndex
|| nIndex
>= maIndexList
.size() )
1871 XclImpXFRange
& prevRange
= *maIndexList
[ nIndex
- 1 ];
1872 XclImpXFRange
& nextRange
= *maIndexList
[ nIndex
];
1874 if( prevRange
.Expand( nextRange
) )
1875 maIndexList
.erase( maIndexList
.begin() + nIndex
);
1878 XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot
& rRoot
) :
1883 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1887 void XclImpXFRangeBuffer::Initialize()
1890 maHyperlinks
.clear();
1891 maMergeList
.RemoveAll();
1894 void XclImpXFRangeBuffer::SetXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
, XclImpXFInsertMode eMode
)
1896 SCCOL nScCol
= rScPos
.Col();
1897 SCROW nScRow
= rScPos
.Row();
1900 size_t nIndex
= static_cast< size_t >( nScCol
);
1901 if( maColumns
.size() <= nIndex
)
1902 maColumns
.resize( nIndex
+ 1 );
1903 if( !maColumns
[ nIndex
] )
1904 maColumns
[ nIndex
] = std::make_shared
<XclImpXFRangeColumn
>();
1905 // remember all Boolean cells, they will get 'Standard' number format
1906 maColumns
[ nIndex
]->SetXF( nScRow
, XclImpXFIndex( nXFIndex
, eMode
== xlXFModeBoolCell
) );
1908 // set "center across selection" and "fill" attribute for all following empty cells
1909 // ignore it on row default XFs
1910 if( eMode
== xlXFModeRow
)
1913 const XclImpXF
* pXF
= GetXFBuffer().GetXF( nXFIndex
);
1914 if( pXF
&& ((pXF
->GetHorAlign() == EXC_XF_HOR_CENTER_AS
) || (pXF
->GetHorAlign() == EXC_XF_HOR_FILL
)) )
1916 // expand last merged range if this attribute is set repeatedly
1917 ScRange
* pRange
= maMergeList
.empty() ? nullptr : &maMergeList
.back();
1918 if (pRange
&& (pRange
->aEnd
.Row() == nScRow
) && (pRange
->aEnd
.Col() + 1 == nScCol
) && (eMode
== xlXFModeBlank
))
1919 pRange
->aEnd
.IncCol();
1920 else if( eMode
!= xlXFModeBlank
) // do not merge empty cells
1921 maMergeList
.push_back( ScRange( nScCol
, nScRow
, 0 ) );
1925 void XclImpXFRangeBuffer::SetXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1927 SetXF( rScPos
, nXFIndex
, xlXFModeCell
);
1930 void XclImpXFRangeBuffer::SetBlankXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1932 SetXF( rScPos
, nXFIndex
, xlXFModeBlank
);
1935 void XclImpXFRangeBuffer::SetBoolXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1937 SetXF( rScPos
, nXFIndex
, xlXFModeBoolCell
);
1940 void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow
, sal_uInt16 nXFIndex
)
1942 for( SCCOL nScCol
= 0; nScCol
<= GetDoc().MaxCol(); ++nScCol
)
1943 SetXF( ScAddress( nScCol
, nScRow
, 0 ), nXFIndex
, xlXFModeRow
);
1946 void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol
, sal_uInt16 nXFIndex
)
1948 // our array should not have values when creating the default column format.
1949 size_t nIndex
= static_cast< size_t >( nScCol
);
1950 if( maColumns
.size() <= nIndex
)
1951 maColumns
.resize( nIndex
+ 1 );
1952 OSL_ENSURE( !maColumns
[ nIndex
], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
1953 maColumns
[ nIndex
] = std::make_shared
<XclImpXFRangeColumn
>();
1954 maColumns
[ nIndex
]->SetDefaultXF( XclImpXFIndex( nXFIndex
), GetRoot());
1957 void XclImpXFRangeBuffer::SetBorderLine( const ScRange
& rRange
, SCTAB nScTab
, SvxBoxItemLine nLine
)
1959 SCCOL nFromScCol
= (nLine
== SvxBoxItemLine::RIGHT
) ? rRange
.aEnd
.Col() : rRange
.aStart
.Col();
1960 SCROW nFromScRow
= (nLine
== SvxBoxItemLine::BOTTOM
) ? rRange
.aEnd
.Row() : rRange
.aStart
.Row();
1961 ScDocument
& rDoc
= GetDoc();
1963 const SvxBoxItem
* pFromItem
=
1964 rDoc
.GetAttr( nFromScCol
, nFromScRow
, nScTab
, ATTR_BORDER
);
1965 const SvxBoxItem
* pToItem
=
1966 rDoc
.GetAttr( rRange
.aStart
.Col(), rRange
.aStart
.Row(), nScTab
, ATTR_BORDER
);
1968 SvxBoxItem
aNewItem( *pToItem
);
1969 aNewItem
.SetLine( pFromItem
->GetLine( nLine
), nLine
);
1970 rDoc
.ApplyAttr( rRange
.aStart
.Col(), rRange
.aStart
.Row(), nScTab
, aNewItem
);
1973 void XclImpXFRangeBuffer::SetHyperlink( const XclRange
& rXclRange
, const OUString
& rUrl
)
1975 maHyperlinks
.emplace_back( rXclRange
, rUrl
);
1978 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1
, SCROW nScRow1
, SCCOL nScCol2
, SCROW nScRow2
)
1980 if( (nScCol1
< nScCol2
) || (nScRow1
< nScRow2
) )
1981 maMergeList
.push_back( ScRange( nScCol1
, nScRow1
, 0, nScCol2
, nScRow2
, 0 ) );
1984 void XclImpXFRangeBuffer::Finalize()
1986 ScDocumentImport
& rDocImport
= GetDocImport();
1987 ScDocument
& rDoc
= rDocImport
.getDoc();
1988 SCTAB nScTab
= GetCurrScTab();
1991 XclImpXFBuffer
& rXFBuffer
= GetXFBuffer();
1992 ScDocumentImport::Attrs aPendingAttrParam
;
1993 SCCOL pendingColStart
= -1;
1994 SCCOL pendingColEnd
= -1;
1996 for( const auto& rxColumn
: maColumns
)
1998 // apply all cell styles of an existing column
2001 XclImpXFRangeColumn
& rColumn
= *rxColumn
;
2002 std::vector
<ScAttrEntry
> aAttrs
;
2003 aAttrs
.reserve(rColumn
.end() - rColumn
.begin());
2005 for (const auto& rxStyle
: rColumn
)
2007 XclImpXFRange
& rStyle
= *rxStyle
;
2008 const XclImpXFIndex
& rXFIndex
= rStyle
.maXFIndex
;
2009 XclImpXF
* pXF
= rXFBuffer
.GetXF( rXFIndex
.GetXFIndex() );
2013 sal_uInt32 nForceScNumFmt
= rXFIndex
.IsBoolCell() ?
2014 GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND
;
2016 pXF
->ApplyPatternToAttrVector(aAttrs
, rStyle
.mnScRow1
, rStyle
.mnScRow2
, nForceScNumFmt
);
2019 if (aAttrs
.empty() || aAttrs
.back().nEndRow
!= rDoc
.MaxRow())
2022 aEntry
.nEndRow
= rDoc
.MaxRow();
2023 aEntry
.pPattern
= rDoc
.GetDefPattern();
2024 aAttrs
.push_back(aEntry
);
2027 aAttrs
.shrink_to_fit();
2028 assert(aAttrs
.size() > 0);
2029 ScDocumentImport::Attrs aAttrParam
;
2030 aAttrParam
.mvData
.swap(aAttrs
);
2031 aAttrParam
.mbLatinNumFmtOnly
= false; // when unsure, set it to false.
2033 // Compress setting the attributes, set the same set in one call.
2034 if( pendingColStart
!= -1 && pendingColEnd
== nScCol
- 1 && aAttrParam
== aPendingAttrParam
)
2038 if( pendingColStart
!= -1 )
2039 rDocImport
.setAttrEntries(nScTab
, pendingColStart
, pendingColEnd
, std::move(aPendingAttrParam
));
2040 pendingColStart
= pendingColEnd
= nScCol
;
2041 aPendingAttrParam
= std::move( aAttrParam
);
2046 if( pendingColStart
!= -1 )
2047 rDocImport
.setAttrEntries(nScTab
, pendingColStart
, pendingColEnd
, std::move(aPendingAttrParam
));
2049 // insert hyperlink cells
2050 for( const auto& [rXclRange
, rUrl
] : maHyperlinks
)
2051 XclImpHyperlink::InsertUrl( GetRoot(), rXclRange
, rUrl
);
2053 // apply cell merging
2054 for ( size_t i
= 0, nRange
= maMergeList
.size(); i
< nRange
; ++i
)
2056 const ScRange
& rRange
= maMergeList
[ i
];
2057 const ScAddress
& rStart
= rRange
.aStart
;
2058 const ScAddress
& rEnd
= rRange
.aEnd
;
2059 bool bMultiCol
= rStart
.Col() != rEnd
.Col();
2060 bool bMultiRow
= rStart
.Row() != rEnd
.Row();
2061 // set correct right border
2063 SetBorderLine( rRange
, nScTab
, SvxBoxItemLine::RIGHT
);
2064 // set correct lower border
2066 SetBorderLine( rRange
, nScTab
, SvxBoxItemLine::BOTTOM
);
2068 if( bMultiCol
|| bMultiRow
)
2069 rDoc
.DoMerge( nScTab
, rStart
.Col(), rStart
.Row(), rEnd
.Col(), rEnd
.Row() );
2070 // #i93609# merged range in a single row: test if manual row height is needed
2073 bool bTextWrap
= rDoc
.GetAttr( rStart
, ATTR_LINEBREAK
)->GetValue();
2074 if( !bTextWrap
&& (rDoc
.GetCellType( rStart
) == CELLTYPE_EDIT
) )
2075 if (const EditTextObject
* pEditObj
= rDoc
.GetEditText(rStart
))
2076 bTextWrap
= pEditObj
->GetParagraphCount() > 1;
2078 GetOldRoot().pColRowBuff
->SetManualRowHeight( rStart
.Row() );
2083 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */