LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / excel / xistyle.cxx
blobc556b51ec60232e35538f5745fe155e74c8d62b0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
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>
55 #include <attrib.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>
69 #include <root.hxx>
70 #include <colrowst.hxx>
72 #include <string_view>
73 #include <vector>
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>
81 using ::std::vector;
82 using namespace ::com::sun::star;
84 typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE;
85 typedef ::std::vector< Color > ColorVec;
87 namespace {
89 class PaletteIndex : public XIndexAccess_BASE
91 public:
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());
116 private:
117 ColorVec maColor;
122 void
123 XclImpPalette::ExportPalette()
125 SfxObjectShell* pDocShell = mrRoot.GetDocShell();
126 if(!pDocShell)
127 return;
129 // copy values in color palette
130 sal_Int16 nColors = maColorTable.size();
131 ColorVec aColors;
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 );
137 if ( xProps.is() )
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 )
169 sal_uInt16 nCount;
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 );
182 Color aColor;
183 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
185 rStrm >> aColor;
186 maColorTable[ nIndex ] = aColor;
188 ExportPalette();
191 // FONT record - font information =============================================
192 XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
193 XclImpRoot( rRoot ),
194 mbHasCharSet( false ),
195 mbHasWstrn( true ),
196 mbHasAsian( false ),
197 mbHasCmplx( false )
199 SetAllUsedFlags( false );
202 XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
203 XclImpRoot( rRoot )
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 )
216 maData = rFontData;
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();
235 GuessScriptType();
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 )
249 switch( GetBiff() )
251 case EXC_BIFF2:
252 ReadFontData2( rStrm );
253 ReadFontName2( rStrm );
254 break;
255 case EXC_BIFF3:
256 case EXC_BIFF4:
257 ReadFontData2( rStrm );
258 ReadFontColor( rStrm );
259 ReadFontName2( rStrm );
260 break;
261 case EXC_BIFF5:
262 ReadFontData5( rStrm );
263 ReadFontName2( rStrm );
264 break;
265 case EXC_BIFF8:
266 ReadFontData5( rStrm );
267 ReadFontName8( rStrm );
268 break;
269 default:
270 DBG_ERROR_BIFF();
271 return;
273 GuessScriptType();
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 )
286 return;
288 rStrm.Ignore( 64 );
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();
294 rStrm.Ignore( 3 );
295 sal_uInt32 nColor = rStrm.ReaduInt32();
296 rStrm.Ignore( 4 );
297 sal_uInt32 nFontFlags1 = rStrm.ReaduInt32();
298 rStrm.Ignore( 4 ); //nFontFlags2
299 sal_uInt32 nFontFlags3 = rStrm.ReaduInt32();
300 rStrm.Ignore( 18 );
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 )
327 // Font item
328 if( mbFontNameUsed )
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;
342 default: break;
344 SvxFontItem aFontItem( eFtFamily , maData.maName, OUString(), ePitch, eTempTextEnc, ATTR_FONT );
346 // set only for valid script types
347 if( mbHasWstrn )
348 PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO );
349 if( mbHasAsian )
350 PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK );
351 if( mbHasCmplx )
352 PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL );
355 // Font height (for all script types)
356 if( mbHeightUsed )
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
369 if( mbColorUsed )
370 PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
372 // Font weight (for all script types)
373 if( mbWeightUsed )
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 );
381 // Font underline
382 if( mbUnderlUsed )
384 SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
385 PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE );
388 // Font posture (for all script types)
389 if( mbItalicUsed )
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
398 if( mbStrikeUsed )
399 PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
400 if( mbOutlineUsed )
401 PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
402 if( mbShadowUsed )
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 ) );
409 #undef PUTITEM
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 )
421 sal_uInt16 nFlags;
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 )
436 sal_uInt16 nFlags;
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();
446 rStrm.Ignore( 1 );
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()
472 mbHasWstrn = true;
473 mbHasAsian = mbHasCmplx = false;
475 // find the script types for which the font contains characters
476 OutputDevice* pPrinter = GetPrinter();
477 if(!pPrinter)
478 return;
480 vcl::Font aFont( maData.maName, Size( 0, 10 ) );
481 FontCharMapRef xFontCharMap;
483 pPrinter->SetFont( aFont );
484 if( !pPrinter->GetFontCharMap( xFontCharMap ) )
485 return;
487 // CJK fonts
488 mbHasAsian =
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
502 // CTL fonts
503 mbHasCmplx =
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
512 // Western fonts
513 mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || xFontCharMap->HasChar( 'A' );
516 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
517 XclImpRoot( rRoot ),
518 maFont4( rRoot ),
519 maCtrlFont( rRoot )
521 Initialize();
523 // default font for form controls without own font information
524 XclFontData aCtrlFontData;
525 switch( GetBiff() )
527 case EXC_BIFF2:
528 case EXC_BIFF3:
529 case EXC_BIFF4:
530 case EXC_BIFF5:
531 aCtrlFontData.maName = "Helv";
532 aCtrlFontData.mnHeight = 160;
533 aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
534 break;
535 case EXC_BIFF8:
536 aCtrlFontData.maName = "Tahoma";
537 aCtrlFontData.mnHeight = 160;
538 aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
539 break;
540 default:
541 DBG_ERROR_BIFF();
543 maCtrlFont.SetFontData( aCtrlFontData, false );
546 void XclImpFontBuffer::Initialize()
548 maFontList.clear();
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. */
564 if (nFontIndex == 4)
565 return &maFont4;
567 if (nFontIndex < 4)
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 ),
631 XclImpRoot( rRoot ),
632 mnNextXclIdx( 0 )
636 void XclImpNumFmtBuffer::Initialize()
638 maIndexMap.clear();
639 mnNextXclIdx = 0;
640 InitializeImport(); // base class
643 void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
645 OUString aFormat;
646 switch( GetBiff() )
648 case EXC_BIFF2:
649 case EXC_BIFF3:
650 aFormat = rStrm.ReadByteString( false );
651 break;
653 case EXC_BIFF4:
654 rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
655 aFormat = rStrm.ReadByteString( false );
656 break;
658 case EXC_BIFF5:
659 mnNextXclIdx = rStrm.ReaduInt16();
660 aFormat = rStrm.ReadByteString( false );
661 break;
663 case EXC_BIFF8:
664 mnNextXclIdx = rStrm.ReaduInt16();
665 aFormat = rStrm.ReadUniString();
666 break;
668 default:
669 DBG_ERROR_BIFF();
670 return;
673 if( mnNextXclIdx < 0xFFFF )
675 InsertFormat( mnNextXclIdx, aFormat );
676 ++mnNextXclIdx;
680 sal_uInt16 XclImpNumFmtBuffer::ReadCFFormat( XclImpStream& rStrm, bool bIFmt )
682 // internal number format ?
683 if(bIFmt)
685 rStrm.Ignore(1);
686 sal_uInt8 nIndex;
687 nIndex = rStrm.ReaduInt8();
688 return nIndex;
690 else
692 OUString aFormat = rStrm.ReadUniString();
693 InsertFormat( mnNextXclIdx, aFormat );
694 ++mnNextXclIdx;
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
707 sal_uInt32 nKey;
708 if( !rNumFmt.maFormat.isEmpty() )
710 OUString aFormat( rNumFmt.maFormat );
711 sal_Int32 nCheckPos;
712 SvNumFormatType nType = SvNumFormatType::DEFINED;
713 rFormatter.PutandConvertEntry( aFormat, nCheckPos,
714 nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage, false);
716 else
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 );
827 // indent
828 sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
829 ScfTools::PutItem( rItemSet, ScIndentItem( nScIndent ), bSkipPoolDefs );
831 // shrink to fit
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 );
930 mbDiagUsed = false;
933 bool XclImpCellBorder::HasAnyOuterBorder() const
935 return
936 (mbLeftUsed && (mnLeftLine != EXC_LINE_NONE)) ||
937 (mbRightUsed && (mnRightLine != EXC_LINE_NONE)) ||
938 (mbTopUsed && (mnTopLine != EXC_LINE_NONE)) ||
939 (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE));
942 namespace {
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 ] =
949 // outer width, type
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 )
967 return false;
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 ]) );
975 return true;
978 } // namespace
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 );
996 if( !mbDiagUsed )
997 return;
999 SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
1000 SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
1001 ::editeng::SvxBorderLine aLine;
1002 if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
1004 if( mbDiagTLtoBR )
1005 aTLBRItem.SetLine( &aLine );
1006 if( mbDiagBLtoTR )
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) )
1072 mbPattUsed = false;
1076 void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
1078 if( !mbPattUsed ) // colors may be both unused in cond. formats
1079 return;
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 );
1088 else
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 ),
1102 mnXclNumFmt( 0 ),
1103 mnXclFont( 0 )
1107 XclImpXF::~XclImpXF()
1111 void XclImpXF::ReadXF2( XclImpStream& rStrm )
1113 sal_uInt8 nReadFont, nReadNumFmt, nFlags;
1114 nReadFont = rStrm.ReaduInt8();
1115 rStrm.Ignore( 1 );
1116 nReadNumFmt = rStrm.ReaduInt8();
1117 nFlags = rStrm.ReaduInt8();
1119 // XF type always cell, no parent, used flags always true
1120 SetAllUsedFlags( true );
1122 // attributes
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 )
1133 sal_uInt32 nBorder;
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 ) );
1148 // attributes
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 )
1159 sal_uInt32 nBorder;
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 ) );
1174 // attributes
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 ) );
1199 // attributes
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 ) );
1224 // attributes
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 )
1233 switch( GetBiff() )
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 )
1246 if( mpPattern )
1247 return *mpPattern;
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. */
1263 if( pParentXF )
1265 if( !mbProtUsed )
1266 mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection);
1267 if( !mbFontUsed )
1268 mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont);
1269 if( !mbFmtUsed )
1270 mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt);
1271 if( !mbAlignUsed )
1272 mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment);
1273 if( !mbBorderUsed )
1274 mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder);
1275 if( !mbAreaUsed )
1276 mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea);
1280 // cell protection
1281 if( mbProtUsed )
1282 maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
1284 // font
1285 if( mbFontUsed )
1286 GetFontBuffer().FillToItemSet( rItemSet, XclFontItemType::Cell, mnXclFont, bSkipPoolDefs );
1288 // value format
1289 if( mbFmtUsed )
1291 GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
1292 // Trace occurrences of Windows date formats
1293 GetTracer().TraceDates( mnXclNumFmt );
1296 // alignment
1297 if( mbAlignUsed )
1298 maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
1300 // border
1301 if( mbBorderUsed )
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 );
1309 // area
1310 if( mbAreaUsed )
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);
1335 return *mpPattern;
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
1342 CreatePattern();
1343 ScPatternAttr& rPat = *mpPattern;
1345 // insert into document
1346 ScDocument& rDoc = GetDoc();
1348 if (IsCellXF())
1350 if (mpStyleSheet)
1352 // Apply style sheet. Don't clear the direct formats.
1353 rPat.SetStyleSheet(mpStyleSheet, false);
1355 else
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
1360 // all.
1361 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
1362 if (pStylePool)
1364 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>(
1365 pStylePool->Find(
1366 ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para));
1368 if (pStyleSheet)
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())
1384 return;
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.
1390 bHasGap = true;
1392 if (!rAttrs.empty() && rAttrs.back().nEndRow + 1 < nRow1)
1393 bHasGap = true;
1395 if (bHasGap)
1397 // Fill this gap with the default pattern.
1398 ScAttrEntry aEntry;
1399 aEntry.nEndRow = nRow1 - 1;
1400 aEntry.pPattern = rDoc.GetDefPattern();
1401 rAttrs.push_back(aEntry);
1404 ScAttrEntry 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,
1412 SCTAB nScTab )
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 ),
1470 mbBuiltin( false ),
1471 mbCustom( false ),
1472 mbHidden( false ),
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 );
1486 if( mbBuiltin )
1488 mnBuiltinId = rStrm.ReaduInt8();
1489 mnLevel = rStrm.ReaduInt8();
1491 else
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;
1498 rStrm.Ignore( 12 );
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 );
1503 if( mbBuiltin )
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);
1522 if( bDefStyle )
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;
1532 else
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 ) );
1538 if( !mpStyleSheet )
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 )
1556 CreateStyleSheet();
1559 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
1560 XclImpRoot( rRoot )
1564 void XclImpXFBuffer::Initialize()
1566 maXFList.clear();
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());
1575 xXF->ReadXF(rStrm);
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 ) );
1601 namespace {
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; }
1610 } // namespace
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() );
1643 else
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() );
1656 else
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 )
1676 if( rpStyle )
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 )
1691 return false;
1693 if( mnScRow2 + 1 == nScRow )
1695 ++mnScRow2;
1696 return true;
1698 if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) )
1700 --mnScRow1;
1701 return true;
1704 return false;
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;
1713 return true;
1715 return false;
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 );
1736 // previous range:
1737 // try to overwrite XF (if row is contained in) or try to expand range
1738 if( pPrevRange )
1740 if( pPrevRange->Contains( nScRow ) ) // overwrite old XF
1742 if( rXFIndex == pPrevRange->maXFIndex )
1743 return;
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 );
1777 return;
1779 else if( pPrevRange->Expand( nScRow, rXFIndex ) ) // try to expand
1781 TryConcatPrev( nNextIndex ); // try to concatenate next with expanded
1782 return;
1786 // try to expand next range
1787 if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) )
1788 return;
1790 // create new range
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;
1808 rnNextIndex = 0;
1809 return;
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();
1822 return;
1825 // test whether row is at beginning of list (really before first range)
1826 if( nScRow < rpPrevRange->mnScRow1 )
1828 rpNextRange = rpPrevRange;
1829 rpPrevRange = nullptr;
1830 rnNextIndex = 0;
1831 return;
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() )
1869 return;
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 ) :
1879 XclImpRoot( rRoot )
1883 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1887 void XclImpXFRangeBuffer::Initialize()
1889 maColumns.clear();
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();
1899 // set cell XF's
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 )
1911 return;
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();
1990 // apply patterns
1991 XclImpXFBuffer& rXFBuffer = GetXFBuffer();
1992 ScDocumentImport::Attrs aPendingAttrParam;
1993 SCCOL pendingColStart = -1;
1994 SCCOL pendingColEnd = -1;
1995 SCCOL nScCol = 0;
1996 for( const auto& rxColumn : maColumns )
1998 // apply all cell styles of an existing column
1999 if( rxColumn )
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() );
2010 if (!pXF)
2011 continue;
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())
2021 ScAttrEntry aEntry;
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 )
2035 ++pendingColEnd;
2036 else
2038 if( pendingColStart != -1 )
2039 rDocImport.setAttrEntries(nScTab, pendingColStart, pendingColEnd, std::move(aPendingAttrParam));
2040 pendingColStart = pendingColEnd = nScCol;
2041 aPendingAttrParam = std::move( aAttrParam );
2044 ++nScCol;
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
2062 if( bMultiCol )
2063 SetBorderLine( rRange, nScTab, SvxBoxItemLine::RIGHT );
2064 // set correct lower border
2065 if( bMultiRow )
2066 SetBorderLine( rRange, nScTab, SvxBoxItemLine::BOTTOM );
2067 // do merge
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
2071 if( !bMultiRow )
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;
2077 if( bTextWrap )
2078 GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
2083 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */