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>
57 #include <patattr.hxx>
58 #include <stlpool.hxx>
59 #include <stlsheet.hxx>
60 #include <globstr.hrc>
61 #include <scresid.hxx>
62 #include <attarray.hxx>
63 #include <xladdress.hxx>
64 #include <xlcontent.hxx>
65 #include <xltracer.hxx>
66 #include <xltools.hxx>
67 #include <xistream.hxx>
68 #include <xicontent.hxx>
71 #include <colrowst.hxx>
73 #include <string_view>
76 #include <cppuhelper/implbase.hxx>
77 #include <com/sun/star/container/XIndexAccess.hpp>
78 #include <com/sun/star/beans/XPropertySet.hpp>
79 #include <com/sun/star/frame/XModel.hpp>
80 #include <svl/numformat.hxx>
81 #include <o3tl/string_view.hxx>
84 using namespace ::com::sun::star
;
86 typedef ::cppu::WeakImplHelper
< container::XIndexAccess
> XIndexAccess_BASE
;
87 typedef ::std::vector
< Color
> ColorVec
;
91 class PaletteIndex
: public XIndexAccess_BASE
94 explicit PaletteIndex( ColorVec
&& rColorTable
) : maColor( std::move(rColorTable
) ) {}
96 // Methods XIndexAccess
97 virtual ::sal_Int32 SAL_CALL
getCount() override
99 return maColor
.size();
102 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) override
104 //--Index; // apparently the palette is already 1 based
105 return uno::Any( sal_Int32( maColor
[ Index
] ) );
108 // Methods XElementAccess
109 virtual uno::Type SAL_CALL
getElementType() override
111 return ::cppu::UnoType
<sal_Int32
>::get();
113 virtual sal_Bool SAL_CALL
hasElements() override
115 return (!maColor
.empty());
125 XclImpPalette::ExportPalette()
127 ScDocShell
* pDocShell
= mrRoot
.GetDocShell();
131 // copy values in color palette
132 sal_Int16 nColors
= maColorTable
.size();
134 aColors
.resize( nColors
);
135 for( sal_uInt16 nIndex
= 0; nIndex
< nColors
; ++nIndex
)
136 aColors
[ nIndex
] = GetColor( nIndex
);
138 ScModelObj
* pModel
= pDocShell
->GetModel();
141 uno::Reference
< container::XIndexAccess
> xIndex( new PaletteIndex( std::move(aColors
) ) );
142 pModel
->setPropertyValue( u
"ColorPalette"_ustr
, uno::Any( xIndex
) );
146 // PALETTE record - color information =========================================
148 XclImpPalette::XclImpPalette( const XclImpRoot
& rRoot
) :
149 XclDefaultPalette( rRoot
), mrRoot( rRoot
)
153 void XclImpPalette::Initialize()
155 maColorTable
.clear();
158 Color
XclImpPalette::GetColor( sal_uInt16 nXclIndex
) const
160 if( nXclIndex
>= EXC_COLOR_USEROFFSET
)
162 sal_uInt32 nIx
= nXclIndex
- EXC_COLOR_USEROFFSET
;
163 if( nIx
< maColorTable
.size() )
164 return maColorTable
[ nIx
];
166 return GetDefColor( nXclIndex
);
169 void XclImpPalette::ReadPalette( XclImpStream
& rStrm
)
172 nCount
= rStrm
.ReaduInt16();
174 const size_t nMinRecordSize
= 4;
175 const size_t nMaxRecords
= rStrm
.GetRecLeft() / nMinRecordSize
;
176 if (nCount
> nMaxRecords
)
178 SAL_WARN("sc", "Parsing error: " << nMaxRecords
<<
179 " max possible entries, but " << nCount
<< " claimed, truncating");
180 nCount
= nMaxRecords
;
183 maColorTable
.resize( nCount
);
185 for( sal_uInt16 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
188 maColorTable
[ nIndex
] = aColor
;
193 // FONT record - font information =============================================
194 XclImpFont::XclImpFont( const XclImpRoot
& rRoot
) :
196 mbHasCharSet( false ),
201 SetAllUsedFlags( false );
204 XclImpFont::XclImpFont( const XclImpRoot
& rRoot
, const XclFontData
& rFontData
) :
207 SetFontData( rFontData
, false );
210 void XclImpFont::SetAllUsedFlags( bool bUsed
)
212 mbFontNameUsed
= mbHeightUsed
= mbColorUsed
= mbWeightUsed
= mbEscapemUsed
=
213 mbUnderlUsed
= mbItalicUsed
= mbStrikeUsed
= mbOutlineUsed
= mbShadowUsed
= bUsed
;
216 void XclImpFont::SetFontData( const XclFontData
& rFontData
, bool bHasCharSet
)
219 mbHasCharSet
= bHasCharSet
;
220 if( !maData
.maStyle
.isEmpty() )
222 if( ScDocShell
* pDocShell
= GetDocShell() )
224 if( const SvxFontListItem
* pInfoItem
= static_cast< const SvxFontListItem
* >(
225 pDocShell
->GetItem( SID_ATTR_CHAR_FONTLIST
) ) )
227 if( const FontList
* pFontList
= pInfoItem
->GetFontList() )
229 FontMetric
aFontMetric( pFontList
->Get( maData
.maName
, maData
.maStyle
) );
230 maData
.SetScWeight( aFontMetric
.GetWeight() );
231 maData
.SetScPosture( aFontMetric
.GetItalic() );
235 maData
.maStyle
.clear();
238 SetAllUsedFlags( true );
241 rtl_TextEncoding
XclImpFont::GetFontEncoding() const
243 // #i63105# use text encoding from FONT record
244 // #i67768# BIFF2-BIFF4 FONT records do not contain character set
245 rtl_TextEncoding eFontEnc
= mbHasCharSet
? maData
.GetFontEncoding() : GetTextEncoding();
246 return (eFontEnc
== RTL_TEXTENCODING_DONTKNOW
) ? GetTextEncoding() : eFontEnc
;
249 void XclImpFont::ReadFont( XclImpStream
& rStrm
)
254 ReadFontData2( rStrm
);
255 ReadFontName2( rStrm
);
259 ReadFontData2( rStrm
);
260 ReadFontColor( rStrm
);
261 ReadFontName2( rStrm
);
264 ReadFontData5( rStrm
);
265 ReadFontName2( rStrm
);
268 ReadFontData5( rStrm
);
269 ReadFontName8( rStrm
);
276 SetAllUsedFlags( true );
279 void XclImpFont::ReadEfont( XclImpStream
& rStrm
)
281 ReadFontColor( rStrm
);
284 void XclImpFont::ReadCFFontBlock( XclImpStream
& rStrm
)
286 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8
);
287 if( GetBiff() != EXC_BIFF8
)
291 sal_uInt32 nHeight
= rStrm
.ReaduInt32();
292 sal_uInt32 nStyle
= rStrm
.ReaduInt32();
293 sal_uInt16 nWeight
= rStrm
.ReaduInt16();
294 rStrm
.Ignore( 2 ); //nEscapem
295 sal_uInt8 nUnderl
= rStrm
.ReaduInt8();
297 sal_uInt32 nColor
= rStrm
.ReaduInt32();
299 sal_uInt32 nFontFlags1
= rStrm
.ReaduInt32();
300 rStrm
.Ignore( 4 ); //nFontFlags2
301 sal_uInt32 nFontFlags3
= rStrm
.ReaduInt32();
304 if( (mbHeightUsed
= (nHeight
<= 0x7FFF)) )
305 maData
.mnHeight
= static_cast< sal_uInt16
>( nHeight
);
306 if( (mbWeightUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STYLE
) && (nWeight
< 0x7FFF)) )
307 maData
.mnWeight
= nWeight
;
308 if( (mbItalicUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STYLE
)) )
309 maData
.mbItalic
= ::get_flag( nStyle
, EXC_CF_FONT_STYLE
);
310 if( (mbUnderlUsed
= !::get_flag( nFontFlags3
, EXC_CF_FONT_UNDERL
) && (nUnderl
<= 0x7F)) )
311 maData
.mnUnderline
= nUnderl
;
312 if( (mbColorUsed
= (nColor
<= 0x7FFF)) )
313 maData
.maComplexColor
.setColor(GetPalette().GetColor(sal_uInt16(nColor
)));
314 if( (mbStrikeUsed
= !::get_flag( nFontFlags1
, EXC_CF_FONT_STRIKEOUT
)) )
315 maData
.mbStrikeout
= ::get_flag( nStyle
, EXC_CF_FONT_STRIKEOUT
);
318 void XclImpFont::FillToItemSet( SfxItemSet
& rItemSet
, XclFontItemType eType
, bool bSkipPoolDefs
) const
320 // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
321 bool bEE
= eType
!= XclFontItemType::Cell
;
323 // item = the item to put into the item set
324 // sc_which = the Calc Which-ID of the item
325 // ee_which = the edit engine Which-ID of the item
326 #define PUTITEM( item, sc_which, ee_which ) \
327 ScfTools::PutItem( rItemSet, item, (bEE ? (static_cast<sal_uInt16>(ee_which)) : (sc_which)), bSkipPoolDefs )
332 rtl_TextEncoding eFontEnc
= maData
.GetFontEncoding();
333 rtl_TextEncoding eTempTextEnc
= (bEE
&& (eFontEnc
== GetTextEncoding())) ?
334 ScfTools::GetSystemTextEncoding() : eFontEnc
;
336 //add corresponding pitch for FontFamily
337 FontPitch ePitch
= PITCH_DONTKNOW
;
338 FontFamily eFtFamily
= maData
.GetScFamily( GetTextEncoding() );
339 switch( eFtFamily
) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx
341 case FAMILY_ROMAN
: ePitch
= PITCH_VARIABLE
; break;
342 case FAMILY_SWISS
: ePitch
= PITCH_VARIABLE
; break;
343 case FAMILY_MODERN
: ePitch
= PITCH_FIXED
; break;
346 SvxFontItem
aFontItem( eFtFamily
, maData
.maName
, OUString(), ePitch
, eTempTextEnc
, ATTR_FONT
);
348 // set only for valid script types
350 PUTITEM( aFontItem
, ATTR_FONT
, EE_CHAR_FONTINFO
);
352 PUTITEM( aFontItem
, ATTR_CJK_FONT
, EE_CHAR_FONTINFO_CJK
);
354 PUTITEM( aFontItem
, ATTR_CTL_FONT
, EE_CHAR_FONTINFO_CTL
);
357 // Font height (for all script types)
360 sal_Int32 nHeight
= maData
.mnHeight
;
361 if( bEE
&& (eType
!= XclFontItemType::HeaderFooter
) ) // do not convert header/footer height
362 nHeight
= convertTwipToMm100(nHeight
);
364 SvxFontHeightItem
aHeightItem( nHeight
, 100, ATTR_FONT_HEIGHT
);
365 PUTITEM( aHeightItem
, ATTR_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT
);
366 PUTITEM( aHeightItem
, ATTR_CJK_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT_CJK
);
367 PUTITEM( aHeightItem
, ATTR_CTL_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT_CTL
);
370 // Font color - pass AUTO_COL to item
372 PUTITEM(SvxColorItem(maData
.maComplexColor
.getFinalColor(), maData
.maComplexColor
, ATTR_FONT_COLOR
), ATTR_FONT_COLOR
, EE_CHAR_COLOR
);
374 // Font weight (for all script types)
377 SvxWeightItem
aWeightItem( maData
.GetScWeight(), ATTR_FONT_WEIGHT
);
378 PUTITEM( aWeightItem
, ATTR_FONT_WEIGHT
, EE_CHAR_WEIGHT
);
379 PUTITEM( aWeightItem
, ATTR_CJK_FONT_WEIGHT
, EE_CHAR_WEIGHT_CJK
);
380 PUTITEM( aWeightItem
, ATTR_CTL_FONT_WEIGHT
, EE_CHAR_WEIGHT_CTL
);
386 SvxUnderlineItem
aUnderlItem( maData
.GetScUnderline(), ATTR_FONT_UNDERLINE
);
387 PUTITEM( aUnderlItem
, ATTR_FONT_UNDERLINE
, EE_CHAR_UNDERLINE
);
390 // Font posture (for all script types)
393 SvxPostureItem
aPostItem( maData
.GetScPosture(), ATTR_FONT_POSTURE
);
394 PUTITEM( aPostItem
, ATTR_FONT_POSTURE
, EE_CHAR_ITALIC
);
395 PUTITEM( aPostItem
, ATTR_CJK_FONT_POSTURE
, EE_CHAR_ITALIC_CJK
);
396 PUTITEM( aPostItem
, ATTR_CTL_FONT_POSTURE
, EE_CHAR_ITALIC_CTL
);
399 // Boolean attributes crossed out, contoured, shadowed
401 PUTITEM( SvxCrossedOutItem( maData
.GetScStrikeout(), ATTR_FONT_CROSSEDOUT
), ATTR_FONT_CROSSEDOUT
, EE_CHAR_STRIKEOUT
);
403 PUTITEM( SvxContourItem( maData
.mbOutline
, ATTR_FONT_CONTOUR
), ATTR_FONT_CONTOUR
, EE_CHAR_OUTLINE
);
405 PUTITEM( SvxShadowedItem( maData
.mbShadow
, ATTR_FONT_SHADOWED
), ATTR_FONT_SHADOWED
, EE_CHAR_SHADOW
);
407 // Super-/subscript: only on edit engine objects
408 if( mbEscapemUsed
&& bEE
)
409 rItemSet
.Put( SvxEscapementItem( maData
.GetScEscapement(), EE_CHAR_ESCAPEMENT
) );
414 void XclImpFont::WriteFontProperties( ScfPropertySet
& rPropSet
,
415 XclFontPropSetType eType
, const Color
* pFontColor
) const
417 GetFontPropSetHelper().WriteFontProperties(
418 rPropSet
, eType
, maData
, mbHasWstrn
, mbHasAsian
, mbHasCmplx
, pFontColor
);
421 void XclImpFont::ReadFontData2( XclImpStream
& rStrm
)
424 maData
.mnHeight
= rStrm
.ReaduInt16();
425 nFlags
= rStrm
.ReaduInt16();
427 maData
.mnWeight
= ::get_flagvalue( nFlags
, EXC_FONTATTR_BOLD
, EXC_FONTWGHT_BOLD
, EXC_FONTWGHT_NORMAL
);
428 maData
.mnUnderline
= ::get_flagvalue( nFlags
, EXC_FONTATTR_UNDERLINE
, EXC_FONTUNDERL_SINGLE
, EXC_FONTUNDERL_NONE
);
429 maData
.mbItalic
= ::get_flag( nFlags
, EXC_FONTATTR_ITALIC
);
430 maData
.mbStrikeout
= ::get_flag( nFlags
, EXC_FONTATTR_STRIKEOUT
);
431 maData
.mbOutline
= ::get_flag( nFlags
, EXC_FONTATTR_OUTLINE
);
432 maData
.mbShadow
= ::get_flag( nFlags
, EXC_FONTATTR_SHADOW
);
433 mbHasCharSet
= false;
436 void XclImpFont::ReadFontData5( XclImpStream
& rStrm
)
440 maData
.mnHeight
= rStrm
.ReaduInt16();
441 nFlags
= rStrm
.ReaduInt16();
442 ReadFontColor( rStrm
);
443 maData
.mnWeight
= rStrm
.ReaduInt16();
444 maData
.mnEscapem
= rStrm
.ReaduInt16();
445 maData
.mnUnderline
= rStrm
.ReaduInt8();
446 maData
.mnFamily
= rStrm
.ReaduInt8();
447 maData
.mnCharSet
= rStrm
.ReaduInt8();
450 maData
.mbItalic
= ::get_flag( nFlags
, EXC_FONTATTR_ITALIC
);
451 maData
.mbStrikeout
= ::get_flag( nFlags
, EXC_FONTATTR_STRIKEOUT
);
452 maData
.mbOutline
= ::get_flag( nFlags
, EXC_FONTATTR_OUTLINE
);
453 maData
.mbShadow
= ::get_flag( nFlags
, EXC_FONTATTR_SHADOW
);
454 mbHasCharSet
= maData
.mnCharSet
!= 0;
457 void XclImpFont::ReadFontColor( XclImpStream
& rStrm
)
459 maData
.maComplexColor
.setColor(GetPalette().GetColor(rStrm
.ReaduInt16()));
462 void XclImpFont::ReadFontName2( XclImpStream
& rStrm
)
464 maData
.maName
= rStrm
.ReadByteString( false );
467 void XclImpFont::ReadFontName8( XclImpStream
& rStrm
)
469 maData
.maName
= rStrm
.ReadUniString( rStrm
.ReaduInt8() );
472 void XclImpFont::GuessScriptType()
475 mbHasAsian
= mbHasCmplx
= false;
477 // find the script types for which the font contains characters
478 OutputDevice
* pPrinter
= GetPrinter();
482 vcl::Font
aFont( maData
.maName
, Size( 0, 10 ) );
483 FontCharMapRef xFontCharMap
;
485 pPrinter
->SetFont( aFont
);
486 if( !pPrinter
->GetFontCharMap( xFontCharMap
) )
491 xFontCharMap
->HasChar( 0x3041 ) || // 3040-309F: Hiragana
492 xFontCharMap
->HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
493 xFontCharMap
->HasChar( 0x3111 ) || // 3100-312F: Bopomofo
494 xFontCharMap
->HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
495 xFontCharMap
->HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
496 xFontCharMap
->HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
497 xFontCharMap
->HasChar( 0x4E01 ) || // 4E00-9FFF: CJK Unified Ideographs
498 xFontCharMap
->HasChar( 0x7E01 ) || // 4E00-9FFF: CJK Unified Ideographs
499 xFontCharMap
->HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
500 xFontCharMap
->HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
501 xFontCharMap
->HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
502 xFontCharMap
->HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
503 xFontCharMap
->HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
506 xFontCharMap
->HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
507 xFontCharMap
->HasChar( 0x0631 ) || // 0600-06FF: Arabic
508 xFontCharMap
->HasChar( 0x0721 ) || // 0700-074F: Syriac
509 xFontCharMap
->HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
510 xFontCharMap
->HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
511 xFontCharMap
->HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
512 xFontCharMap
->HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
513 xFontCharMap
->HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
515 mbHasWstrn
= (!mbHasAsian
&& !mbHasCmplx
) || xFontCharMap
->HasChar( 'A' );
518 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot
& rRoot
) :
525 // default font for form controls without own font information
526 XclFontData aCtrlFontData
;
533 aCtrlFontData
.maName
= "Helv";
534 aCtrlFontData
.mnHeight
= 160;
535 aCtrlFontData
.mnWeight
= EXC_FONTWGHT_BOLD
;
538 aCtrlFontData
.maName
= "Tahoma";
539 aCtrlFontData
.mnHeight
= 160;
540 aCtrlFontData
.mnWeight
= EXC_FONTWGHT_NORMAL
;
545 maCtrlFont
.SetFontData( aCtrlFontData
, false );
548 void XclImpFontBuffer::Initialize()
552 // application font for column width calculation, later filled with first font from font list
553 XclFontData aAppFontData
;
554 aAppFontData
.maName
= "Arial";
555 aAppFontData
.mnHeight
= 200;
556 aAppFontData
.mnWeight
= EXC_FONTWGHT_NORMAL
;
557 UpdateAppFont( aAppFontData
, false );
560 const XclImpFont
* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex
) const
562 /* Font with index 4 is not stored in an Excel file, but used e.g. by
563 BIFF5 form pushbutton objects. It is the bold default font.
564 This also means that entries above 4 are out by one in the list. */
571 // Font ID is zero-based when it's less than 4.
572 return nFontIndex
>= maFontList
.size() ? nullptr : &maFontList
[nFontIndex
];
575 // Font ID is greater than 4. It is now 1-based.
576 return nFontIndex
> maFontList
.size() ? nullptr : &maFontList
[nFontIndex
-1];
579 void XclImpFontBuffer::ReadFont( XclImpStream
& rStrm
)
581 maFontList
.emplace_back( GetRoot() );
582 XclImpFont
& rFont
= maFontList
.back();
583 rFont
.ReadFont( rStrm
);
585 if( maFontList
.size() == 1 )
587 UpdateAppFont( rFont
.GetFontData(), rFont
.HasCharSet() );
591 void XclImpFontBuffer::ReadEfont( XclImpStream
& rStrm
)
593 if( !maFontList
.empty() )
594 maFontList
.back().ReadEfont( rStrm
);
597 void XclImpFontBuffer::FillToItemSet(
598 SfxItemSet
& rItemSet
, XclFontItemType eType
,
599 sal_uInt16 nFontIdx
, bool bSkipPoolDefs
) const
601 if( const XclImpFont
* pFont
= GetFont( nFontIdx
) )
602 pFont
->FillToItemSet( rItemSet
, eType
, bSkipPoolDefs
);
605 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet
& rPropSet
,
606 XclFontPropSetType eType
, sal_uInt16 nFontIdx
, const Color
* pFontColor
) const
608 if( const XclImpFont
* pFont
= GetFont( nFontIdx
) )
609 pFont
->WriteFontProperties( rPropSet
, eType
, pFontColor
);
612 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet
& rPropSet
) const
614 maCtrlFont
.WriteFontProperties( rPropSet
, EXC_FONTPROPSET_CONTROL
);
617 void XclImpFontBuffer::UpdateAppFont( const XclFontData
& rFontData
, bool bHasCharSet
)
619 maAppFont
= rFontData
;
620 // #i3006# Calculate the width of '0' from first font and current printer.
621 SetCharWidth( maAppFont
);
623 // font 4 is bold font 0
624 XclFontData
aFont4Data( maAppFont
);
625 aFont4Data
.mnWeight
= EXC_FONTWGHT_BOLD
;
626 maFont4
.SetFontData( aFont4Data
, bHasCharSet
);
629 // FORMAT record - number formats =============================================
631 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot
& rRoot
) :
632 XclNumFmtBuffer( rRoot
),
638 void XclImpNumFmtBuffer::Initialize()
642 InitializeImport(); // base class
645 void XclImpNumFmtBuffer::ReadFormat( XclImpStream
& rStrm
)
652 aFormat
= rStrm
.ReadByteString( false );
656 rStrm
.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
657 aFormat
= rStrm
.ReadByteString( false );
661 mnNextXclIdx
= rStrm
.ReaduInt16();
662 aFormat
= rStrm
.ReadByteString( false );
666 mnNextXclIdx
= rStrm
.ReaduInt16();
667 aFormat
= rStrm
.ReadUniString();
675 if( mnNextXclIdx
< 0xFFFF )
677 InsertFormat( mnNextXclIdx
, aFormat
);
682 sal_uInt16
XclImpNumFmtBuffer::ReadCFFormat( XclImpStream
& rStrm
, bool bIFmt
)
684 // internal number format ?
689 nIndex
= rStrm
.ReaduInt8();
694 OUString aFormat
= rStrm
.ReadUniString();
695 InsertFormat( mnNextXclIdx
, aFormat
);
697 return mnNextXclIdx
- 1;
701 void XclImpNumFmtBuffer::CreateScFormats()
703 OSL_ENSURE( maIndexMap
.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
705 SvNumberFormatter
& rFormatter
= GetFormatter();
706 for( const auto& [rXclNumFmt
, rNumFmt
] : GetFormatMap() )
708 // insert/convert the Excel number format
710 if( !rNumFmt
.maFormat
.isEmpty() )
712 OUString
aFormat( rNumFmt
.maFormat
);
714 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
715 rFormatter
.PutandConvertEntry( aFormat
, nCheckPos
,
716 nType
, nKey
, LANGUAGE_ENGLISH_US
, rNumFmt
.meLanguage
, false);
719 nKey
= rFormatter
.GetFormatIndex( rNumFmt
.meOffset
, rNumFmt
.meLanguage
);
721 // insert the resulting format key into the Excel->Calc index map
722 maIndexMap
[ rXclNumFmt
] = nKey
;
726 sal_uInt32
XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt
) const
728 XclImpIndexMap::const_iterator aIt
= maIndexMap
.find( nXclNumFmt
);
729 return (aIt
!= maIndexMap
.end()) ? aIt
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
;
732 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet
& rItemSet
, sal_uInt16 nXclNumFmt
, bool bSkipPoolDefs
) const
734 sal_uInt32 nScNumFmt
= GetScFormat( nXclNumFmt
);
735 if( nScNumFmt
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
736 nScNumFmt
= GetStdScNumFmt();
737 FillScFmtToItemSet( rItemSet
, nScNumFmt
, bSkipPoolDefs
);
740 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet
& rItemSet
, sal_uInt32 nScNumFmt
, bool bSkipPoolDefs
) const
742 OSL_ENSURE( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
743 ScfTools::PutItem( rItemSet
, SfxUInt32Item( ATTR_VALUE_FORMAT
, nScNumFmt
), bSkipPoolDefs
);
744 if( rItemSet
.GetItemState( ATTR_VALUE_FORMAT
, false ) == SfxItemState::SET
)
745 ScGlobal::AddLanguage( rItemSet
, GetFormatter() );
748 // XF, STYLE record - Cell formatting =========================================
750 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt
)
752 mbLocked
= ::get_flag( nNumFmt
, EXC_XF2_LOCKED
);
753 mbHidden
= ::get_flag( nNumFmt
, EXC_XF2_HIDDEN
);
756 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt
)
758 mbLocked
= ::get_flag( nProt
, EXC_XF_LOCKED
);
759 mbHidden
= ::get_flag( nProt
, EXC_XF_HIDDEN
);
762 void XclImpCellProt::FillToItemSet( SfxItemSet
& rItemSet
, bool bSkipPoolDefs
) const
764 ScfTools::PutItem( rItemSet
, ScProtectionAttr( mbLocked
, mbHidden
), bSkipPoolDefs
);
767 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags
)
769 mnHorAlign
= ::extract_value
< sal_uInt8
>( nFlags
, 0, 3 );
772 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign
)
774 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
775 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
); // new in BIFF3
778 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign
)
780 FillFromXF3( nAlign
);
781 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 2 ); // new in BIFF4
782 mnOrient
= ::extract_value
< sal_uInt8
>( nAlign
, 6, 2 ); // new in BIFF4
785 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign
)
787 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
788 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
789 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
);
790 mnOrient
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 2 );
793 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign
, sal_uInt16 nMiscAttrib
)
795 mnHorAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
796 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
797 mbLineBreak
= ::get_flag( nAlign
, EXC_XF_LINEBREAK
);
798 mnRotation
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 8 ); // new in BIFF8
799 mnIndent
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 0, 4 ); // new in BIFF8
800 mbShrink
= ::get_flag( nMiscAttrib
, EXC_XF8_SHRINK
); // new in BIFF8
801 mnTextDir
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 6, 2 ); // new in BIFF8
804 void XclImpCellAlign::FillFromCF( sal_uInt16 nAlign
, sal_uInt16 nMiscAttrib
)
806 mnHorAlign
= extract_value
< sal_uInt8
>( nAlign
, 0, 3 );
807 mbLineBreak
= get_flag
< sal_uInt8
>( nAlign
, EXC_XF_LINEBREAK
);
808 mnVerAlign
= ::extract_value
< sal_uInt8
>( nAlign
, 4, 3 );
809 mnRotation
= ::extract_value
< sal_uInt8
>( nAlign
, 8, 8 );
810 mnIndent
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 0, 4 );
811 mbShrink
= ::get_flag( nMiscAttrib
, EXC_XF8_SHRINK
);
812 mnTextDir
= ::extract_value
< sal_uInt8
>( nMiscAttrib
, 6, 2 );
815 void XclImpCellAlign::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpFont
* pFont
, bool bSkipPoolDefs
) const
817 // horizontal alignment
818 ScfTools::PutItem( rItemSet
, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY
), bSkipPoolDefs
);
819 ScfTools::PutItem( rItemSet
, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD
), bSkipPoolDefs
);
821 // text wrap (#i74508# always if vertical alignment is justified or distributed)
822 bool bLineBreak
= mbLineBreak
|| (mnVerAlign
== EXC_XF_VER_JUSTIFY
) || (mnVerAlign
== EXC_XF_VER_DISTRIB
);
823 ScfTools::PutItem( rItemSet
, ScLineBreakCell( bLineBreak
), bSkipPoolDefs
);
825 // vertical alignment
826 ScfTools::PutItem( rItemSet
, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY
), bSkipPoolDefs
);
827 ScfTools::PutItem( rItemSet
, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD
), bSkipPoolDefs
);
830 sal_uInt16 nScIndent
= mnIndent
* 200; // 1 Excel unit == 10 pt == 200 twips
831 ScfTools::PutItem( rItemSet
, ScIndentItem( nScIndent
), bSkipPoolDefs
);
834 ScfTools::PutItem( rItemSet
, ScShrinkToFitCell( mbShrink
), bSkipPoolDefs
);
836 // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
837 sal_uInt8 nXclRot
= (mnOrient
== EXC_ORIENT_NONE
) ? mnRotation
: XclTools::GetXclRotFromOrient( mnOrient
);
838 bool bStacked
= (nXclRot
== EXC_ROT_STACKED
);
839 ScfTools::PutItem( rItemSet
, ScVerticalStackCell( bStacked
), bSkipPoolDefs
);
840 // set an angle in the range from -90 to 90 degrees
841 Degree100 nAngle
= XclTools::GetScRotation( nXclRot
, 0_deg100
);
842 ScfTools::PutItem( rItemSet
, ScRotateValueItem( nAngle
), bSkipPoolDefs
);
843 // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
844 bool bAsianVert
= bStacked
&& pFont
&& pFont
->HasAsianChars();
845 ScfTools::PutItem( rItemSet
, SfxBoolItem( ATTR_VERTICAL_ASIAN
, bAsianVert
), bSkipPoolDefs
);
847 // CTL text direction
848 ScfTools::PutItem( rItemSet
, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR
), bSkipPoolDefs
);
851 XclImpCellBorder::XclImpCellBorder()
853 SetUsedFlags( false, false );
856 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed
, bool bDiagUsed
)
858 mbLeftUsed
= mbRightUsed
= mbTopUsed
= mbBottomUsed
= bOuterUsed
;
859 mbDiagUsed
= bDiagUsed
;
862 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags
)
864 mnLeftLine
= ::get_flagvalue( nFlags
, EXC_XF2_LEFTLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
865 mnRightLine
= ::get_flagvalue( nFlags
, EXC_XF2_RIGHTLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
866 mnTopLine
= ::get_flagvalue( nFlags
, EXC_XF2_TOPLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
867 mnBottomLine
= ::get_flagvalue( nFlags
, EXC_XF2_BOTTOMLINE
, EXC_LINE_THIN
, EXC_LINE_NONE
);
868 mnLeftColor
= mnRightColor
= mnTopColor
= mnBottomColor
= EXC_COLOR_BIFF2_BLACK
;
869 SetUsedFlags( true, false );
872 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder
)
874 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder
, 0, 3 );
875 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder
, 8, 3 );
876 mnBottomLine
= ::extract_value
< sal_uInt8
>( nBorder
, 16, 3 );
877 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder
, 24, 3 );
878 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder
, 3, 5 );
879 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder
, 11, 5 );
880 mnBottomColor
= ::extract_value
< sal_uInt16
>( nBorder
, 19, 5 );
881 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder
, 27, 5 );
882 SetUsedFlags( true, false );
885 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder
, sal_uInt32 nArea
)
887 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder
, 0, 3 );
888 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder
, 3, 3 );
889 mnBottomLine
= ::extract_value
< sal_uInt8
>( nArea
, 22, 3 );
890 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder
, 6, 3 );
891 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder
, 9, 7 );
892 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder
, 16, 7 );
893 mnBottomColor
= ::extract_value
< sal_uInt16
>( nArea
, 25, 7 );
894 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder
, 23, 7 );
895 SetUsedFlags( true, false );
898 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1
, sal_uInt32 nBorder2
)
900 mnLeftLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 0, 4 );
901 mnRightLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 4, 4 );
902 mnTopLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 8, 4 );
903 mnBottomLine
= ::extract_value
< sal_uInt8
>( nBorder1
, 12, 4 );
904 mnLeftColor
= ::extract_value
< sal_uInt16
>( nBorder1
, 16, 7 );
905 mnRightColor
= ::extract_value
< sal_uInt16
>( nBorder1
, 23, 7 );
906 mnTopColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 0, 7 );
907 mnBottomColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 7, 7 );
908 mbDiagTLtoBR
= ::get_flag( nBorder1
, EXC_XF_DIAGONAL_TL_TO_BR
);
909 mbDiagBLtoTR
= ::get_flag( nBorder1
, EXC_XF_DIAGONAL_BL_TO_TR
);
910 if( mbDiagTLtoBR
|| mbDiagBLtoTR
)
912 mnDiagLine
= ::extract_value
< sal_uInt8
>( nBorder2
, 21, 4 );
913 mnDiagColor
= ::extract_value
< sal_uInt16
>( nBorder2
, 14, 7 );
915 SetUsedFlags( true, true );
918 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle
, sal_uInt32 nLineColor
, sal_uInt32 nFlags
)
920 mnLeftLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 0, 4 );
921 mnRightLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 4, 4 );
922 mnTopLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 8, 4 );
923 mnBottomLine
= ::extract_value
< sal_uInt8
>( nLineStyle
, 12, 4 );
924 mnLeftColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 0, 7 );
925 mnRightColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 7, 7 );
926 mnTopColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 16, 7 );
927 mnBottomColor
= ::extract_value
< sal_uInt16
>( nLineColor
, 23, 7 );
928 mbLeftUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_LEFT
);
929 mbRightUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_RIGHT
);
930 mbTopUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_TOP
);
931 mbBottomUsed
= !::get_flag( nFlags
, EXC_CF_BORDER_BOTTOM
);
935 bool XclImpCellBorder::HasAnyOuterBorder() const
938 (mbLeftUsed
&& (mnLeftLine
!= EXC_LINE_NONE
)) ||
939 (mbRightUsed
&& (mnRightLine
!= EXC_LINE_NONE
)) ||
940 (mbTopUsed
&& (mnTopLine
!= EXC_LINE_NONE
)) ||
941 (mbBottomUsed
&& (mnBottomLine
!= EXC_LINE_NONE
));
946 /** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
947 bool lclConvertBorderLine( ::editeng::SvxBorderLine
& rLine
, const XclImpPalette
& rPalette
, sal_uInt8 nXclLine
, sal_uInt16 nXclColor
)
949 static const sal_uInt16 ppnLineParam
[][ 4 ] =
952 { 0, table::BorderLineStyle::SOLID
}, // 0 = none
953 { EXC_BORDER_THIN
, table::BorderLineStyle::SOLID
}, // 1 = thin
954 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::SOLID
}, // 2 = medium
955 { EXC_BORDER_THIN
, table::BorderLineStyle::FINE_DASHED
}, // 3 = dashed
956 { EXC_BORDER_THIN
, table::BorderLineStyle::DOTTED
}, // 4 = dotted
957 { EXC_BORDER_THICK
, table::BorderLineStyle::SOLID
}, // 5 = thick
958 { EXC_BORDER_THICK
, table::BorderLineStyle::DOUBLE_THIN
}, // 6 = double
959 { EXC_BORDER_HAIR
, table::BorderLineStyle::SOLID
}, // 7 = hair
960 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASHED
}, // 8 = med dash
961 { EXC_BORDER_THIN
, table::BorderLineStyle::DASH_DOT
}, // 9 = thin dashdot
962 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT
}, // A = med dashdot
963 { EXC_BORDER_THIN
, table::BorderLineStyle::DASH_DOT_DOT
}, // B = thin dashdotdot
964 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT_DOT
}, // C = med dashdotdot
965 { EXC_BORDER_MEDIUM
, table::BorderLineStyle::DASH_DOT
} // D = med slant dashdot
968 if( nXclLine
== EXC_LINE_NONE
)
970 if( nXclLine
>= std::size( ppnLineParam
) )
971 nXclLine
= EXC_LINE_THIN
;
973 rLine
.SetColor( rPalette
.GetColor( nXclColor
) );
974 rLine
.SetWidth( ppnLineParam
[ nXclLine
][ 0 ] );
975 rLine
.SetBorderLineStyle( static_cast< SvxBorderLineStyle
>(
976 ppnLineParam
[ nXclLine
][ 1 ]) );
982 void XclImpCellBorder::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpPalette
& rPalette
, bool bSkipPoolDefs
) const
984 if( mbLeftUsed
|| mbRightUsed
|| mbTopUsed
|| mbBottomUsed
)
986 SvxBoxItem
aBoxItem( ATTR_BORDER
);
987 ::editeng::SvxBorderLine aLine
;
988 if( mbLeftUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnLeftLine
, mnLeftColor
) )
989 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::LEFT
);
990 if( mbRightUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnRightLine
, mnRightColor
) )
991 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::RIGHT
);
992 if( mbTopUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnTopLine
, mnTopColor
) )
993 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::TOP
);
994 if( mbBottomUsed
&& lclConvertBorderLine( aLine
, rPalette
, mnBottomLine
, mnBottomColor
) )
995 aBoxItem
.SetLine( &aLine
, SvxBoxItemLine::BOTTOM
);
996 ScfTools::PutItem( rItemSet
, aBoxItem
, bSkipPoolDefs
);
1001 SvxLineItem
aTLBRItem( ATTR_BORDER_TLBR
);
1002 SvxLineItem
aBLTRItem( ATTR_BORDER_BLTR
);
1003 ::editeng::SvxBorderLine aLine
;
1004 if( lclConvertBorderLine( aLine
, rPalette
, mnDiagLine
, mnDiagColor
) )
1007 aTLBRItem
.SetLine( &aLine
);
1009 aBLTRItem
.SetLine( &aLine
);
1011 ScfTools::PutItem( rItemSet
, aTLBRItem
, bSkipPoolDefs
);
1012 ScfTools::PutItem( rItemSet
, aBLTRItem
, bSkipPoolDefs
);
1015 XclImpCellArea::XclImpCellArea()
1017 SetUsedFlags( false );
1020 void XclImpCellArea::SetUsedFlags( bool bUsed
)
1022 mbForeUsed
= mbBackUsed
= mbPattUsed
= bUsed
;
1025 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags
)
1027 mnPattern
= ::get_flagvalue( nFlags
, EXC_XF2_BACKGROUND
, EXC_PATT_12_5_PERC
, EXC_PATT_NONE
);
1028 mnForeColor
= EXC_COLOR_BIFF2_BLACK
;
1029 mnBackColor
= EXC_COLOR_BIFF2_WHITE
;
1030 SetUsedFlags( true );
1033 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea
)
1035 mnPattern
= ::extract_value
< sal_uInt8
>( nArea
, 0, 6 );
1036 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 6, 5 );
1037 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 11, 5 );
1038 SetUsedFlags( true );
1041 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea
)
1043 mnPattern
= ::extract_value
< sal_uInt8
>( nArea
, 16, 6 );
1044 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 0, 7 );
1045 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 7, 7 );
1046 SetUsedFlags( true );
1049 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2
, sal_uInt16 nArea
)
1051 mnPattern
= ::extract_value
< sal_uInt8
>( nBorder2
, 26, 6 );
1052 mnForeColor
= ::extract_value
< sal_uInt16
>( nArea
, 0, 7 );
1053 mnBackColor
= ::extract_value
< sal_uInt16
>( nArea
, 7, 7 );
1054 SetUsedFlags( true );
1057 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern
, sal_uInt16 nColor
, sal_uInt32 nFlags
)
1059 mnForeColor
= ::extract_value
< sal_uInt16
>( nColor
, 0, 7 );
1060 mnBackColor
= ::extract_value
< sal_uInt16
>( nColor
, 7, 7 );
1061 mnPattern
= ::extract_value
< sal_uInt8
>( nPattern
, 10, 6 );
1062 mbForeUsed
= !::get_flag( nFlags
, EXC_CF_AREA_FGCOLOR
);
1063 mbBackUsed
= !::get_flag( nFlags
, EXC_CF_AREA_BGCOLOR
);
1064 mbPattUsed
= !::get_flag( nFlags
, EXC_CF_AREA_PATTERN
);
1066 if( mbBackUsed
&& (!mbPattUsed
|| (mnPattern
== EXC_PATT_SOLID
)) )
1068 mnForeColor
= mnBackColor
;
1069 mnPattern
= EXC_PATT_SOLID
;
1070 mbForeUsed
= mbPattUsed
= true;
1072 else if( !mbBackUsed
&& mbPattUsed
&& (mnPattern
== EXC_PATT_SOLID
) )
1078 void XclImpCellArea::FillToItemSet( SfxItemSet
& rItemSet
, const XclImpPalette
& rPalette
, bool bSkipPoolDefs
) const
1080 if( !mbPattUsed
) // colors may be both unused in cond. formats
1083 SvxBrushItem
aBrushItem( ATTR_BACKGROUND
);
1085 // do not use IsTransparent() - old Calc filter writes transparency with different color indexes
1086 if( mnPattern
== EXC_PATT_NONE
)
1088 aBrushItem
.SetColor( COL_TRANSPARENT
);
1092 Color
aFore( rPalette
.GetColor( mbForeUsed
? mnForeColor
: EXC_COLOR_WINDOWTEXT
) );
1093 Color
aBack( rPalette
.GetColor( mbBackUsed
? mnBackColor
: EXC_COLOR_WINDOWBACK
) );
1094 aBrushItem
.SetColor( XclTools::GetPatternColor( aFore
, aBack
, mnPattern
) );
1097 ScfTools::PutItem( rItemSet
, aBrushItem
, bSkipPoolDefs
);
1100 XclImpXF::XclImpXF( const XclImpRoot
& rRoot
) :
1101 XclXFBase( true ), // default is cell XF
1102 XclImpRoot( rRoot
),
1103 mpStyleSheet( nullptr ),
1109 XclImpXF::~XclImpXF()
1113 void XclImpXF::ReadXF2( XclImpStream
& rStrm
)
1115 sal_uInt8 nReadFont
, nReadNumFmt
, nFlags
;
1116 nReadFont
= rStrm
.ReaduInt8();
1118 nReadNumFmt
= rStrm
.ReaduInt8();
1119 nFlags
= rStrm
.ReaduInt8();
1121 // XF type always cell, no parent, used flags always true
1122 SetAllUsedFlags( true );
1125 maProtection
.FillFromXF2( nReadNumFmt
);
1126 mnXclFont
= nReadFont
;
1127 mnXclNumFmt
= nReadNumFmt
& EXC_XF2_VALFMT_MASK
;
1128 maAlignment
.FillFromXF2( nFlags
);
1129 maBorder
.FillFromXF2( nFlags
);
1130 maArea
.FillFromXF2( nFlags
);
1133 void XclImpXF::ReadXF3( XclImpStream
& rStrm
)
1136 sal_uInt16 nTypeProt
, nAlign
, nArea
;
1137 sal_uInt8 nReadFont
, nReadNumFmt
;
1138 nReadFont
= rStrm
.ReaduInt8();
1139 nReadNumFmt
= rStrm
.ReaduInt8();
1140 nTypeProt
= rStrm
.ReaduInt16();
1141 nAlign
= rStrm
.ReaduInt16();
1142 nArea
= rStrm
.ReaduInt16();
1143 nBorder
= rStrm
.ReaduInt32();
1145 // XF type/parent, attribute used flags
1146 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
); // new in BIFF3
1147 mnParent
= ::extract_value
< sal_uInt16
>( nAlign
, 4, 12 ); // new in BIFF3
1148 SetUsedFlags( ::extract_value
< sal_uInt8
>( nTypeProt
, 10, 6 ) );
1151 maProtection
.FillFromXF3( nTypeProt
);
1152 mnXclFont
= nReadFont
;
1153 mnXclNumFmt
= nReadNumFmt
;
1154 maAlignment
.FillFromXF3( nAlign
);
1155 maBorder
.FillFromXF3( nBorder
);
1156 maArea
.FillFromXF3( nArea
); // new in BIFF3
1159 void XclImpXF::ReadXF4( XclImpStream
& rStrm
)
1162 sal_uInt16 nTypeProt
, nAlign
, nArea
;
1163 sal_uInt8 nReadFont
, nReadNumFmt
;
1164 nReadFont
= rStrm
.ReaduInt8();
1165 nReadNumFmt
= rStrm
.ReaduInt8();
1166 nTypeProt
= rStrm
.ReaduInt16();
1167 nAlign
= rStrm
.ReaduInt16();
1168 nArea
= rStrm
.ReaduInt16();
1169 nBorder
= rStrm
.ReaduInt32();
1171 // XF type/parent, attribute used flags
1172 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1173 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1174 SetUsedFlags( ::extract_value
< sal_uInt8
>( nAlign
, 10, 6 ) );
1177 maProtection
.FillFromXF3( nTypeProt
);
1178 mnXclFont
= nReadFont
;
1179 mnXclNumFmt
= nReadNumFmt
;
1180 maAlignment
.FillFromXF4( nAlign
);
1181 maBorder
.FillFromXF3( nBorder
);
1182 maArea
.FillFromXF3( nArea
);
1185 void XclImpXF::ReadXF5( XclImpStream
& rStrm
)
1187 sal_uInt32 nArea
, nBorder
;
1188 sal_uInt16 nTypeProt
, nAlign
;
1189 mnXclFont
= rStrm
.ReaduInt16();
1190 mnXclNumFmt
= rStrm
.ReaduInt16();
1191 nTypeProt
= rStrm
.ReaduInt16();
1192 nAlign
= rStrm
.ReaduInt16();
1193 nArea
= rStrm
.ReaduInt32();
1194 nBorder
= rStrm
.ReaduInt32();
1196 // XF type/parent, attribute used flags
1197 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1198 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1199 SetUsedFlags( ::extract_value
< sal_uInt8
>( nAlign
, 10, 6 ) );
1202 maProtection
.FillFromXF3( nTypeProt
);
1203 maAlignment
.FillFromXF5( nAlign
);
1204 maBorder
.FillFromXF5( nBorder
, nArea
);
1205 maArea
.FillFromXF5( nArea
);
1208 void XclImpXF::ReadXF8( XclImpStream
& rStrm
)
1210 sal_uInt32 nBorder1
, nBorder2
;
1211 sal_uInt16 nTypeProt
, nAlign
, nMiscAttrib
, nArea
;
1212 mnXclFont
= rStrm
.ReaduInt16();
1213 mnXclNumFmt
= rStrm
.ReaduInt16();
1214 nTypeProt
= rStrm
.ReaduInt16();
1215 nAlign
= rStrm
.ReaduInt16();
1216 nMiscAttrib
= rStrm
.ReaduInt16();
1217 nBorder1
= rStrm
.ReaduInt32();
1218 nBorder2
= rStrm
.ReaduInt32( );
1219 nArea
= rStrm
.ReaduInt16();
1221 // XF type/parent, attribute used flags
1222 mbCellXF
= !::get_flag( nTypeProt
, EXC_XF_STYLE
);
1223 mnParent
= ::extract_value
< sal_uInt16
>( nTypeProt
, 4, 12 );
1224 SetUsedFlags( ::extract_value
< sal_uInt8
>( nMiscAttrib
, 10, 6 ) );
1227 maProtection
.FillFromXF3( nTypeProt
);
1228 maAlignment
.FillFromXF8( nAlign
, nMiscAttrib
);
1229 maBorder
.FillFromXF8( nBorder1
, nBorder2
);
1230 maArea
.FillFromXF8( nBorder2
, nArea
);
1233 void XclImpXF::ReadXF( XclImpStream
& rStrm
)
1237 case EXC_BIFF2
: ReadXF2( rStrm
); break;
1238 case EXC_BIFF3
: ReadXF3( rStrm
); break;
1239 case EXC_BIFF4
: ReadXF4( rStrm
); break;
1240 case EXC_BIFF5
: ReadXF5( rStrm
); break;
1241 case EXC_BIFF8
: ReadXF8( rStrm
); break;
1242 default: DBG_ERROR_BIFF();
1246 const ScPatternAttr
& XclImpXF::CreatePattern( bool bSkipPoolDefs
)
1251 // create new pattern attribute set
1252 mpPattern
.reset( new ScPatternAttr(GetDoc().getCellAttributeHelper()) );
1253 SfxItemSet
& rItemSet
= mpPattern
->GetItemSet();
1254 XclImpXF
* pParentXF
= IsCellXF() ? GetXFBuffer().GetXF( mnParent
) : nullptr;
1256 // parent cell style
1257 if( IsCellXF() && !mpStyleSheet
)
1259 mpStyleSheet
= GetXFBuffer().CreateStyleSheet( mnParent
);
1261 /* Enables mb***Used flags, if the formatting attributes differ from
1262 the passed XF record. In cell XFs Excel uses the cell attributes,
1263 if they differ from the parent style XF.
1264 ...or if the respective flag is not set in parent style XF. */
1268 mbProtUsed
= !pParentXF
->mbProtUsed
|| !(maProtection
== pParentXF
->maProtection
);
1270 mbFontUsed
= !pParentXF
->mbFontUsed
|| (mnXclFont
!= pParentXF
->mnXclFont
);
1272 mbFmtUsed
= !pParentXF
->mbFmtUsed
|| (mnXclNumFmt
!= pParentXF
->mnXclNumFmt
);
1274 mbAlignUsed
= !pParentXF
->mbAlignUsed
|| !(maAlignment
== pParentXF
->maAlignment
);
1276 mbBorderUsed
= !pParentXF
->mbBorderUsed
|| !(maBorder
== pParentXF
->maBorder
);
1278 mbAreaUsed
= !pParentXF
->mbAreaUsed
|| !(maArea
== pParentXF
->maArea
);
1284 maProtection
.FillToItemSet( rItemSet
, bSkipPoolDefs
);
1288 GetFontBuffer().FillToItemSet( rItemSet
, XclFontItemType::Cell
, mnXclFont
, bSkipPoolDefs
);
1293 GetNumFmtBuffer().FillToItemSet( rItemSet
, mnXclNumFmt
, bSkipPoolDefs
);
1294 // Trace occurrences of Windows date formats
1295 GetTracer().TraceDates( mnXclNumFmt
);
1300 maAlignment
.FillToItemSet( rItemSet
, GetFontBuffer().GetFont( mnXclFont
), bSkipPoolDefs
);
1305 maBorder
.FillToItemSet( rItemSet
, GetPalette(), bSkipPoolDefs
);
1306 GetTracer().TraceBorderLineStyle(maBorder
.mnLeftLine
> EXC_LINE_HAIR
||
1307 maBorder
.mnRightLine
> EXC_LINE_HAIR
|| maBorder
.mnTopLine
> EXC_LINE_HAIR
||
1308 maBorder
.mnBottomLine
> EXC_LINE_HAIR
);
1314 maArea
.FillToItemSet( rItemSet
, GetPalette(), bSkipPoolDefs
);
1315 GetTracer().TraceFillPattern(maArea
.mnPattern
!= EXC_PATT_NONE
&&
1316 maArea
.mnPattern
!= EXC_PATT_SOLID
);
1319 /* #i38709# Decide which rotation reference mode to use. If any outer
1320 border line of the cell is set (either explicitly or via cell style),
1321 and the cell contents are rotated, set rotation reference to bottom of
1322 cell. This causes the borders to be painted rotated with the text. */
1323 if( mbAlignUsed
|| mbBorderUsed
)
1325 SvxRotateMode eRotateMode
= SVX_ROTATE_MODE_STANDARD
;
1326 const XclImpCellAlign
* pAlign
= mbAlignUsed
? &maAlignment
: (pParentXF
? &pParentXF
->maAlignment
: nullptr);
1327 const XclImpCellBorder
* pBorder
= mbBorderUsed
? &maBorder
: (pParentXF
? &pParentXF
->maBorder
: nullptr);
1328 if( pAlign
&& pBorder
&& (0 < pAlign
->mnRotation
) && (pAlign
->mnRotation
<= 180) && pBorder
->HasAnyOuterBorder() )
1329 eRotateMode
= SVX_ROTATE_MODE_BOTTOM
;
1330 ScfTools::PutItem( rItemSet
, SvxRotateModeItem( eRotateMode
, ATTR_ROTATE_MODE
), bSkipPoolDefs
);
1333 // Excel's cell margins are different from Calc's default margins.
1334 SvxMarginItem
aItem(40, 40, 40, 40, ATTR_MARGIN
);
1335 ScfTools::PutItem(rItemSet
, aItem
, bSkipPoolDefs
);
1340 void XclImpXF::ApplyPatternToAttrVector(
1341 std::vector
<ScAttrEntry
>& rAttrs
, SCROW nRow1
, SCROW nRow2
, sal_uInt32 nForceScNumFmt
)
1343 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1345 ScPatternAttr
& rPat
= *mpPattern
;
1347 // insert into document
1348 ScDocument
& rDoc
= GetDoc();
1354 // Apply style sheet. Don't clear the direct formats.
1355 rPat
.SetStyleSheet(mpStyleSheet
, false);
1359 // When the cell format is not associated with any style, use the
1360 // 'Default' style. Some buggy XLS docs generated by apps other
1361 // than Excel (such as 1C) may not have any built-in styles at
1363 ScStyleSheetPool
* pStylePool
= rDoc
.GetStyleSheetPool();
1366 ScStyleSheet
* pStyleSheet
= static_cast<ScStyleSheet
*>(
1368 ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
));
1371 rPat
.SetStyleSheet(pStyleSheet
, false);
1377 if (nForceScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1379 ScPatternAttr
aNumPat(rDoc
.getCellAttributeHelper());
1380 GetNumFmtBuffer().FillScFmtToItemSet(aNumPat
.GetItemSet(), nForceScNumFmt
);
1381 rPat
.GetItemSet().Put(aNumPat
.GetItemSet());
1384 // Make sure we skip unnamed styles.
1385 if (!rPat
.GetStyleName())
1388 // Check for a gap between the last entry and this one.
1389 bool bHasGap
= false;
1390 if (rAttrs
.empty() && nRow1
> 0)
1391 // First attribute range doesn't start at row 0.
1394 if (!rAttrs
.empty() && rAttrs
.back().nEndRow
+ 1 < nRow1
)
1399 // Fill this gap with the default pattern.
1401 aEntry
.nEndRow
= nRow1
- 1;
1402 aEntry
.setScPatternAttr(&rDoc
.getCellAttributeHelper().getDefaultCellAttribute());
1403 rAttrs
.push_back(aEntry
);
1407 aEntry
.nEndRow
= nRow2
;
1408 aEntry
.setScPatternAttr(&rPat
, false);
1409 rAttrs
.push_back(aEntry
);
1412 void XclImpXF::ApplyPattern(
1413 SCCOL nScCol1
, SCROW nScRow1
, SCCOL nScCol2
, SCROW nScRow2
,
1416 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1417 const ScPatternAttr
& rPattern
= CreatePattern();
1419 // insert into document
1420 ScDocument
& rDoc
= GetDoc();
1421 if( IsCellXF() && mpStyleSheet
)
1422 rDoc
.ApplyStyleAreaTab( nScCol1
, nScRow1
, nScCol2
, nScRow2
, nScTab
, *mpStyleSheet
);
1423 if( HasUsedFlags() )
1424 rDoc
.ApplyPatternAreaTab( nScCol1
, nScRow1
, nScCol2
, nScRow2
, nScTab
, rPattern
);
1428 /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot
& rRoot
,
1429 const ScAddress
& rScPos
, sal_uInt8 nFlags1
, sal_uInt8 nFlags2
, sal_uInt8 nFlags3
)
1431 /* Create an XF object and let it do the work. We will have access to its
1432 private members here. */
1433 XclImpXF
aXF( rRoot
);
1435 // no used flags available in BIFF2 (always true)
1436 aXF
.SetAllUsedFlags( true );
1438 // set the attributes
1439 aXF
.maProtection
.FillFromXF2( nFlags1
);
1440 aXF
.maAlignment
.FillFromXF2( nFlags3
);
1441 aXF
.maBorder
.FillFromXF2( nFlags3
);
1442 aXF
.maArea
.FillFromXF2( nFlags3
);
1443 aXF
.mnXclNumFmt
= ::extract_value
< sal_uInt16
>( nFlags2
, 0, 6 );
1444 aXF
.mnXclFont
= ::extract_value
< sal_uInt16
>( nFlags2
, 6, 2 );
1446 // write the attributes to the cell
1447 aXF
.ApplyPattern( rScPos
.Col(), rScPos
.Row(), rScPos
.Col(), rScPos
.Row(), rScPos
.Tab() );
1450 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags
)
1452 /* Notes about finding the mb***Used flags:
1453 - In cell XFs a *set* bit means a used attribute.
1454 - In style XFs a *cleared* bit means a used attribute.
1455 The mb***Used members always store true, if the attribute is used.
1456 The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1457 both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1459 mbProtUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_PROT
));
1460 mbFontUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_FONT
));
1461 mbFmtUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_VALFMT
));
1462 mbAlignUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_ALIGN
));
1463 mbBorderUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_BORDER
));
1464 mbAreaUsed
= (mbCellXF
== ::get_flag( nUsedFlags
, EXC_XF_DIFF_AREA
));
1467 XclImpStyle::XclImpStyle( const XclImpRoot
& rRoot
) :
1468 XclImpRoot( rRoot
),
1469 mnXfId( EXC_XF_NOTFOUND
),
1470 mnBuiltinId( EXC_STYLE_USERDEF
),
1471 mnLevel( EXC_STYLE_NOLEVEL
),
1475 mpStyleSheet( nullptr )
1479 void XclImpStyle::ReadStyle( XclImpStream
& rStrm
)
1481 OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3
);
1483 sal_uInt16 nXFIndex
;
1484 nXFIndex
= rStrm
.ReaduInt16();
1485 mnXfId
= nXFIndex
& EXC_STYLE_XFMASK
;
1486 mbBuiltin
= ::get_flag( nXFIndex
, EXC_STYLE_BUILTIN
);
1490 mnBuiltinId
= rStrm
.ReaduInt8();
1491 mnLevel
= rStrm
.ReaduInt8();
1495 maName
= (GetBiff() <= EXC_BIFF5
) ? rStrm
.ReadByteString( false ) : rStrm
.ReadUniString();
1496 // #i103281# check if this is a new built-in style introduced in XL2007
1497 if( (GetBiff() == EXC_BIFF8
) && (rStrm
.GetNextRecId() == EXC_ID_STYLEEXT
) && rStrm
.StartNextRecord() )
1499 sal_uInt8 nExtFlags
;
1501 nExtFlags
= rStrm
.ReaduInt8();
1502 mbBuiltin
= ::get_flag( nExtFlags
, EXC_STYLEEXT_BUILTIN
);
1503 mbCustom
= ::get_flag( nExtFlags
, EXC_STYLEEXT_CUSTOM
);
1504 mbHidden
= ::get_flag( nExtFlags
, EXC_STYLEEXT_HIDDEN
);
1507 rStrm
.Ignore( 1 ); // category
1508 mnBuiltinId
= rStrm
.ReaduInt8();
1509 mnLevel
= rStrm
.ReaduInt8();
1515 ScStyleSheet
* XclImpStyle::CreateStyleSheet()
1517 // #i1624# #i1768# ignore unnamed user styles
1518 if( !mpStyleSheet
&& (!maFinalName
.isEmpty()) )
1520 bool bCreatePattern
= false;
1521 XclImpXF
* pXF
= GetXFBuffer().GetXF( mnXfId
);
1523 bool bDefStyle
= mbBuiltin
&& (mnBuiltinId
== EXC_STYLE_NORMAL
);
1526 // set all flags to true to get all items in XclImpXF::CreatePattern()
1527 if( pXF
) pXF
->SetAllUsedFlags( true );
1528 // use existing "Default" style sheet
1529 mpStyleSheet
= static_cast< ScStyleSheet
* >( GetStyleSheetPool().Find(
1530 ScResId( STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
) );
1531 OSL_ENSURE( mpStyleSheet
, "XclImpStyle::CreateStyleSheet - Default style not found" );
1532 bCreatePattern
= true;
1536 /* #i103281# do not create another style sheet of the same name,
1537 if it exists already. This is needed to prevent that styles
1538 pasted from clipboard get duplicated over and over. */
1539 mpStyleSheet
= static_cast< ScStyleSheet
* >( GetStyleSheetPool().Find( maFinalName
, SfxStyleFamily::Para
) );
1542 mpStyleSheet
= &static_cast< ScStyleSheet
& >( GetStyleSheetPool().Make( maFinalName
, SfxStyleFamily::Para
, SfxStyleSearchBits::UserDefined
) );
1543 bCreatePattern
= true;
1547 // bDefStyle==true omits default pool items in CreatePattern()
1548 if( bCreatePattern
&& mpStyleSheet
&& pXF
)
1549 mpStyleSheet
->GetItemSet().Put( pXF
->CreatePattern( bDefStyle
).GetItemSet() );
1551 return mpStyleSheet
;
1554 void XclImpStyle::CreateUserStyle( const OUString
& rFinalName
)
1556 maFinalName
= rFinalName
;
1557 if( !IsBuiltin() || mbCustom
)
1561 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot
& rRoot
) :
1566 void XclImpXFBuffer::Initialize()
1569 maBuiltinStyles
.clear();
1570 maUserStyles
.clear();
1571 maStylesByXf
.clear();
1574 void XclImpXFBuffer::ReadXF( XclImpStream
& rStrm
)
1576 std::unique_ptr
<XclImpXF
> xXF
= std::make_unique
<XclImpXF
>(GetRoot());
1578 maXFList
.emplace_back(std::move(xXF
));
1581 void XclImpXFBuffer::ReadStyle( XclImpStream
& rStrm
)
1583 std::unique_ptr
<XclImpStyle
> xStyle(std::make_unique
<XclImpStyle
>(GetRoot()));
1584 xStyle
->ReadStyle(rStrm
);
1585 XclImpStyleList
& rStyleList
= (xStyle
->IsBuiltin() ? maBuiltinStyles
: maUserStyles
);
1586 rStyleList
.emplace_back(std::move(xStyle
));
1587 XclImpStyle
* pStyle
= rStyleList
.back().get();
1588 OSL_ENSURE( maStylesByXf
.count( pStyle
->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1589 maStylesByXf
[ pStyle
->GetXfId() ] = pStyle
;
1592 sal_uInt16
XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex
) const
1594 const XclImpXF
* pXF
= GetXF( nXFIndex
);
1595 return pXF
? pXF
->GetFontIndex() : EXC_FONT_NOTFOUND
;
1598 const XclImpFont
* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex
) const
1600 return GetFontBuffer().GetFont( GetFontIndex( nXFIndex
) );
1605 /** Functor for case-insensitive string comparison, usable in maps etc. */
1606 struct IgnoreCaseCompare
1608 bool operator()( std::u16string_view rName1
, std::u16string_view rName2
) const
1609 { return o3tl::compareToIgnoreAsciiCase( rName1
, rName2
) < 0; }
1614 void XclImpXFBuffer::CreateUserStyles()
1616 // calculate final names of all styles
1617 std::map
< OUString
, XclImpStyle
*, IgnoreCaseCompare
> aCellStyles
;
1618 std::vector
< XclImpStyle
* > aConflictNameStyles
;
1620 /* First, reserve style names that are built-in in Calc. This causes that
1621 imported cell styles get different unused names and thus do not try to
1622 overwrite these built-in styles. For BIFF4 workbooks (which contain a
1623 separate list of cell styles per sheet), reserve all existing styles if
1624 current sheet is not the first sheet (this styles buffer will be
1625 initialized again for every new sheet). This will create unique names
1626 for styles in different sheets with the same name. Assuming that the
1627 BIFF4W import filter is never used to import from clipboard... */
1628 bool bReserveAll
= (GetBiff() == EXC_BIFF4
) && (GetCurrScTab() > 0);
1629 SfxStyleSheetIterator
aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para
);
1630 OUString aStandardName
= ScResId( STR_STYLENAME_STANDARD
);
1631 for( SfxStyleSheetBase
* pStyleSheet
= aStyleIter
.First(); pStyleSheet
; pStyleSheet
= aStyleIter
.Next() )
1632 if( (pStyleSheet
->GetName() != aStandardName
) && (bReserveAll
|| !pStyleSheet
->IsUserDefined()) )
1633 if( aCellStyles
.count( pStyleSheet
->GetName() ) == 0 )
1634 aCellStyles
[ pStyleSheet
->GetName() ] = nullptr;
1636 /* Calculate names of built-in styles. Store styles with reserved names
1637 in the aConflictNameStyles list. */
1638 for( const auto& rxStyle
: maBuiltinStyles
)
1640 OUString aStyleName
= XclTools::GetBuiltInStyleName( rxStyle
->GetBuiltinId(), rxStyle
->GetName(), rxStyle
->GetLevel() );
1641 OSL_ENSURE( bReserveAll
|| (aCellStyles
.count( aStyleName
) == 0),
1642 "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1643 if( aCellStyles
.count( aStyleName
) > 0 )
1644 aConflictNameStyles
.push_back( rxStyle
.get() );
1646 aCellStyles
[ aStyleName
] = rxStyle
.get();
1649 /* Calculate names of user defined styles. Store styles with reserved
1650 names in the aConflictNameStyles list. */
1651 for( const auto& rxStyle
: maUserStyles
)
1653 // #i1624# #i1768# ignore unnamed user styles
1654 if( !rxStyle
->GetName().isEmpty() )
1656 if( aCellStyles
.count( rxStyle
->GetName() ) > 0 )
1657 aConflictNameStyles
.push_back( rxStyle
.get() );
1659 aCellStyles
[ rxStyle
->GetName() ] = rxStyle
.get();
1663 // find unused names for all styles with conflicting names
1664 for( XclImpStyle
* pStyle
: aConflictNameStyles
)
1666 OUString aUnusedName
;
1667 sal_Int32 nIndex
= 0;
1670 aUnusedName
= pStyle
->GetName() + " " + OUString::number( ++nIndex
);
1672 while( aCellStyles
.count( aUnusedName
) > 0 );
1673 aCellStyles
[ aUnusedName
] = pStyle
;
1676 // set final names and create user-defined and modified built-in cell styles
1677 for( auto& [rStyleName
, rpStyle
] : aCellStyles
)
1679 rpStyle
->CreateUserStyle( rStyleName
);
1682 ScStyleSheet
* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex
)
1684 XclImpStyleMap::iterator aIt
= maStylesByXf
.find( nXFIndex
);
1685 return (aIt
== maStylesByXf
.end()) ? nullptr : aIt
->second
->CreateStyleSheet();
1688 // Buffer for XF indexes in cells =============================================
1690 bool XclImpXFRange::Expand( SCROW nScRow
, const XclImpXFIndex
& rXFIndex
)
1692 if( maXFIndex
!= rXFIndex
)
1695 if( mnScRow2
+ 1 == nScRow
)
1700 if( mnScRow1
> 0 && (mnScRow1
- 1 == nScRow
) )
1709 bool XclImpXFRange::Expand( const XclImpXFRange
& rNextRange
)
1711 OSL_ENSURE( mnScRow2
< rNextRange
.mnScRow1
, "XclImpXFRange::Expand - rows out of order" );
1712 if( (maXFIndex
== rNextRange
.maXFIndex
) && (mnScRow2
+ 1 == rNextRange
.mnScRow1
) )
1714 mnScRow2
= rNextRange
.mnScRow2
;
1720 void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex
& rXFIndex
, const XclImpRoot
& rRoot
)
1722 // List should be empty when inserting the default column format.
1723 // Later explicit SetXF() calls will break up this range.
1724 OSL_ENSURE( maIndexList
.empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
1726 // insert a complete row range with one insert.
1727 maIndexList
.push_back( XclImpXFRange( 0, rRoot
.GetDoc().MaxRow(), rXFIndex
) );
1730 void XclImpXFRangeColumn::SetXF( SCROW nScRow
, const XclImpXFIndex
& rXFIndex
)
1732 XclImpXFRange
* pPrevRange
;
1733 XclImpXFRange
* pNextRange
;
1734 sal_uLong nNextIndex
;
1736 Find( pPrevRange
, pNextRange
, nNextIndex
, nScRow
);
1739 // try to overwrite XF (if row is contained in) or try to expand range
1742 if( pPrevRange
->Contains( nScRow
) ) // overwrite old XF
1744 if( rXFIndex
== pPrevRange
->maXFIndex
)
1747 SCROW nFirstScRow
= pPrevRange
->mnScRow1
;
1748 SCROW nLastScRow
= pPrevRange
->mnScRow2
;
1749 sal_uLong nIndex
= nNextIndex
- 1;
1750 XclImpXFRange
* pThisRange
= pPrevRange
;
1751 pPrevRange
= (nIndex
> 0 && nIndex
<= maIndexList
.size()) ? &maIndexList
[ nIndex
- 1 ] : nullptr;
1753 if( nFirstScRow
== nLastScRow
) // replace solely XF
1755 pThisRange
->maXFIndex
= rXFIndex
;
1756 TryConcatPrev( nNextIndex
); // try to concat. next with this
1757 TryConcatPrev( nIndex
); // try to concat. this with previous
1759 else if( nFirstScRow
== nScRow
) // replace first XF
1761 ++(pThisRange
->mnScRow1
);
1762 // try to concatenate with previous of this
1763 if( !pPrevRange
|| !pPrevRange
->Expand( nScRow
, rXFIndex
) )
1764 Insert( XclImpXFRange( nScRow
, rXFIndex
), nIndex
);
1766 else if( nLastScRow
== nScRow
) // replace last XF
1768 --(pThisRange
->mnScRow2
);
1769 if( !pNextRange
|| !pNextRange
->Expand( nScRow
, rXFIndex
) )
1770 Insert( XclImpXFRange( nScRow
, rXFIndex
), nNextIndex
);
1772 else // insert in the middle of the range
1774 pThisRange
->mnScRow1
= nScRow
+ 1;
1775 XclImpXFIndex
aXFIndex(pThisRange
->maXFIndex
);
1776 // List::Insert() moves entries towards end of list, so insert twice at nIndex
1777 Insert( XclImpXFRange( nScRow
, rXFIndex
), nIndex
);
1778 Insert( XclImpXFRange( nFirstScRow
, nScRow
- 1, aXFIndex
), nIndex
);
1782 else if( pPrevRange
->Expand( nScRow
, rXFIndex
) ) // try to expand
1784 TryConcatPrev( nNextIndex
); // try to concatenate next with expanded
1789 // try to expand next range
1790 if( pNextRange
&& pNextRange
->Expand( nScRow
, rXFIndex
) )
1794 Insert( XclImpXFRange( nScRow
, rXFIndex
), nNextIndex
);
1797 void XclImpXFRangeColumn::Insert(XclImpXFRange aXFRange
, sal_uLong nIndex
)
1799 maIndexList
.insert( maIndexList
.begin() + nIndex
, std::move(aXFRange
) );
1802 void XclImpXFRangeColumn::Find(
1803 XclImpXFRange
*& rpPrevRange
, XclImpXFRange
*& rpNextRange
,
1804 sal_uLong
& rnNextIndex
, SCROW nScRow
)
1807 // test whether list is empty
1808 if( maIndexList
.empty() )
1810 rpPrevRange
= rpNextRange
= nullptr;
1815 rpPrevRange
= &maIndexList
.front();
1816 rpNextRange
= &maIndexList
.back();
1818 // test whether row is at end of list (contained in or behind last range)
1819 // rpPrevRange will contain a possible existing row
1820 if( rpNextRange
->mnScRow1
<= nScRow
)
1822 rpPrevRange
= rpNextRange
;
1823 rpNextRange
= nullptr;
1824 rnNextIndex
= maIndexList
.size();
1828 // test whether row is at beginning of list (really before first range)
1829 if( nScRow
< rpPrevRange
->mnScRow1
)
1831 rpNextRange
= rpPrevRange
;
1832 rpPrevRange
= nullptr;
1837 // loop: find range entries before and after new row
1838 // break the loop if there is no more range between first and last -or-
1839 // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
1840 sal_uLong nPrevIndex
= 0;
1841 sal_uLong nMidIndex
;
1842 rnNextIndex
= maIndexList
.size() - 1;
1843 XclImpXFRange
* pMidRange
;
1844 while( ((rnNextIndex
- nPrevIndex
) > 1) && (rpPrevRange
->mnScRow2
< nScRow
) )
1846 nMidIndex
= (nPrevIndex
+ rnNextIndex
) / 2;
1847 pMidRange
= &maIndexList
[nMidIndex
];
1848 assert(pMidRange
&& "XclImpXFRangeColumn::Find - missing XF index range");
1849 if( nScRow
< pMidRange
->mnScRow1
) // row is really before pMidRange
1851 rpNextRange
= pMidRange
;
1852 rnNextIndex
= nMidIndex
;
1854 else // row is in or after pMidRange
1856 rpPrevRange
= pMidRange
;
1857 nPrevIndex
= nMidIndex
;
1861 // find next rpNextRange if rpPrevRange contains nScRow
1862 if( nScRow
<= rpPrevRange
->mnScRow2
)
1864 rnNextIndex
= nPrevIndex
+ 1;
1865 rpNextRange
= &maIndexList
[rnNextIndex
];
1869 void XclImpXFRangeColumn::TryConcatPrev( sal_uLong nIndex
)
1871 if( !nIndex
|| nIndex
>= maIndexList
.size() )
1874 XclImpXFRange
& prevRange
= maIndexList
[ nIndex
- 1 ];
1875 XclImpXFRange
& nextRange
= maIndexList
[ nIndex
];
1877 if( prevRange
.Expand( nextRange
) )
1878 maIndexList
.erase( maIndexList
.begin() + nIndex
);
1881 XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot
& rRoot
) :
1886 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1890 void XclImpXFRangeBuffer::Initialize()
1894 maHyperlinks
.clear();
1895 maMergeList
.RemoveAll();
1898 void XclImpXFRangeBuffer::SetXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
, XclImpXFInsertMode eMode
)
1900 SCCOL nScCol
= rScPos
.Col();
1901 SCROW nScRow
= rScPos
.Row();
1904 size_t nIndex
= static_cast< size_t >( nScCol
);
1905 if( maColumns
.size() <= nIndex
)
1906 maColumns
.resize( nIndex
+ 1 );
1907 if( !maColumns
[ nIndex
] )
1908 maColumns
[ nIndex
].emplace();
1909 // remember all Boolean cells, they will get 'Standard' number format
1910 maColumns
[ nIndex
]->SetXF( nScRow
, XclImpXFIndex( nXFIndex
, eMode
== xlXFModeBoolCell
) );
1912 // set "center across selection" and "fill" attribute for all following empty cells
1913 // ignore it on row default XFs
1914 if( eMode
== xlXFModeRow
)
1917 const XclImpXF
* pXF
= GetXFBuffer().GetXF( nXFIndex
);
1918 if( pXF
&& ((pXF
->GetHorAlign() == EXC_XF_HOR_CENTER_AS
) || (pXF
->GetHorAlign() == EXC_XF_HOR_FILL
)) )
1920 // expand last merged range if this attribute is set repeatedly
1921 ScRange
* pRange
= maMergeList
.empty() ? nullptr : &maMergeList
.back();
1922 if (pRange
&& (pRange
->aEnd
.Row() == nScRow
) && (pRange
->aEnd
.Col() + 1 == nScCol
) && (eMode
== xlXFModeBlank
))
1923 pRange
->aEnd
.IncCol();
1924 else if( eMode
!= xlXFModeBlank
) // do not merge empty cells
1925 maMergeList
.push_back( ScRange( nScCol
, nScRow
, 0 ) );
1929 void XclImpXFRangeBuffer::SetXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1931 SetXF( rScPos
, nXFIndex
, xlXFModeCell
);
1934 void XclImpXFRangeBuffer::SetBlankXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1936 SetXF( rScPos
, nXFIndex
, xlXFModeBlank
);
1939 void XclImpXFRangeBuffer::SetBoolXF( const ScAddress
& rScPos
, sal_uInt16 nXFIndex
)
1941 SetXF( rScPos
, nXFIndex
, xlXFModeBoolCell
);
1944 void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow
, sal_uInt16 nXFIndex
)
1946 size_t nIndex
= static_cast< size_t >( nScRow
);
1947 if( maRows
.size() <= nIndex
)
1948 maRows
.resize( nIndex
+ 1 );
1949 maRows
[ nIndex
].emplace(nXFIndex
);
1952 void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol
, sal_uInt16 nXFIndex
)
1954 // our array should not have values when creating the default column format.
1955 size_t nIndex
= static_cast< size_t >( nScCol
);
1956 if( maColumns
.size() <= nIndex
)
1957 maColumns
.resize( nIndex
+ 1 );
1958 OSL_ENSURE( !maColumns
[ nIndex
], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
1959 maColumns
[ nIndex
].emplace();
1960 maColumns
[ nIndex
]->SetDefaultXF( XclImpXFIndex( nXFIndex
), GetRoot());
1963 void XclImpXFRangeBuffer::SetBorderLine( const ScRange
& rRange
, SCTAB nScTab
, SvxBoxItemLine nLine
)
1965 SCCOL nFromScCol
= (nLine
== SvxBoxItemLine::RIGHT
) ? rRange
.aEnd
.Col() : rRange
.aStart
.Col();
1966 SCROW nFromScRow
= (nLine
== SvxBoxItemLine::BOTTOM
) ? rRange
.aEnd
.Row() : rRange
.aStart
.Row();
1967 ScDocument
& rDoc
= GetDoc();
1969 const SvxBoxItem
* pFromItem
=
1970 rDoc
.GetAttr( nFromScCol
, nFromScRow
, nScTab
, ATTR_BORDER
);
1971 const SvxBoxItem
* pToItem
=
1972 rDoc
.GetAttr( rRange
.aStart
.Col(), rRange
.aStart
.Row(), nScTab
, ATTR_BORDER
);
1974 SvxBoxItem
aNewItem( *pToItem
);
1975 aNewItem
.SetLine( pFromItem
->GetLine( nLine
), nLine
);
1976 rDoc
.ApplyAttr( rRange
.aStart
.Col(), rRange
.aStart
.Row(), nScTab
, aNewItem
);
1979 void XclImpXFRangeBuffer::SetHyperlink( const XclRange
& rXclRange
, const OUString
& rUrl
)
1981 maHyperlinks
.emplace_back( rXclRange
, rUrl
);
1984 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1
, SCROW nScRow1
, SCCOL nScCol2
, SCROW nScRow2
)
1986 if( (nScCol1
< nScCol2
) || (nScRow1
< nScRow2
) )
1987 maMergeList
.push_back( ScRange( nScCol1
, nScRow1
, 0, nScCol2
, nScRow2
, 0 ) );
1990 void XclImpXFRangeBuffer::Finalize()
1992 ScDocumentImport
& rDocImport
= GetDocImport();
1993 ScDocument
& rDoc
= rDocImport
.getDoc();
1994 SCTAB nScTab
= GetCurrScTab();
1997 for( SCROW nScRow
= 0; nScRow
< static_cast<SCROW
>(maRows
.size()); ++nScRow
)
1999 if (!maRows
[nScRow
])
2001 sal_uInt16 nXFIndex
= *maRows
[nScRow
];
2002 for( SCCOL nScCol
= 0; nScCol
< static_cast<SCCOL
>(maColumns
.size()); ++nScCol
)
2003 if (maColumns
[nScCol
])
2004 SetXF( ScAddress( nScCol
, nScRow
, 0 ), nXFIndex
, xlXFModeRow
);
2008 XclImpXFBuffer
& rXFBuffer
= GetXFBuffer();
2009 ScDocumentImport::Attrs aPendingAttrParam
;
2010 SCCOL pendingColStart
= -1;
2011 SCCOL pendingColEnd
= -1;
2013 for( auto& rxColumn
: maColumns
)
2015 // apply all cell styles of an existing column
2018 XclImpXFRangeColumn
& rColumn
= *rxColumn
;
2019 std::vector
<ScAttrEntry
> aAttrs
;
2020 aAttrs
.reserve(rColumn
.end() - rColumn
.begin());
2022 for (const auto& rStyle
: rColumn
)
2024 const XclImpXFIndex
& rXFIndex
= rStyle
.maXFIndex
;
2025 XclImpXF
* pXF
= rXFBuffer
.GetXF( rXFIndex
.GetXFIndex() );
2029 sal_uInt32 nForceScNumFmt
= rXFIndex
.IsBoolCell() ?
2030 GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND
;
2032 pXF
->ApplyPatternToAttrVector(aAttrs
, rStyle
.mnScRow1
, rStyle
.mnScRow2
, nForceScNumFmt
);
2035 if (aAttrs
.empty() || aAttrs
.back().nEndRow
!= rDoc
.MaxRow())
2038 aEntry
.nEndRow
= rDoc
.MaxRow();
2039 aEntry
.setScPatternAttr(&rDoc
.getCellAttributeHelper().getDefaultCellAttribute());
2040 aAttrs
.push_back(aEntry
);
2043 aAttrs
.shrink_to_fit();
2044 assert(aAttrs
.size() > 0);
2045 ScDocumentImport::Attrs aAttrParam
;
2046 aAttrParam
.mvData
.swap(aAttrs
);
2047 aAttrParam
.mbLatinNumFmtOnly
= false; // when unsure, set it to false.
2049 // Compress setting the attributes, set the same set in one call.
2050 if( pendingColStart
!= -1 && pendingColEnd
== nScCol
- 1 && aAttrParam
== aPendingAttrParam
)
2054 if( pendingColStart
!= -1 )
2055 rDocImport
.setAttrEntries(nScTab
, pendingColStart
, pendingColEnd
, std::move(aPendingAttrParam
));
2056 pendingColStart
= pendingColEnd
= nScCol
;
2057 aPendingAttrParam
= std::move( aAttrParam
);
2062 if( pendingColStart
!= -1 )
2063 rDocImport
.setAttrEntries(nScTab
, pendingColStart
, pendingColEnd
, std::move(aPendingAttrParam
));
2065 // insert hyperlink cells
2066 for( const auto& [rXclRange
, rUrl
] : maHyperlinks
)
2067 XclImpHyperlink::InsertUrl( GetRoot(), rXclRange
, rUrl
);
2069 // apply cell merging
2070 for ( size_t i
= 0, nRange
= maMergeList
.size(); i
< nRange
; ++i
)
2072 const ScRange
& rRange
= maMergeList
[ i
];
2073 const ScAddress
& rStart
= rRange
.aStart
;
2074 const ScAddress
& rEnd
= rRange
.aEnd
;
2075 bool bMultiCol
= rStart
.Col() != rEnd
.Col();
2076 bool bMultiRow
= rStart
.Row() != rEnd
.Row();
2077 // set correct right border
2079 SetBorderLine( rRange
, nScTab
, SvxBoxItemLine::RIGHT
);
2080 // set correct lower border
2082 SetBorderLine( rRange
, nScTab
, SvxBoxItemLine::BOTTOM
);
2084 if( bMultiCol
|| bMultiRow
)
2085 rDoc
.DoMerge( rStart
.Col(), rStart
.Row(), rEnd
.Col(), rEnd
.Row(), nScTab
);
2086 // #i93609# merged range in a single row: test if manual row height is needed
2089 bool bTextWrap
= rDoc
.GetAttr( rStart
, ATTR_LINEBREAK
)->GetValue();
2090 if( !bTextWrap
&& (rDoc
.GetCellType( rStart
) == CELLTYPE_EDIT
) )
2091 if (const EditTextObject
* pEditObj
= rDoc
.GetEditText(rStart
))
2092 bTextWrap
= pEditObj
->GetParagraphCount() > 1;
2094 GetOldRoot().pColRowBuff
->SetManualRowHeight( rStart
.Row() );
2099 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */