1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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 <vcl/fontcharmap.hxx>
50 #include <vcl/outdev.hxx>
51 #include <document.hxx>
52 #include <documentimport.hxx>
53 #include <docpool.hxx>
54 #include <attrib.hxx>
55 #include <patattr.hxx>
56 #include <stlpool.hxx>
57 #include <stlsheet.hxx>
58 #include <globstr.hrc>
59 #include <scresid.hxx>
60 #include <attarray.hxx>
61 #include <xladdress.hxx>
62 #include <xlcontent.hxx>
63 #include <xltracer.hxx>
64 #include <xltools.hxx>
65 #include <xistream.hxx>
66 #include <xicontent.hxx>
67
68 #include <root.hxx>
69 #include <colrowst.hxx>
70
71 #include <vector>
72
73 #include <cppuhelper/implbase.hxx>
74 #include <com/sun/star/container/XIndexAccess.hpp>
75 #include <com/sun/star/beans/XPropertySet.hpp>
76
77 using ::std::vector;
78 using namespace ::com::sun::star;
79
80 typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE;
81 typedef ::std::vector< Color > ColorVec;
82
83 class PaletteIndex : public XIndexAccess_BASE
84 {
85 public:
PaletteIndex(const ColorVec & rColorTable)86 explicit PaletteIndex( const ColorVec& rColorTable ) : maColor( rColorTable ) {}
87
88 // Methods XIndexAccess
getCount()89 virtual ::sal_Int32 SAL_CALL getCount() override
90 {
91 return maColor.size();
92 }
93
getByIndex(::sal_Int32 Index)94 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
95 {
96 //--Index; // apparently the palette is already 1 based
97 return uno::makeAny( sal_Int32( maColor[ Index ] ) );
98 }
99
100 // Methods XElementAccess
getElementType()101 virtual uno::Type SAL_CALL getElementType() override
102 {
103 return ::cppu::UnoType<sal_Int32>::get();
104 }
hasElements()105 virtual sal_Bool SAL_CALL hasElements() override
106 {
107 return (!maColor.empty());
108 }
109
110 private:
111 ColorVec maColor;
112 };
113
114 void
ExportPalette()115 XclImpPalette::ExportPalette()
116 {
117 if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
118 {
119 // copy values in color palette
120 sal_Int16 nColors = maColorTable.size();
121 ColorVec aColors;
122 aColors.resize( nColors );
123 for( sal_uInt16 nIndex = 0; nIndex < nColors; ++nIndex )
124 aColors[ nIndex ] = GetColor( nIndex );
125
126 uno::Reference< beans::XPropertySet > xProps( pDocShell->GetModel(), uno::UNO_QUERY );
127 if ( xProps.is() )
128 {
129 uno::Reference< container::XIndexAccess > xIndex( new PaletteIndex( aColors ) );
130 xProps->setPropertyValue( "ColorPalette", uno::makeAny( xIndex ) );
131 }
132 }
133
134 }
135 // PALETTE record - color information =========================================
136
XclImpPalette(const XclImpRoot & rRoot)137 XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) :
138 XclDefaultPalette( rRoot ), mrRoot( rRoot )
139 {
140 }
141
Initialize()142 void XclImpPalette::Initialize()
143 {
144 maColorTable.clear();
145 }
146
GetColor(sal_uInt16 nXclIndex) const147 Color XclImpPalette::GetColor( sal_uInt16 nXclIndex ) const
148 {
149 if( nXclIndex >= EXC_COLOR_USEROFFSET )
150 {
151 sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET;
152 if( nIx < maColorTable.size() )
153 return maColorTable[ nIx ];
154 }
155 return GetDefColor( nXclIndex );
156 }
157
ReadPalette(XclImpStream & rStrm)158 void XclImpPalette::ReadPalette( XclImpStream& rStrm )
159 {
160 sal_uInt16 nCount;
161 nCount = rStrm.ReaduInt16();
162
163 const size_t nMinRecordSize = 4;
164 const size_t nMaxRecords = rStrm.GetRecLeft() / nMinRecordSize;
165 if (nCount > nMaxRecords)
166 {
167 SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
168 " max possible entries, but " << nCount << " claimed, truncating");
169 nCount = nMaxRecords;
170 }
171
172 maColorTable.resize( nCount );
173 Color aColor;
174 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
175 {
176 rStrm >> aColor;
177 maColorTable[ nIndex ] = aColor;
178 }
179 ExportPalette();
180 }
181
182 // FONT record - font information =============================================
XclImpFont(const XclImpRoot & rRoot)183 XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
184 XclImpRoot( rRoot ),
185 mbHasCharSet( false ),
186 mbHasWstrn( true ),
187 mbHasAsian( false ),
188 mbHasCmplx( false )
189 {
190 SetAllUsedFlags( false );
191 }
192
XclImpFont(const XclImpRoot & rRoot,const XclFontData & rFontData)193 XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
194 XclImpRoot( rRoot )
195 {
196 SetFontData( rFontData, false );
197 }
198
SetAllUsedFlags(bool bUsed)199 void XclImpFont::SetAllUsedFlags( bool bUsed )
200 {
201 mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed =
202 mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed;
203 }
204
SetFontData(const XclFontData & rFontData,bool bHasCharSet)205 void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet )
206 {
207 maData = rFontData;
208 mbHasCharSet = bHasCharSet;
209 if( !maData.maStyle.isEmpty() )
210 {
211 if( SfxObjectShell* pDocShell = GetDocShell() )
212 {
213 if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
214 pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
215 {
216 if( const FontList* pFontList = pInfoItem->GetFontList() )
217 {
218 FontMetric aFontMetric( pFontList->Get( maData.maName, maData.maStyle ) );
219 maData.SetScWeight( aFontMetric.GetWeight() );
220 maData.SetScPosture( aFontMetric.GetItalic() );
221 }
222 }
223 }
224 maData.maStyle.clear();
225 }
226 GuessScriptType();
227 SetAllUsedFlags( true );
228 }
229
GetFontEncoding() const230 rtl_TextEncoding XclImpFont::GetFontEncoding() const
231 {
232 // #i63105# use text encoding from FONT record
233 // #i67768# BIFF2-BIFF4 FONT records do not contain character set
234 rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding();
235 return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc;
236 }
237
ReadFont(XclImpStream & rStrm)238 void XclImpFont::ReadFont( XclImpStream& rStrm )
239 {
240 switch( GetBiff() )
241 {
242 case EXC_BIFF2:
243 ReadFontData2( rStrm );
244 ReadFontName2( rStrm );
245 break;
246 case EXC_BIFF3:
247 case EXC_BIFF4:
248 ReadFontData2( rStrm );
249 ReadFontColor( rStrm );
250 ReadFontName2( rStrm );
251 break;
252 case EXC_BIFF5:
253 ReadFontData5( rStrm );
254 ReadFontName2( rStrm );
255 break;
256 case EXC_BIFF8:
257 ReadFontData5( rStrm );
258 ReadFontName8( rStrm );
259 break;
260 default:
261 DBG_ERROR_BIFF();
262 return;
263 }
264 GuessScriptType();
265 SetAllUsedFlags( true );
266 }
267
ReadEfont(XclImpStream & rStrm)268 void XclImpFont::ReadEfont( XclImpStream& rStrm )
269 {
270 ReadFontColor( rStrm );
271 }
272
ReadCFFontBlock(XclImpStream & rStrm)273 void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm )
274 {
275 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
276 if( GetBiff() != EXC_BIFF8 )
277 return;
278
279 rStrm.Ignore( 64 );
280 sal_uInt32 nHeight = rStrm.ReaduInt32();
281 sal_uInt32 nStyle = rStrm.ReaduInt32();
282 sal_uInt16 nWeight = rStrm.ReaduInt16();
283 rStrm.Ignore( 2 ); //nEscapem
284 sal_uInt8 nUnderl = rStrm.ReaduInt8();
285 rStrm.Ignore( 3 );
286 sal_uInt32 nColor = rStrm.ReaduInt32();
287 rStrm.Ignore( 4 );
288 sal_uInt32 nFontFlags1 = rStrm.ReaduInt32();
289 rStrm.Ignore( 4 ); //nFontFlags2
290 sal_uInt32 nFontFlags3 = rStrm.ReaduInt32();
291 rStrm.Ignore( 18 );
292
293 if( (mbHeightUsed = (nHeight <= 0x7FFF)) )
294 maData.mnHeight = static_cast< sal_uInt16 >( nHeight );
295 if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) )
296 maData.mnWeight = nWeight;
297 if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) )
298 maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE );
299 if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) )
300 maData.mnUnderline = nUnderl;
301 if( (mbColorUsed = (nColor <= 0x7FFF)) )
302 maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) );
303 if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) )
304 maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT );
305 }
306
FillToItemSet(SfxItemSet & rItemSet,XclFontItemType eType,bool bSkipPoolDefs) const307 void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const
308 {
309 // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
310 bool bEE = eType != XclFontItemType::Cell;
311
312 // item = the item to put into the item set
313 // sc_which = the Calc Which-ID of the item
314 // ee_which = the edit engine Which-ID of the item
315 #define PUTITEM( item, sc_which, ee_which ) \
316 ScfTools::PutItem( rItemSet, item, (bEE ? (static_cast<sal_uInt16>(ee_which)) : (sc_which)), bSkipPoolDefs )
317
318 // Font item
319 if( mbFontNameUsed )
320 {
321 rtl_TextEncoding eFontEnc = maData.GetFontEncoding();
322 rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ?
323 ScfTools::GetSystemTextEncoding() : eFontEnc;
324
325 //add corresponding pitch for FontFamily
326 FontPitch ePitch = PITCH_DONTKNOW;
327 FontFamily eFtFamily = maData.GetScFamily( GetTextEncoding() );
328 switch( eFtFamily ) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx
329 {
330 case FAMILY_ROMAN: ePitch = PITCH_VARIABLE; break;
331 case FAMILY_SWISS: ePitch = PITCH_VARIABLE; break;
332 case FAMILY_MODERN: ePitch = PITCH_FIXED; break;
333 default: break;
334 }
335 SvxFontItem aFontItem( eFtFamily , maData.maName, EMPTY_OUSTRING, ePitch, eTempTextEnc, ATTR_FONT );
336
337 // set only for valid script types
338 if( mbHasWstrn )
339 PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO );
340 if( mbHasAsian )
341 PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK );
342 if( mbHasCmplx )
343 PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL );
344 }
345
346 // Font height (for all script types)
347 if( mbHeightUsed )
348 {
349 sal_Int32 nHeight = maData.mnHeight;
350 if( bEE && (eType != XclFontItemType::HeaderFooter) ) // do not convert header/footer height
351 nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH; // 1 in == 72 pt
352
353 SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT );
354 PUTITEM( aHeightItem, ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT );
355 PUTITEM( aHeightItem, ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK );
356 PUTITEM( aHeightItem, ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL );
357 }
358
359 // Font color - pass AUTO_COL to item
360 if( mbColorUsed )
361 PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
362
363 // Font weight (for all script types)
364 if( mbWeightUsed )
365 {
366 SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT );
367 PUTITEM( aWeightItem, ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT );
368 PUTITEM( aWeightItem, ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK );
369 PUTITEM( aWeightItem, ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL );
370 }
371
372 // Font underline
373 if( mbUnderlUsed )
374 {
375 SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
376 PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE );
377 }
378
379 // Font posture (for all script types)
380 if( mbItalicUsed )
381 {
382 SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE );
383 PUTITEM( aPostItem, ATTR_FONT_POSTURE, EE_CHAR_ITALIC );
384 PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK );
385 PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL );
386 }
387
388 // Boolean attributes crossed out, contoured, shadowed
389 if( mbStrikeUsed )
390 PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
391 if( mbOutlineUsed )
392 PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
393 if( mbShadowUsed )
394 PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW );
395
396 // Super-/subscript: only on edit engine objects
397 if( mbEscapemUsed && bEE )
398 rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) );
399
400 #undef PUTITEM
401 }
402
WriteFontProperties(ScfPropertySet & rPropSet,XclFontPropSetType eType,const Color * pFontColor) const403 void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet,
404 XclFontPropSetType eType, const Color* pFontColor ) const
405 {
406 GetFontPropSetHelper().WriteFontProperties(
407 rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor );
408 }
409
ReadFontData2(XclImpStream & rStrm)410 void XclImpFont::ReadFontData2( XclImpStream& rStrm )
411 {
412 sal_uInt16 nFlags;
413 maData.mnHeight = rStrm.ReaduInt16();
414 nFlags = rStrm.ReaduInt16();
415
416 maData.mnWeight = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL );
417 maData.mnUnderline = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE );
418 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
419 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
420 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
421 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
422 mbHasCharSet = false;
423 }
424
ReadFontData5(XclImpStream & rStrm)425 void XclImpFont::ReadFontData5( XclImpStream& rStrm )
426 {
427 sal_uInt16 nFlags;
428
429 maData.mnHeight = rStrm.ReaduInt16();
430 nFlags = rStrm.ReaduInt16();
431 ReadFontColor( rStrm );
432 maData.mnWeight = rStrm.ReaduInt16();
433 maData.mnEscapem = rStrm.ReaduInt16();
434 maData.mnUnderline = rStrm.ReaduInt8();
435 maData.mnFamily = rStrm.ReaduInt8();
436 maData.mnCharSet = rStrm.ReaduInt8();
437 rStrm.Ignore( 1 );
438
439 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
440 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
441 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
442 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
443 mbHasCharSet = true;
444 }
445
ReadFontColor(XclImpStream & rStrm)446 void XclImpFont::ReadFontColor( XclImpStream& rStrm )
447 {
448 maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() );
449 }
450
ReadFontName2(XclImpStream & rStrm)451 void XclImpFont::ReadFontName2( XclImpStream& rStrm )
452 {
453 maData.maName = rStrm.ReadByteString( false );
454 }
455
ReadFontName8(XclImpStream & rStrm)456 void XclImpFont::ReadFontName8( XclImpStream& rStrm )
457 {
458 maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() );
459 }
460
GuessScriptType()461 void XclImpFont::GuessScriptType()
462 {
463 mbHasWstrn = true;
464 mbHasAsian = mbHasCmplx = false;
465
466 // find the script types for which the font contains characters
467 if( OutputDevice* pPrinter = GetPrinter() )
468 {
469 vcl::Font aFont( maData.maName, Size( 0, 10 ) );
470 FontCharMapRef xFontCharMap;
471
472 pPrinter->SetFont( aFont );
473 if( pPrinter->GetFontCharMap( xFontCharMap ) )
474 {
475 // CJK fonts
476 mbHasAsian =
477 xFontCharMap->HasChar( 0x3041 ) || // 3040-309F: Hiragana
478 xFontCharMap->HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
479 xFontCharMap->HasChar( 0x3111 ) || // 3100-312F: Bopomofo
480 xFontCharMap->HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
481 xFontCharMap->HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
482 xFontCharMap->HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
483 xFontCharMap->HasChar( 0x4E01 ) || // 4E00-9FFF: CJK Unified Ideographs
484 xFontCharMap->HasChar( 0x7E01 ) || // 4E00-9FFF: CJK Unified Ideographs
485 xFontCharMap->HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
486 xFontCharMap->HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
487 xFontCharMap->HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
488 xFontCharMap->HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
489 xFontCharMap->HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
490 // CTL fonts
491 mbHasCmplx =
492 xFontCharMap->HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
493 xFontCharMap->HasChar( 0x0631 ) || // 0600-06FF: Arabic
494 xFontCharMap->HasChar( 0x0721 ) || // 0700-074F: Syriac
495 xFontCharMap->HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
496 xFontCharMap->HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
497 xFontCharMap->HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
498 xFontCharMap->HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
499 xFontCharMap->HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
500 // Western fonts
501 mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || xFontCharMap->HasChar( 'A' );
502 }
503 }
504 }
505
XclImpFontBuffer(const XclImpRoot & rRoot)506 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
507 XclImpRoot( rRoot ),
508 maFont4( rRoot ),
509 maCtrlFont( rRoot )
510 {
511 Initialize();
512
513 // default font for form controls without own font information
514 XclFontData aCtrlFontData;
515 switch( GetBiff() )
516 {
517 case EXC_BIFF2:
518 case EXC_BIFF3:
519 case EXC_BIFF4:
520 case EXC_BIFF5:
521 aCtrlFontData.maName = "Helv";
522 aCtrlFontData.mnHeight = 160;
523 aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
524 break;
525 case EXC_BIFF8:
526 aCtrlFontData.maName = "Tahoma";
527 aCtrlFontData.mnHeight = 160;
528 aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
529 break;
530 default:
531 DBG_ERROR_BIFF();
532 }
533 maCtrlFont.SetFontData( aCtrlFontData, false );
534 }
535
Initialize()536 void XclImpFontBuffer::Initialize()
537 {
538 maFontList.clear();
539
540 // application font for column width calculation, later filled with first font from font list
541 XclFontData aAppFontData;
542 aAppFontData.maName = "Arial";
543 aAppFontData.mnHeight = 200;
544 aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL;
545 UpdateAppFont( aAppFontData, false );
546 }
547
GetFont(sal_uInt16 nFontIndex) const548 const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const
549 {
550 /* Font with index 4 is not stored in an Excel file, but used e.g. by
551 BIFF5 form pushbutton objects. It is the bold default font.
552 This also means that entries above 4 are out by one in the list. */
553
554 if (nFontIndex == 4)
555 return &maFont4;
556
557 if (nFontIndex < 4)
558 {
559 // Font ID is zero-based when it's less than 4.
560 return nFontIndex >= maFontList.size() ? nullptr : &maFontList[nFontIndex];
561 }
562
563 // Font ID is greater than 4. It is now 1-based.
564 return nFontIndex > maFontList.size() ? nullptr : &maFontList[nFontIndex-1];
565 }
566
ReadFont(XclImpStream & rStrm)567 void XclImpFontBuffer::ReadFont( XclImpStream& rStrm )
568 {
569 maFontList.emplace_back( GetRoot() );
570 XclImpFont& rFont = maFontList.back();
571 rFont.ReadFont( rStrm );
572
573 if( maFontList.size() == 1 )
574 {
575 UpdateAppFont( rFont.GetFontData(), rFont.HasCharSet() );
576 // #i71033# set text encoding from application font, if CODEPAGE is missing
577 SetAppFontEncoding( rFont.GetFontEncoding() );
578 }
579 }
580
ReadEfont(XclImpStream & rStrm)581 void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm )
582 {
583 if( !maFontList.empty() )
584 maFontList.back().ReadEfont( rStrm );
585 }
586
FillToItemSet(SfxItemSet & rItemSet,XclFontItemType eType,sal_uInt16 nFontIdx,bool bSkipPoolDefs) const587 void XclImpFontBuffer::FillToItemSet(
588 SfxItemSet& rItemSet, XclFontItemType eType,
589 sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const
590 {
591 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
592 pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs );
593 }
594
WriteFontProperties(ScfPropertySet & rPropSet,XclFontPropSetType eType,sal_uInt16 nFontIdx,const Color * pFontColor) const595 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet,
596 XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const
597 {
598 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
599 pFont->WriteFontProperties( rPropSet, eType, pFontColor );
600 }
601
WriteDefaultCtrlFontProperties(ScfPropertySet & rPropSet) const602 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const
603 {
604 maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL );
605 }
606
UpdateAppFont(const XclFontData & rFontData,bool bHasCharSet)607 void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet )
608 {
609 maAppFont = rFontData;
610 // #i3006# Calculate the width of '0' from first font and current printer.
611 SetCharWidth( maAppFont );
612
613 // font 4 is bold font 0
614 XclFontData aFont4Data( maAppFont );
615 aFont4Data.mnWeight = EXC_FONTWGHT_BOLD;
616 maFont4.SetFontData( aFont4Data, bHasCharSet );
617 }
618
619 // FORMAT record - number formats =============================================
620
XclImpNumFmtBuffer(const XclImpRoot & rRoot)621 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) :
622 XclNumFmtBuffer( rRoot ),
623 XclImpRoot( rRoot ),
624 mnNextXclIdx( 0 )
625 {
626 }
627
Initialize()628 void XclImpNumFmtBuffer::Initialize()
629 {
630 maIndexMap.clear();
631 mnNextXclIdx = 0;
632 InitializeImport(); // base class
633 }
634
ReadFormat(XclImpStream & rStrm)635 void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
636 {
637 OUString aFormat;
638 switch( GetBiff() )
639 {
640 case EXC_BIFF2:
641 case EXC_BIFF3:
642 aFormat = rStrm.ReadByteString( false );
643 break;
644
645 case EXC_BIFF4:
646 rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
647 aFormat = rStrm.ReadByteString( false );
648 break;
649
650 case EXC_BIFF5:
651 mnNextXclIdx = rStrm.ReaduInt16();
652 aFormat = rStrm.ReadByteString( false );
653 break;
654
655 case EXC_BIFF8:
656 mnNextXclIdx = rStrm.ReaduInt16();
657 aFormat = rStrm.ReadUniString();
658 break;
659
660 default:
661 DBG_ERROR_BIFF();
662 return;
663 }
664
665 if( mnNextXclIdx < 0xFFFF )
666 {
667 InsertFormat( mnNextXclIdx, aFormat );
668 ++mnNextXclIdx;
669 }
670 }
671
ReadCFFormat(XclImpStream & rStrm,bool bIFmt)672 sal_uInt16 XclImpNumFmtBuffer::ReadCFFormat( XclImpStream& rStrm, bool bIFmt )
673 {
674 // internal number format ?
675 if(bIFmt)
676 {
677 rStrm.Ignore(1);
678 sal_uInt8 nIndex;
679 nIndex = rStrm.ReaduInt8();
680 return nIndex;
681 }
682 else
683 {
684 OUString aFormat = rStrm.ReadUniString();
685 InsertFormat( mnNextXclIdx, aFormat );
686 ++mnNextXclIdx;
687 return mnNextXclIdx - 1;
688 }
689 }
690
CreateScFormats()691 void XclImpNumFmtBuffer::CreateScFormats()
692 {
693 OSL_ENSURE( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
694
695 SvNumberFormatter& rFormatter = GetFormatter();
696 for( const auto& [rXclNumFmt, rNumFmt] : GetFormatMap() )
697 {
698 // insert/convert the Excel number format
699 sal_Int32 nCheckPos;
700 SvNumFormatType nType = SvNumFormatType::DEFINED;
701 sal_uInt32 nKey;
702 if( !rNumFmt.maFormat.isEmpty() )
703 {
704 OUString aFormat( rNumFmt.maFormat );
705 rFormatter.PutandConvertEntry( aFormat, nCheckPos,
706 nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage, false);
707 }
708 else
709 nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage );
710
711 // insert the resulting format key into the Excel->Calc index map
712 maIndexMap[ rXclNumFmt ] = nKey;
713 }
714 }
715
GetScFormat(sal_uInt16 nXclNumFmt) const716 sal_uInt32 XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const
717 {
718 XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt );
719 return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND;
720 }
721
FillToItemSet(SfxItemSet & rItemSet,sal_uInt16 nXclNumFmt,bool bSkipPoolDefs) const722 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const
723 {
724 sal_uInt32 nScNumFmt = GetScFormat( nXclNumFmt );
725 if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND )
726 nScNumFmt = GetStdScNumFmt();
727 FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs );
728 }
729
FillScFmtToItemSet(SfxItemSet & rItemSet,sal_uInt32 nScNumFmt,bool bSkipPoolDefs) const730 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, sal_uInt32 nScNumFmt, bool bSkipPoolDefs ) const
731 {
732 OSL_ENSURE( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
733 ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
734 if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, false ) == SfxItemState::SET )
735 ScGlobal::AddLanguage( rItemSet, GetFormatter() );
736 }
737
738 // XF, STYLE record - Cell formatting =========================================
739
FillFromXF2(sal_uInt8 nNumFmt)740 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt )
741 {
742 mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED );
743 mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN );
744 }
745
FillFromXF3(sal_uInt16 nProt)746 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt )
747 {
748 mbLocked = ::get_flag( nProt, EXC_XF_LOCKED );
749 mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN );
750 }
751
FillToItemSet(SfxItemSet & rItemSet,bool bSkipPoolDefs) const752 void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
753 {
754 ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs );
755 }
756
FillFromXF2(sal_uInt8 nFlags)757 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags )
758 {
759 mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 );
760 }
761
FillFromXF3(sal_uInt16 nAlign)762 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign )
763 {
764 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
765 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); // new in BIFF3
766 }
767
FillFromXF4(sal_uInt16 nAlign)768 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign )
769 {
770 FillFromXF3( nAlign );
771 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 ); // new in BIFF4
772 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 ); // new in BIFF4
773 }
774
FillFromXF5(sal_uInt16 nAlign)775 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign )
776 {
777 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
778 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
779 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
780 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 );
781 }
782
FillFromXF8(sal_uInt16 nAlign,sal_uInt16 nMiscAttrib)783 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
784 {
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 mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 ); // new in BIFF8
789 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
790 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK ); // new in BIFF8
791 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 ); // new in BIFF8
792 }
793
FillFromCF(sal_uInt16 nAlign,sal_uInt16 nMiscAttrib)794 void XclImpCellAlign::FillFromCF( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
795 {
796 mnHorAlign = extract_value< sal_uInt8 >( nAlign, 0, 3 );
797 mbLineBreak = get_flag< sal_uInt8 >( nAlign, EXC_XF_LINEBREAK );
798 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
799 mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 );
800 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 );
801 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK );
802 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 );
803 }
804
FillToItemSet(SfxItemSet & rItemSet,const XclImpFont * pFont,bool bSkipPoolDefs) const805 void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const
806 {
807 // horizontal alignment
808 ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs );
809 ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD ), bSkipPoolDefs );
810
811 // text wrap (#i74508# always if vertical alignment is justified or distributed)
812 bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB);
813 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs );
814
815 // vertical alignment
816 ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs );
817 ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD ), bSkipPoolDefs );
818
819 // indent
820 sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
821 ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs );
822
823 // shrink to fit
824 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs );
825
826 // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
827 sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient );
828 bool bStacked = (nXclRot == EXC_ROT_STACKED);
829 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs );
830 // set an angle in the range from -90 to 90 degrees
831 sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 );
832 ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs );
833 // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
834 bool bAsianVert = bStacked && pFont && pFont->HasAsianChars();
835 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs );
836
837 // CTL text direction
838 ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs );
839 }
840
XclImpCellBorder()841 XclImpCellBorder::XclImpCellBorder()
842 {
843 SetUsedFlags( false, false );
844 }
845
SetUsedFlags(bool bOuterUsed,bool bDiagUsed)846 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed )
847 {
848 mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed;
849 mbDiagUsed = bDiagUsed;
850 }
851
FillFromXF2(sal_uInt8 nFlags)852 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags )
853 {
854 mnLeftLine = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
855 mnRightLine = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
856 mnTopLine = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE, EXC_LINE_THIN, EXC_LINE_NONE );
857 mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE );
858 mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK;
859 SetUsedFlags( true, false );
860 }
861
FillFromXF3(sal_uInt32 nBorder)862 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder )
863 {
864 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
865 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 8, 3 );
866 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder, 16, 3 );
867 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 24, 3 );
868 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 3, 5 );
869 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 11, 5 );
870 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 );
871 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 27, 5 );
872 SetUsedFlags( true, false );
873 }
874
FillFromXF5(sal_uInt32 nBorder,sal_uInt32 nArea)875 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea )
876 {
877 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
878 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 3, 3 );
879 mnBottomLine = ::extract_value< sal_uInt8 >( nArea, 22, 3 );
880 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 6, 3 );
881 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 9, 7 );
882 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 16, 7 );
883 mnBottomColor = ::extract_value< sal_uInt16 >( nArea, 25, 7 );
884 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 23, 7 );
885 SetUsedFlags( true, false );
886 }
887
FillFromXF8(sal_uInt32 nBorder1,sal_uInt32 nBorder2)888 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
889 {
890 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder1, 0, 4 );
891 mnRightLine = ::extract_value< sal_uInt8 >( nBorder1, 4, 4 );
892 mnTopLine = ::extract_value< sal_uInt8 >( nBorder1, 8, 4 );
893 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder1, 12, 4 );
894 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 );
895 mnRightColor = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 );
896 mnTopColor = ::extract_value< sal_uInt16 >( nBorder2, 0, 7 );
897 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2, 7, 7 );
898 mbDiagTLtoBR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR );
899 mbDiagBLtoTR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR );
900 if( mbDiagTLtoBR || mbDiagBLtoTR )
901 {
902 mnDiagLine = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 );
903 mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 );
904 }
905 SetUsedFlags( true, true );
906 }
907
FillFromCF8(sal_uInt16 nLineStyle,sal_uInt32 nLineColor,sal_uInt32 nFlags)908 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags )
909 {
910 mnLeftLine = ::extract_value< sal_uInt8 >( nLineStyle, 0, 4 );
911 mnRightLine = ::extract_value< sal_uInt8 >( nLineStyle, 4, 4 );
912 mnTopLine = ::extract_value< sal_uInt8 >( nLineStyle, 8, 4 );
913 mnBottomLine = ::extract_value< sal_uInt8 >( nLineStyle, 12, 4 );
914 mnLeftColor = ::extract_value< sal_uInt16 >( nLineColor, 0, 7 );
915 mnRightColor = ::extract_value< sal_uInt16 >( nLineColor, 7, 7 );
916 mnTopColor = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 );
917 mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 );
918 mbLeftUsed = !::get_flag( nFlags, EXC_CF_BORDER_LEFT );
919 mbRightUsed = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT );
920 mbTopUsed = !::get_flag( nFlags, EXC_CF_BORDER_TOP );
921 mbBottomUsed = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM );
922 mbDiagUsed = false;
923 }
924
HasAnyOuterBorder() const925 bool XclImpCellBorder::HasAnyOuterBorder() const
926 {
927 return
928 (mbLeftUsed && (mnLeftLine != EXC_LINE_NONE)) ||
929 (mbRightUsed && (mnRightLine != EXC_LINE_NONE)) ||
930 (mbTopUsed && (mnTopLine != EXC_LINE_NONE)) ||
931 (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE));
932 }
933
934 namespace {
935
936 /** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
lclConvertBorderLine(::editeng::SvxBorderLine & rLine,const XclImpPalette & rPalette,sal_uInt8 nXclLine,sal_uInt16 nXclColor)937 bool lclConvertBorderLine( ::editeng::SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor )
938 {
939 static const sal_uInt16 ppnLineParam[][ 4 ] =
940 {
941 // outer width, type
942 { 0, table::BorderLineStyle::SOLID }, // 0 = none
943 { EXC_BORDER_THIN, table::BorderLineStyle::SOLID }, // 1 = thin
944 { EXC_BORDER_MEDIUM, table::BorderLineStyle::SOLID }, // 2 = medium
945 { EXC_BORDER_THIN, table::BorderLineStyle::FINE_DASHED }, // 3 = dashed
946 { EXC_BORDER_THIN, table::BorderLineStyle::DOTTED }, // 4 = dotted
947 { EXC_BORDER_THICK, table::BorderLineStyle::SOLID }, // 5 = thick
948 { EXC_BORDER_THICK, table::BorderLineStyle::DOUBLE_THIN }, // 6 = double
949 { EXC_BORDER_HAIR, table::BorderLineStyle::SOLID }, // 7 = hair
950 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASHED }, // 8 = med dash
951 { EXC_BORDER_THIN, table::BorderLineStyle::DASH_DOT }, // 9 = thin dashdot
952 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT }, // A = med dashdot
953 { EXC_BORDER_THIN, table::BorderLineStyle::DASH_DOT_DOT }, // B = thin dashdotdot
954 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT_DOT }, // C = med dashdotdot
955 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT } // D = med slant dashdot
956 };
957
958 if( nXclLine == EXC_LINE_NONE )
959 return false;
960 if( nXclLine >= SAL_N_ELEMENTS( ppnLineParam ) )
961 nXclLine = EXC_LINE_THIN;
962
963 rLine.SetColor( rPalette.GetColor( nXclColor ) );
964 rLine.SetWidth( ppnLineParam[ nXclLine ][ 0 ] );
965 rLine.SetBorderLineStyle( static_cast< SvxBorderLineStyle>(
966 ppnLineParam[ nXclLine ][ 1 ]) );
967 return true;
968 }
969
970 } // namespace
971
FillToItemSet(SfxItemSet & rItemSet,const XclImpPalette & rPalette,bool bSkipPoolDefs) const972 void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
973 {
974 if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed )
975 {
976 SvxBoxItem aBoxItem( ATTR_BORDER );
977 ::editeng::SvxBorderLine aLine;
978 if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) )
979 aBoxItem.SetLine( &aLine, SvxBoxItemLine::LEFT );
980 if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) )
981 aBoxItem.SetLine( &aLine, SvxBoxItemLine::RIGHT );
982 if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) )
983 aBoxItem.SetLine( &aLine, SvxBoxItemLine::TOP );
984 if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) )
985 aBoxItem.SetLine( &aLine, SvxBoxItemLine::BOTTOM );
986 ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs );
987 }
988 if( mbDiagUsed )
989 {
990 SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
991 SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
992 ::editeng::SvxBorderLine aLine;
993 if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
994 {
995 if( mbDiagTLtoBR )
996 aTLBRItem.SetLine( &aLine );
997 if( mbDiagBLtoTR )
998 aBLTRItem.SetLine( &aLine );
999 }
1000 ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs );
1001 ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs );
1002 }
1003 }
1004
XclImpCellArea()1005 XclImpCellArea::XclImpCellArea()
1006 {
1007 SetUsedFlags( false );
1008 }
1009
SetUsedFlags(bool bUsed)1010 void XclImpCellArea::SetUsedFlags( bool bUsed )
1011 {
1012 mbForeUsed = mbBackUsed = mbPattUsed = bUsed;
1013 }
1014
FillFromXF2(sal_uInt8 nFlags)1015 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags )
1016 {
1017 mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE );
1018 mnForeColor = EXC_COLOR_BIFF2_BLACK;
1019 mnBackColor = EXC_COLOR_BIFF2_WHITE;
1020 SetUsedFlags( true );
1021 }
1022
FillFromXF3(sal_uInt16 nArea)1023 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea )
1024 {
1025 mnPattern = ::extract_value< sal_uInt8 >( nArea, 0, 6 );
1026 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 6, 5 );
1027 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 );
1028 SetUsedFlags( true );
1029 }
1030
FillFromXF5(sal_uInt32 nArea)1031 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea )
1032 {
1033 mnPattern = ::extract_value< sal_uInt8 >( nArea, 16, 6 );
1034 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
1035 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
1036 SetUsedFlags( true );
1037 }
1038
FillFromXF8(sal_uInt32 nBorder2,sal_uInt16 nArea)1039 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea )
1040 {
1041 mnPattern = ::extract_value< sal_uInt8 >( nBorder2, 26, 6 );
1042 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
1043 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
1044 SetUsedFlags( true );
1045 }
1046
FillFromCF8(sal_uInt16 nPattern,sal_uInt16 nColor,sal_uInt32 nFlags)1047 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags )
1048 {
1049 mnForeColor = ::extract_value< sal_uInt16 >( nColor, 0, 7 );
1050 mnBackColor = ::extract_value< sal_uInt16 >( nColor, 7, 7 );
1051 mnPattern = ::extract_value< sal_uInt8 >( nPattern, 10, 6 );
1052 mbForeUsed = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR );
1053 mbBackUsed = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR );
1054 mbPattUsed = !::get_flag( nFlags, EXC_CF_AREA_PATTERN );
1055
1056 if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) )
1057 {
1058 mnForeColor = mnBackColor;
1059 mnPattern = EXC_PATT_SOLID;
1060 mbForeUsed = mbPattUsed = true;
1061 }
1062 else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) )
1063 {
1064 mbPattUsed = false;
1065 }
1066 }
1067
FillToItemSet(SfxItemSet & rItemSet,const XclImpPalette & rPalette,bool bSkipPoolDefs) const1068 void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
1069 {
1070 if( mbPattUsed ) // colors may be both unused in cond. formats
1071 {
1072 SvxBrushItem aBrushItem( ATTR_BACKGROUND );
1073
1074 // do not use IsTransparent() - old Calc filter writes tranparency with different color indexes
1075 if( mnPattern == EXC_PATT_NONE )
1076 {
1077 aBrushItem.SetColor( COL_TRANSPARENT );
1078 }
1079 else
1080 {
1081 Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) );
1082 Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) );
1083 aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) );
1084 }
1085
1086 ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs );
1087 }
1088 }
1089
XclImpXF(const XclImpRoot & rRoot)1090 XclImpXF::XclImpXF( const XclImpRoot& rRoot ) :
1091 XclXFBase( true ), // default is cell XF
1092 XclImpRoot( rRoot ),
1093 mpStyleSheet( nullptr ),
1094 mnXclNumFmt( 0 ),
1095 mnXclFont( 0 )
1096 {
1097 }
1098
~XclImpXF()1099 XclImpXF::~XclImpXF()
1100 {
1101 }
1102
ReadXF2(XclImpStream & rStrm)1103 void XclImpXF::ReadXF2( XclImpStream& rStrm )
1104 {
1105 sal_uInt8 nReadFont, nReadNumFmt, nFlags;
1106 nReadFont = rStrm.ReaduInt8();
1107 rStrm.Ignore( 1 );
1108 nReadNumFmt = rStrm.ReaduInt8();
1109 nFlags = rStrm.ReaduInt8();
1110
1111 // XF type always cell, no parent, used flags always true
1112 SetAllUsedFlags( true );
1113
1114 // attributes
1115 maProtection.FillFromXF2( nReadNumFmt );
1116 mnXclFont = nReadFont;
1117 mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK;
1118 maAlignment.FillFromXF2( nFlags );
1119 maBorder.FillFromXF2( nFlags );
1120 maArea.FillFromXF2( nFlags );
1121 }
1122
ReadXF3(XclImpStream & rStrm)1123 void XclImpXF::ReadXF3( XclImpStream& rStrm )
1124 {
1125 sal_uInt32 nBorder;
1126 sal_uInt16 nTypeProt, nAlign, nArea;
1127 sal_uInt8 nReadFont, nReadNumFmt;
1128 nReadFont = rStrm.ReaduInt8();
1129 nReadNumFmt = rStrm.ReaduInt8();
1130 nTypeProt = rStrm.ReaduInt16();
1131 nAlign = rStrm.ReaduInt16();
1132 nArea = rStrm.ReaduInt16();
1133 nBorder = rStrm.ReaduInt32();
1134
1135 // XF type/parent, attribute used flags
1136 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); // new in BIFF3
1137 mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 ); // new in BIFF3
1138 SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) );
1139
1140 // attributes
1141 maProtection.FillFromXF3( nTypeProt );
1142 mnXclFont = nReadFont;
1143 mnXclNumFmt = nReadNumFmt;
1144 maAlignment.FillFromXF3( nAlign );
1145 maBorder.FillFromXF3( nBorder );
1146 maArea.FillFromXF3( nArea ); // new in BIFF3
1147 }
1148
ReadXF4(XclImpStream & rStrm)1149 void XclImpXF::ReadXF4( XclImpStream& rStrm )
1150 {
1151 sal_uInt32 nBorder;
1152 sal_uInt16 nTypeProt, nAlign, nArea;
1153 sal_uInt8 nReadFont, nReadNumFmt;
1154 nReadFont = rStrm.ReaduInt8();
1155 nReadNumFmt = rStrm.ReaduInt8();
1156 nTypeProt = rStrm.ReaduInt16();
1157 nAlign = rStrm.ReaduInt16();
1158 nArea = rStrm.ReaduInt16();
1159 nBorder = rStrm.ReaduInt32();
1160
1161 // XF type/parent, attribute used flags
1162 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1163 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1164 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1165
1166 // attributes
1167 maProtection.FillFromXF3( nTypeProt );
1168 mnXclFont = nReadFont;
1169 mnXclNumFmt = nReadNumFmt;
1170 maAlignment.FillFromXF4( nAlign );
1171 maBorder.FillFromXF3( nBorder );
1172 maArea.FillFromXF3( nArea );
1173 }
1174
ReadXF5(XclImpStream & rStrm)1175 void XclImpXF::ReadXF5( XclImpStream& rStrm )
1176 {
1177 sal_uInt32 nArea, nBorder;
1178 sal_uInt16 nTypeProt, nAlign;
1179 mnXclFont = rStrm.ReaduInt16();
1180 mnXclNumFmt = rStrm.ReaduInt16();
1181 nTypeProt = rStrm.ReaduInt16();
1182 nAlign = rStrm.ReaduInt16();
1183 nArea = rStrm.ReaduInt32();
1184 nBorder = rStrm.ReaduInt32();
1185
1186 // XF type/parent, attribute used flags
1187 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1188 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1189 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1190
1191 // attributes
1192 maProtection.FillFromXF3( nTypeProt );
1193 maAlignment.FillFromXF5( nAlign );
1194 maBorder.FillFromXF5( nBorder, nArea );
1195 maArea.FillFromXF5( nArea );
1196 }
1197
ReadXF8(XclImpStream & rStrm)1198 void XclImpXF::ReadXF8( XclImpStream& rStrm )
1199 {
1200 sal_uInt32 nBorder1, nBorder2;
1201 sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea;
1202 mnXclFont = rStrm.ReaduInt16();
1203 mnXclNumFmt = rStrm.ReaduInt16();
1204 nTypeProt = rStrm.ReaduInt16();
1205 nAlign = rStrm.ReaduInt16();
1206 nMiscAttrib = rStrm.ReaduInt16();
1207 nBorder1 = rStrm.ReaduInt32();
1208 nBorder2 = rStrm.ReaduInt32( );
1209 nArea = rStrm.ReaduInt16();
1210
1211 // XF type/parent, attribute used flags
1212 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1213 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1214 SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
1215
1216 // attributes
1217 maProtection.FillFromXF3( nTypeProt );
1218 maAlignment.FillFromXF8( nAlign, nMiscAttrib );
1219 maBorder.FillFromXF8( nBorder1, nBorder2 );
1220 maArea.FillFromXF8( nBorder2, nArea );
1221 }
1222
ReadXF(XclImpStream & rStrm)1223 void XclImpXF::ReadXF( XclImpStream& rStrm )
1224 {
1225 switch( GetBiff() )
1226 {
1227 case EXC_BIFF2: ReadXF2( rStrm ); break;
1228 case EXC_BIFF3: ReadXF3( rStrm ); break;
1229 case EXC_BIFF4: ReadXF4( rStrm ); break;
1230 case EXC_BIFF5: ReadXF5( rStrm ); break;
1231 case EXC_BIFF8: ReadXF8( rStrm ); break;
1232 default: DBG_ERROR_BIFF();
1233 }
1234 }
1235
CreatePattern(bool bSkipPoolDefs)1236 const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs )
1237 {
1238 if( mpPattern.get() )
1239 return *mpPattern;
1240
1241 // create new pattern attribute set
1242 mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) );
1243 SfxItemSet& rItemSet = mpPattern->GetItemSet();
1244 XclImpXF* pParentXF = IsCellXF() ? GetXFBuffer().GetXF( mnParent ) : nullptr;
1245
1246 // parent cell style
1247 if( IsCellXF() && !mpStyleSheet )
1248 {
1249 mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent );
1250
1251 /* Enables mb***Used flags, if the formatting attributes differ from
1252 the passed XF record. In cell XFs Excel uses the cell attributes,
1253 if they differ from the parent style XF.
1254 ...or if the respective flag is not set in parent style XF. */
1255 if( pParentXF )
1256 {
1257 if( !mbProtUsed )
1258 mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection);
1259 if( !mbFontUsed )
1260 mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont);
1261 if( !mbFmtUsed )
1262 mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt);
1263 if( !mbAlignUsed )
1264 mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment);
1265 if( !mbBorderUsed )
1266 mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder);
1267 if( !mbAreaUsed )
1268 mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea);
1269 }
1270 }
1271
1272 // cell protection
1273 if( mbProtUsed )
1274 maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
1275
1276 // font
1277 if( mbFontUsed )
1278 GetFontBuffer().FillToItemSet( rItemSet, XclFontItemType::Cell, mnXclFont, bSkipPoolDefs );
1279
1280 // value format
1281 if( mbFmtUsed )
1282 {
1283 GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
1284 // Trace occurrences of Windows date formats
1285 GetTracer().TraceDates( mnXclNumFmt );
1286 }
1287
1288 // alignment
1289 if( mbAlignUsed )
1290 maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
1291
1292 // border
1293 if( mbBorderUsed )
1294 {
1295 maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1296 GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR ||
1297 maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR ||
1298 maBorder.mnBottomLine > EXC_LINE_HAIR );
1299 }
1300
1301 // area
1302 if( mbAreaUsed )
1303 {
1304 maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1305 GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE &&
1306 maArea.mnPattern != EXC_PATT_SOLID);
1307 }
1308
1309 /* #i38709# Decide which rotation reference mode to use. If any outer
1310 border line of the cell is set (either explicitly or via cell style),
1311 and the cell contents are rotated, set rotation reference to bottom of
1312 cell. This causes the borders to be painted rotated with the text. */
1313 if( mbAlignUsed || mbBorderUsed )
1314 {
1315 SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD;
1316 const XclImpCellAlign* pAlign = mbAlignUsed ? &maAlignment : (pParentXF ? &pParentXF->maAlignment : nullptr);
1317 const XclImpCellBorder* pBorder = mbBorderUsed ? &maBorder : (pParentXF ? &pParentXF->maBorder : nullptr);
1318 if( pAlign && pBorder && (0 < pAlign->mnRotation) && (pAlign->mnRotation <= 180) && pBorder->HasAnyOuterBorder() )
1319 eRotateMode = SVX_ROTATE_MODE_BOTTOM;
1320 ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs );
1321 }
1322
1323 // Excel's cell margins are different from Calc's default margins.
1324 SvxMarginItem aItem(40, 40, 40, 40, ATTR_MARGIN);
1325 ScfTools::PutItem(rItemSet, aItem, bSkipPoolDefs);
1326
1327 return *mpPattern;
1328 }
1329
ApplyPatternToAttrVector(std::vector<ScAttrEntry> & rAttrs,SCROW nRow1,SCROW nRow2,sal_uInt32 nForceScNumFmt)1330 void XclImpXF::ApplyPatternToAttrVector(
1331 std::vector<ScAttrEntry>& rAttrs, SCROW nRow1, SCROW nRow2, sal_uInt32 nForceScNumFmt)
1332 {
1333 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1334 CreatePattern();
1335 ScPatternAttr& rPat = *mpPattern;
1336
1337 // insert into document
1338 ScDocument& rDoc = GetDoc();
1339
1340 if (IsCellXF())
1341 {
1342 if (mpStyleSheet)
1343 {
1344 // Apply style sheet. Don't clear the direct formats.
1345 rPat.SetStyleSheet(mpStyleSheet, false);
1346 }
1347 else
1348 {
1349 // When the cell format is not associated with any style, use the
1350 // 'Default' style. Some buggy XLS docs generated by apps other
1351 // than Excel (such as 1C) may not have any built-in styles at
1352 // all.
1353 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
1354 if (pStylePool)
1355 {
1356 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>(
1357 pStylePool->Find(
1358 ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para));
1359
1360 if (pStyleSheet)
1361 rPat.SetStyleSheet(pStyleSheet, false);
1362 }
1363
1364 }
1365 }
1366
1367 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
1368 {
1369 ScPatternAttr aNumPat(rDoc.GetPool());
1370 GetNumFmtBuffer().FillScFmtToItemSet(aNumPat.GetItemSet(), nForceScNumFmt);
1371 rPat.GetItemSet().Put(aNumPat.GetItemSet());
1372 }
1373
1374 // Make sure we skip unnamed styles.
1375 if (rPat.GetStyleName())
1376 {
1377 // Check for a gap between the last entry and this one.
1378 bool bHasGap = false;
1379 if (rAttrs.empty() && nRow1 > 0)
1380 // First attribute range doesn't start at row 0.
1381 bHasGap = true;
1382
1383 if (!rAttrs.empty() && rAttrs.back().nEndRow + 1 < nRow1)
1384 bHasGap = true;
1385
1386 if (bHasGap)
1387 {
1388 // Fill this gap with the default pattern.
1389 ScAttrEntry aEntry;
1390 aEntry.nEndRow = nRow1 - 1;
1391 aEntry.pPattern = rDoc.GetDefPattern();
1392 rAttrs.push_back(aEntry);
1393 }
1394
1395 ScAttrEntry aEntry;
1396 aEntry.nEndRow = nRow2;
1397 aEntry.pPattern = &rDoc.GetPool()->Put(rPat);
1398 rAttrs.push_back(aEntry);
1399 }
1400 }
1401
ApplyPattern(SCCOL nScCol1,SCROW nScRow1,SCCOL nScCol2,SCROW nScRow2,SCTAB nScTab)1402 void XclImpXF::ApplyPattern(
1403 SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2,
1404 SCTAB nScTab )
1405 {
1406 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1407 const ScPatternAttr& rPattern = CreatePattern();
1408
1409 // insert into document
1410 ScDocument& rDoc = GetDoc();
1411 if( IsCellXF() && mpStyleSheet )
1412 rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet );
1413 if( HasUsedFlags() )
1414 rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern );
1415
1416 }
1417
ApplyPatternForBiff2CellFormat(const XclImpRoot & rRoot,const ScAddress & rScPos,sal_uInt8 nFlags1,sal_uInt8 nFlags2,sal_uInt8 nFlags3)1418 /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot& rRoot,
1419 const ScAddress& rScPos, sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 )
1420 {
1421 /* Create an XF object and let it do the work. We will have access to its
1422 private members here. */
1423 XclImpXF aXF( rRoot );
1424
1425 // no used flags available in BIFF2 (always true)
1426 aXF.SetAllUsedFlags( true );
1427
1428 // set the attributes
1429 aXF.maProtection.FillFromXF2( nFlags1 );
1430 aXF.maAlignment.FillFromXF2( nFlags3 );
1431 aXF.maBorder.FillFromXF2( nFlags3 );
1432 aXF.maArea.FillFromXF2( nFlags3 );
1433 aXF.mnXclNumFmt = ::extract_value< sal_uInt16 >( nFlags2, 0, 6 );
1434 aXF.mnXclFont = ::extract_value< sal_uInt16 >( nFlags2, 6, 2 );
1435
1436 // write the attributes to the cell
1437 aXF.ApplyPattern( rScPos.Col(), rScPos.Row(), rScPos.Col(), rScPos.Row(), rScPos.Tab() );
1438 }
1439
SetUsedFlags(sal_uInt8 nUsedFlags)1440 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags )
1441 {
1442 /* Notes about finding the mb***Used flags:
1443 - In cell XFs a *set* bit means a used attribute.
1444 - In style XFs a *cleared* bit means a used attribute.
1445 The mb***Used members always store true, if the attribute is used.
1446 The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1447 both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1448 */
1449 mbProtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT ));
1450 mbFontUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT ));
1451 mbFmtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT ));
1452 mbAlignUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN ));
1453 mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER ));
1454 mbAreaUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA ));
1455 }
1456
XclImpStyle(const XclImpRoot & rRoot)1457 XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) :
1458 XclImpRoot( rRoot ),
1459 mnXfId( EXC_XF_NOTFOUND ),
1460 mnBuiltinId( EXC_STYLE_USERDEF ),
1461 mnLevel( EXC_STYLE_NOLEVEL ),
1462 mbBuiltin( false ),
1463 mbCustom( false ),
1464 mbHidden( false ),
1465 mpStyleSheet( nullptr )
1466 {
1467 }
1468
ReadStyle(XclImpStream & rStrm)1469 void XclImpStyle::ReadStyle( XclImpStream& rStrm )
1470 {
1471 OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3 );
1472
1473 sal_uInt16 nXFIndex;
1474 nXFIndex = rStrm.ReaduInt16();
1475 mnXfId = nXFIndex & EXC_STYLE_XFMASK;
1476 mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN );
1477
1478 if( mbBuiltin )
1479 {
1480 mnBuiltinId = rStrm.ReaduInt8();
1481 mnLevel = rStrm.ReaduInt8();
1482 }
1483 else
1484 {
1485 maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
1486 // #i103281# check if this is a new built-in style introduced in XL2007
1487 if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() )
1488 {
1489 sal_uInt8 nExtFlags;
1490 rStrm.Ignore( 12 );
1491 nExtFlags = rStrm.ReaduInt8();
1492 mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN );
1493 mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM );
1494 mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN );
1495 if( mbBuiltin )
1496 {
1497 rStrm.Ignore( 1 ); // category
1498 mnBuiltinId = rStrm.ReaduInt8();
1499 mnLevel = rStrm.ReaduInt8();
1500 }
1501 }
1502 }
1503 }
1504
CreateStyleSheet()1505 ScStyleSheet* XclImpStyle::CreateStyleSheet()
1506 {
1507 // #i1624# #i1768# ignore unnamed user styles
1508 if( !mpStyleSheet && (!maFinalName.isEmpty()) )
1509 {
1510 bool bCreatePattern = false;
1511 XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId );
1512
1513 bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL);
1514 if( bDefStyle )
1515 {
1516 // set all flags to true to get all items in XclImpXF::CreatePattern()
1517 if( pXF ) pXF->SetAllUsedFlags( true );
1518 // use existing "Default" style sheet
1519 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find(
1520 ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) );
1521 OSL_ENSURE( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" );
1522 bCreatePattern = true;
1523 }
1524 else
1525 {
1526 /* #i103281# do not create another style sheet of the same name,
1527 if it exists already. This is needed to prevent that styles
1528 pasted from clipboard get duplicated over and over. */
1529 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SfxStyleFamily::Para ) );
1530 if( !mpStyleSheet )
1531 {
1532 mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined ) );
1533 bCreatePattern = true;
1534 }
1535 }
1536
1537 // bDefStyle==true omits default pool items in CreatePattern()
1538 if( bCreatePattern && mpStyleSheet && pXF )
1539 mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() );
1540 }
1541 return mpStyleSheet;
1542 }
1543
CreateUserStyle(const OUString & rFinalName)1544 void XclImpStyle::CreateUserStyle( const OUString& rFinalName )
1545 {
1546 maFinalName = rFinalName;
1547 if( !IsBuiltin() || mbCustom )
1548 CreateStyleSheet();
1549 }
1550
XclImpXFBuffer(const XclImpRoot & rRoot)1551 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
1552 XclImpRoot( rRoot )
1553 {
1554 }
1555
Initialize()1556 void XclImpXFBuffer::Initialize()
1557 {
1558 maXFList.clear();
1559 maBuiltinStyles.clear();
1560 maUserStyles.clear();
1561 maStylesByXf.clear();
1562 }
1563
ReadXF(XclImpStream & rStrm)1564 void XclImpXFBuffer::ReadXF( XclImpStream& rStrm )
1565 {
1566 XclImpXF* pXF = new XclImpXF( GetRoot() );
1567 pXF->ReadXF( rStrm );
1568 maXFList.push_back( std::unique_ptr<XclImpXF>(pXF) );
1569 }
1570
ReadStyle(XclImpStream & rStrm)1571 void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm )
1572 {
1573 XclImpStyle* pStyle = new XclImpStyle( GetRoot() );
1574 pStyle->ReadStyle( rStrm );
1575 (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).push_back( std::unique_ptr<XclImpStyle>(pStyle) );
1576 OSL_ENSURE( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1577 maStylesByXf[ pStyle->GetXfId() ] = pStyle;
1578 }
1579
GetFontIndex(sal_uInt16 nXFIndex) const1580 sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const
1581 {
1582 const XclImpXF* pXF = GetXF( nXFIndex );
1583 return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND;
1584 }
1585
GetFont(sal_uInt16 nXFIndex) const1586 const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const
1587 {
1588 return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) );
1589 }
1590
1591 namespace {
1592
1593 /** Functor for case-insensitive string comparison, usable in maps etc. */
1594 struct IgnoreCaseCompare
1595 {
operator ()__anon18eef3b20211::IgnoreCaseCompare1596 bool operator()( const OUString& rName1, const OUString& rName2 ) const
1597 { return rName1.compareToIgnoreAsciiCase( rName2 ) < 0; }
1598 };
1599
1600 } // namespace
1601
CreateUserStyles()1602 void XclImpXFBuffer::CreateUserStyles()
1603 {
1604 // calculate final names of all styles
1605 typedef ::std::map< OUString, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap;
1606 typedef ::std::vector< XclImpStyle* > XclImpStyleVector;
1607
1608 CellStyleNameMap aCellStyles;
1609 XclImpStyleVector aConflictNameStyles;
1610
1611 /* First, reserve style names that are built-in in Calc. This causes that
1612 imported cell styles get different unused names and thus do not try to
1613 overwrite these built-in styles. For BIFF4 workbooks (which contain a
1614 separate list of cell styles per sheet), reserve all existing styles if
1615 current sheet is not the first sheet (this styles buffer will be
1616 initialized again for every new sheet). This will create unique names
1617 for styles in different sheets with the same name. Assuming that the
1618 BIFF4W import filter is never used to import from clipboard... */
1619 bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0);
1620 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para );
1621 OUString aStandardName = ScResId( STR_STYLENAME_STANDARD );
1622 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
1623 if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) )
1624 if( aCellStyles.count( pStyleSheet->GetName() ) == 0 )
1625 aCellStyles[ pStyleSheet->GetName() ] = nullptr;
1626
1627 /* Calculate names of built-in styles. Store styles with reserved names
1628 in the aConflictNameStyles list. */
1629 for( const auto& rxStyle : maBuiltinStyles )
1630 {
1631 OUString aStyleName = XclTools::GetBuiltInStyleName( rxStyle->GetBuiltinId(), rxStyle->GetName(), rxStyle->GetLevel() );
1632 OSL_ENSURE( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
1633 "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1634 if( aCellStyles.count( aStyleName ) > 0 )
1635 aConflictNameStyles.push_back( rxStyle.get() );
1636 else
1637 aCellStyles[ aStyleName ] = rxStyle.get();
1638 }
1639
1640 /* Calculate names of user defined styles. Store styles with reserved
1641 names in the aConflictNameStyles list. */
1642 for( const auto& rxStyle : maUserStyles )
1643 {
1644 // #i1624# #i1768# ignore unnamed user styles
1645 if( !rxStyle->GetName().isEmpty() )
1646 {
1647 if( aCellStyles.count( rxStyle->GetName() ) > 0 )
1648 aConflictNameStyles.push_back( rxStyle.get() );
1649 else
1650 aCellStyles[ rxStyle->GetName() ] = rxStyle.get();
1651 }
1652 }
1653
1654 // find unused names for all styles with conflicting names
1655 for( XclImpStyle* pStyle : aConflictNameStyles )
1656 {
1657 OUString aUnusedName;
1658 sal_Int32 nIndex = 0;
1659 do
1660 {
1661 aUnusedName = pStyle->GetName() + " " + OUString::number( ++nIndex );
1662 }
1663 while( aCellStyles.count( aUnusedName ) > 0 );
1664 aCellStyles[ aUnusedName ] = pStyle;
1665 }
1666
1667 // set final names and create user-defined and modified built-in cell styles
1668 for( auto& [rStyleName, rpStyle] : aCellStyles )
1669 if( rpStyle )
1670 rpStyle->CreateUserStyle( rStyleName );
1671 }
1672
CreateStyleSheet(sal_uInt16 nXFIndex)1673 ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex )
1674 {
1675 XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex );
1676 return (aIt == maStylesByXf.end()) ? nullptr : aIt->second->CreateStyleSheet();
1677 }
1678
1679 // Buffer for XF indexes in cells =============================================
1680
Expand(SCROW nScRow,const XclImpXFIndex & rXFIndex)1681 bool XclImpXFRange::Expand( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1682 {
1683 if( maXFIndex != rXFIndex )
1684 return false;
1685
1686 if( mnScRow2 + 1 == nScRow )
1687 {
1688 ++mnScRow2;
1689 return true;
1690 }
1691 if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) )
1692 {
1693 --mnScRow1;
1694 return true;
1695 }
1696
1697 return false;
1698 }
1699
Expand(const XclImpXFRange & rNextRange)1700 bool XclImpXFRange::Expand( const XclImpXFRange& rNextRange )
1701 {
1702 OSL_ENSURE( mnScRow2 < rNextRange.mnScRow1, "XclImpXFRange::Expand - rows out of order" );
1703 if( (maXFIndex == rNextRange.maXFIndex) && (mnScRow2 + 1 == rNextRange.mnScRow1) )
1704 {
1705 mnScRow2 = rNextRange.mnScRow2;
1706 return true;
1707 }
1708 return false;
1709 }
1710
SetDefaultXF(const XclImpXFIndex & rXFIndex)1711 void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex& rXFIndex )
1712 {
1713 // List should be empty when inserting the default column format.
1714 // Later explicit SetXF() calls will break up this range.
1715 OSL_ENSURE( maIndexList.empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
1716
1717 // insert a complete row range with one insert.
1718 maIndexList.push_back( std::make_unique<XclImpXFRange>( 0, MAXROW, rXFIndex ) );
1719 }
1720
SetXF(SCROW nScRow,const XclImpXFIndex & rXFIndex)1721 void XclImpXFRangeColumn::SetXF( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1722 {
1723 XclImpXFRange* pPrevRange;
1724 XclImpXFRange* pNextRange;
1725 sal_uLong nNextIndex;
1726
1727 Find( pPrevRange, pNextRange, nNextIndex, nScRow );
1728
1729 // previous range:
1730 // try to overwrite XF (if row is contained in) or try to expand range
1731 if( pPrevRange )
1732 {
1733 if( pPrevRange->Contains( nScRow ) ) // overwrite old XF
1734 {
1735 if( rXFIndex == pPrevRange->maXFIndex )
1736 return;
1737
1738 SCROW nFirstScRow = pPrevRange->mnScRow1;
1739 SCROW nLastScRow = pPrevRange->mnScRow2;
1740 sal_uLong nIndex = nNextIndex - 1;
1741 XclImpXFRange* pThisRange = pPrevRange;
1742 pPrevRange = (nIndex > 0 && nIndex <= maIndexList.size()) ? maIndexList[ nIndex - 1 ].get() : nullptr;
1743
1744 if( nFirstScRow == nLastScRow ) // replace solely XF
1745 {
1746 pThisRange->maXFIndex = rXFIndex;
1747 TryConcatPrev( nNextIndex ); // try to concat. next with this
1748 TryConcatPrev( nIndex ); // try to concat. this with previous
1749 }
1750 else if( nFirstScRow == nScRow ) // replace first XF
1751 {
1752 ++(pThisRange->mnScRow1);
1753 // try to concatenate with previous of this
1754 if( !pPrevRange || !pPrevRange->Expand( nScRow, rXFIndex ) )
1755 Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1756 }
1757 else if( nLastScRow == nScRow ) // replace last XF
1758 {
1759 --(pThisRange->mnScRow2);
1760 if( !pNextRange || !pNextRange->Expand( nScRow, rXFIndex ) )
1761 Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1762 }
1763 else // insert in the middle of the range
1764 {
1765 pThisRange->mnScRow1 = nScRow + 1;
1766 // List::Insert() moves entries towards end of list, so insert twice at nIndex
1767 Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1768 Insert( new XclImpXFRange( nFirstScRow, nScRow - 1, pThisRange->maXFIndex ), nIndex );
1769 }
1770 return;
1771 }
1772 else if( pPrevRange->Expand( nScRow, rXFIndex ) ) // try to expand
1773 {
1774 TryConcatPrev( nNextIndex ); // try to concatenate next with expanded
1775 return;
1776 }
1777 }
1778
1779 // try to expand next range
1780 if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) )
1781 return;
1782
1783 // create new range
1784 Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1785 }
1786
Insert(XclImpXFRange * pXFRange,sal_uLong nIndex)1787 void XclImpXFRangeColumn::Insert(XclImpXFRange* pXFRange, sal_uLong nIndex)
1788 {
1789 maIndexList.insert( maIndexList.begin() + nIndex, std::unique_ptr<XclImpXFRange>(pXFRange) );
1790 }
1791
Find(XclImpXFRange * & rpPrevRange,XclImpXFRange * & rpNextRange,sal_uLong & rnNextIndex,SCROW nScRow)1792 void XclImpXFRangeColumn::Find(
1793 XclImpXFRange*& rpPrevRange, XclImpXFRange*& rpNextRange,
1794 sal_uLong& rnNextIndex, SCROW nScRow )
1795 {
1796
1797 // test whether list is empty
1798 if( maIndexList.empty() )
1799 {
1800 rpPrevRange = rpNextRange = nullptr;
1801 rnNextIndex = 0;
1802 return;
1803 }
1804
1805 rpPrevRange = maIndexList.front().get();
1806 rpNextRange = maIndexList.back().get();
1807
1808 // test whether row is at end of list (contained in or behind last range)
1809 // rpPrevRange will contain a possible existing row
1810 if( rpNextRange->mnScRow1 <= nScRow )
1811 {
1812 rpPrevRange = rpNextRange;
1813 rpNextRange = nullptr;
1814 rnNextIndex = maIndexList.size();
1815 return;
1816 }
1817
1818 // test whether row is at beginning of list (really before first range)
1819 if( nScRow < rpPrevRange->mnScRow1 )
1820 {
1821 rpNextRange = rpPrevRange;
1822 rpPrevRange = nullptr;
1823 rnNextIndex = 0;
1824 return;
1825 }
1826
1827 // loop: find range entries before and after new row
1828 // break the loop if there is no more range between first and last -or-
1829 // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
1830 sal_uLong nPrevIndex = 0;
1831 sal_uLong nMidIndex;
1832 rnNextIndex = maIndexList.size() - 1;
1833 XclImpXFRange* pMidRange;
1834 while( ((rnNextIndex - nPrevIndex) > 1) && (rpPrevRange->mnScRow2 < nScRow) )
1835 {
1836 nMidIndex = (nPrevIndex + rnNextIndex) / 2;
1837 pMidRange = maIndexList[nMidIndex].get();
1838 OSL_ENSURE( pMidRange, "XclImpXFRangeColumn::Find - missing XF index range" );
1839 if( nScRow < pMidRange->mnScRow1 ) // row is really before pMidRange
1840 {
1841 rpNextRange = pMidRange;
1842 rnNextIndex = nMidIndex;
1843 }
1844 else // row is in or after pMidRange
1845 {
1846 rpPrevRange = pMidRange;
1847 nPrevIndex = nMidIndex;
1848 }
1849 }
1850
1851 // find next rpNextRange if rpPrevRange contains nScRow
1852 if( nScRow <= rpPrevRange->mnScRow2 )
1853 {
1854 rnNextIndex = nPrevIndex + 1;
1855 rpNextRange = maIndexList[rnNextIndex].get();
1856 }
1857 }
1858
TryConcatPrev(sal_uLong nIndex)1859 void XclImpXFRangeColumn::TryConcatPrev( sal_uLong nIndex )
1860 {
1861 if( !nIndex || nIndex >= maIndexList.size() )
1862 return;
1863
1864 XclImpXFRange& prevRange = *maIndexList[ nIndex - 1 ];
1865 XclImpXFRange& nextRange = *maIndexList[ nIndex ];
1866
1867 if( prevRange.Expand( nextRange ) )
1868 maIndexList.erase( maIndexList.begin() + nIndex );
1869 }
1870
XclImpXFRangeBuffer(const XclImpRoot & rRoot)1871 XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot& rRoot ) :
1872 XclImpRoot( rRoot )
1873 {
1874 }
1875
~XclImpXFRangeBuffer()1876 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1877 {
1878 }
1879
Initialize()1880 void XclImpXFRangeBuffer::Initialize()
1881 {
1882 maColumns.clear();
1883 maHyperlinks.clear();
1884 maMergeList.RemoveAll();
1885 }
1886
SetXF(const ScAddress & rScPos,sal_uInt16 nXFIndex,XclImpXFInsertMode eMode)1887 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex, XclImpXFInsertMode eMode )
1888 {
1889 SCCOL nScCol = rScPos.Col();
1890 SCROW nScRow = rScPos.Row();
1891
1892 // set cell XF's
1893 size_t nIndex = static_cast< size_t >( nScCol );
1894 if( maColumns.size() <= nIndex )
1895 maColumns.resize( nIndex + 1 );
1896 if( !maColumns[ nIndex ] )
1897 maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1898 // remember all Boolean cells, they will get 'Standard' number format
1899 maColumns[ nIndex ]->SetXF( nScRow, XclImpXFIndex( nXFIndex, eMode == xlXFModeBoolCell ) );
1900
1901 // set "center across selection" and "fill" attribute for all following empty cells
1902 // ignore it on row default XFs
1903 if( eMode != xlXFModeRow )
1904 {
1905 const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex );
1906 if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) )
1907 {
1908 // expand last merged range if this attribute is set repeatedly
1909 ScRange* pRange = maMergeList.empty() ? nullptr : &maMergeList.back();
1910 if (pRange && (pRange->aEnd.Row() == nScRow) && (pRange->aEnd.Col() + 1 == nScCol) && (eMode == xlXFModeBlank))
1911 pRange->aEnd.IncCol();
1912 else if( eMode != xlXFModeBlank ) // do not merge empty cells
1913 maMergeList.push_back( ScRange( nScCol, nScRow, 0 ) );
1914 }
1915 }
1916 }
1917
SetXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1918 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1919 {
1920 SetXF( rScPos, nXFIndex, xlXFModeCell );
1921 }
1922
SetBlankXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1923 void XclImpXFRangeBuffer::SetBlankXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1924 {
1925 SetXF( rScPos, nXFIndex, xlXFModeBlank );
1926 }
1927
SetBoolXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1928 void XclImpXFRangeBuffer::SetBoolXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1929 {
1930 SetXF( rScPos, nXFIndex, xlXFModeBoolCell );
1931 }
1932
SetRowDefXF(SCROW nScRow,sal_uInt16 nXFIndex)1933 void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow, sal_uInt16 nXFIndex )
1934 {
1935 for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
1936 SetXF( ScAddress( nScCol, nScRow, 0 ), nXFIndex, xlXFModeRow );
1937 }
1938
SetColumnDefXF(SCCOL nScCol,sal_uInt16 nXFIndex)1939 void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol, sal_uInt16 nXFIndex )
1940 {
1941 // our array should not have values when creating the default column format.
1942 size_t nIndex = static_cast< size_t >( nScCol );
1943 if( maColumns.size() <= nIndex )
1944 maColumns.resize( nIndex + 1 );
1945 OSL_ENSURE( !maColumns[ nIndex ], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
1946 maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1947 maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) );
1948 }
1949
SetBorderLine(const ScRange & rRange,SCTAB nScTab,SvxBoxItemLine nLine)1950 void XclImpXFRangeBuffer::SetBorderLine( const ScRange& rRange, SCTAB nScTab, SvxBoxItemLine nLine )
1951 {
1952 SCCOL nFromScCol = (nLine == SvxBoxItemLine::RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
1953 SCROW nFromScRow = (nLine == SvxBoxItemLine::BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
1954 ScDocument& rDoc = GetDoc();
1955
1956 const SvxBoxItem* pFromItem =
1957 rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER );
1958 const SvxBoxItem* pToItem =
1959 rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER );
1960
1961 SvxBoxItem aNewItem( *pToItem );
1962 aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
1963 rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
1964 }
1965
SetHyperlink(const XclRange & rXclRange,const OUString & rUrl)1966 void XclImpXFRangeBuffer::SetHyperlink( const XclRange& rXclRange, const OUString& rUrl )
1967 {
1968 maHyperlinks.emplace_back( rXclRange, rUrl );
1969 }
1970
SetMerge(SCCOL nScCol1,SCROW nScRow1,SCCOL nScCol2,SCROW nScRow2)1971 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 )
1972 {
1973 if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) )
1974 maMergeList.push_back( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) );
1975 }
1976
Finalize()1977 void XclImpXFRangeBuffer::Finalize()
1978 {
1979 ScDocumentImport& rDocImport = GetDocImport();
1980 ScDocument& rDoc = rDocImport.getDoc();
1981 SCTAB nScTab = GetCurrScTab();
1982
1983 // apply patterns
1984 XclImpXFBuffer& rXFBuffer = GetXFBuffer();
1985 SCCOL nScCol = 0;
1986 for( const auto& rxColumn : maColumns )
1987 {
1988 // apply all cell styles of an existing column
1989 if( rxColumn.get() )
1990 {
1991 XclImpXFRangeColumn& rColumn = *rxColumn;
1992 std::vector<ScAttrEntry> aAttrs;
1993 aAttrs.reserve(rColumn.end() - rColumn.begin());
1994
1995 for (const auto& rxStyle : rColumn)
1996 {
1997 XclImpXFRange& rStyle = *rxStyle;
1998 const XclImpXFIndex& rXFIndex = rStyle.maXFIndex;
1999 XclImpXF* pXF = rXFBuffer.GetXF( rXFIndex.GetXFIndex() );
2000 if (!pXF)
2001 continue;
2002
2003 sal_uInt32 nForceScNumFmt = rXFIndex.IsBoolCell() ?
2004 GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND;
2005
2006 pXF->ApplyPatternToAttrVector(aAttrs, rStyle.mnScRow1, rStyle.mnScRow2, nForceScNumFmt);
2007 }
2008
2009 if (aAttrs.empty() || aAttrs.back().nEndRow != rDoc.MaxRow())
2010 {
2011 ScAttrEntry aEntry;
2012 aEntry.nEndRow = rDoc.MaxRow();
2013 aEntry.pPattern = rDoc.GetDefPattern();
2014 aAttrs.push_back(aEntry);
2015 }
2016
2017 aAttrs.shrink_to_fit();
2018 assert(aAttrs.size() > 0);
2019 ScDocumentImport::Attrs aAttrParam;
2020 aAttrParam.mvData.swap(aAttrs);
2021 aAttrParam.mbLatinNumFmtOnly = false; // when unsure, set it to false.
2022 rDocImport.setAttrEntries(nScTab, nScCol, std::move(aAttrParam));
2023 }
2024 ++nScCol;
2025 }
2026
2027 // insert hyperlink cells
2028 for( const auto& [rXclRange, rUrl] : maHyperlinks )
2029 XclImpHyperlink::InsertUrl( GetRoot(), rXclRange, rUrl );
2030
2031 // apply cell merging
2032 for ( size_t i = 0, nRange = maMergeList.size(); i < nRange; ++i )
2033 {
2034 const ScRange & rRange = maMergeList[ i ];
2035 const ScAddress& rStart = rRange.aStart;
2036 const ScAddress& rEnd = rRange.aEnd;
2037 bool bMultiCol = rStart.Col() != rEnd.Col();
2038 bool bMultiRow = rStart.Row() != rEnd.Row();
2039 // set correct right border
2040 if( bMultiCol )
2041 SetBorderLine( rRange, nScTab, SvxBoxItemLine::RIGHT );
2042 // set correct lower border
2043 if( bMultiRow )
2044 SetBorderLine( rRange, nScTab, SvxBoxItemLine::BOTTOM );
2045 // do merge
2046 if( bMultiCol || bMultiRow )
2047 rDoc.DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
2048 // #i93609# merged range in a single row: test if manual row height is needed
2049 if( !bMultiRow )
2050 {
2051 bool bTextWrap = rDoc.GetAttr( rStart, ATTR_LINEBREAK )->GetValue();
2052 if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
2053 if (const EditTextObject* pEditObj = rDoc.GetEditText(rStart))
2054 bTextWrap = pEditObj->GetParagraphCount() > 1;
2055 if( bTextWrap )
2056 GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
2057 }
2058 }
2059 }
2060
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2062