fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xistyle.cxx
blob47251d5b39973e6977316132857051b7f19ffa2c
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 "xistyle.hxx"
21 #include <sfx2/printer.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/boxitem.hxx>
37 #include <editeng/lineitem.hxx>
38 #include <svx/rotmodit.hxx>
39 #include <editeng/colritem.hxx>
40 #include <editeng/brushitem.hxx>
41 #include <editeng/frmdiritem.hxx>
42 #include <editeng/eeitem.hxx>
43 #include <editeng/flstitem.hxx>
44 #include <editeng/justifyitem.hxx>
45 #include <sal/macros.h>
46 #include "document.hxx"
47 #include "docpool.hxx"
48 #include "attrib.hxx"
49 #include "stlpool.hxx"
50 #include "stlsheet.hxx"
51 #include "formulacell.hxx"
52 #include "globstr.hrc"
53 #include "attarray.hxx"
54 #include "xltracer.hxx"
55 #include "xistream.hxx"
56 #include "xicontent.hxx"
58 #include "root.hxx"
59 #include "colrowst.hxx"
60 #include <svl/poolcach.hxx>
62 #include <list>
64 using ::std::list;
66 #include <cppuhelper/implbase1.hxx>
67 #include <com/sun/star/container/XIndexAccess.hpp>
68 #include <com/sun/star/beans/XPropertySet.hpp>
69 using namespace ::com::sun::star;
71 typedef ::cppu::WeakImplHelper1< container::XIndexAccess > XIndexAccess_BASE;
72 typedef ::std::vector< ColorData > ColorDataVec;
74 class PaletteIndex : public XIndexAccess_BASE
76 public:
77 PaletteIndex( const ColorDataVec& rColorDataTable ) : maColorData( rColorDataTable ) {}
79 // Methods XIndexAccess
80 virtual ::sal_Int32 SAL_CALL getCount() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
82 return maColorData.size();
85 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException, std::exception) SAL_OVERRIDE
87 //--Index; // apparently the palette is already 1 based
88 return uno::makeAny( sal_Int32( maColorData[ Index ] ) );
91 // Methods XElementAcess
92 virtual uno::Type SAL_CALL getElementType() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
94 return ::cppu::UnoType<sal_Int32>::get();
96 virtual sal_Bool SAL_CALL hasElements() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
98 return (maColorData.size() > 0);
101 private:
102 ColorDataVec maColorData;
105 void
106 XclImpPalette::ExportPalette()
108 if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
110 // copy values in color palette
111 sal_Int16 nColors = maColorTable.size();
112 ColorDataVec aColors;
113 aColors.resize( nColors );
114 for( sal_uInt16 nIndex = 0; nIndex < nColors; ++nIndex )
115 aColors[ nIndex ] = GetColorData( nIndex );
117 uno::Reference< beans::XPropertySet > xProps( pDocShell->GetModel(), uno::UNO_QUERY );
118 if ( xProps.is() )
120 uno::Reference< container::XIndexAccess > xIndex( new PaletteIndex( aColors ) );
121 xProps->setPropertyValue( "ColorPalette", uno::makeAny( xIndex ) );
126 // PALETTE record - color information =========================================
128 XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) :
129 XclDefaultPalette( rRoot ), mrRoot( rRoot )
133 void XclImpPalette::Initialize()
135 maColorTable.clear();
138 ColorData XclImpPalette::GetColorData( sal_uInt16 nXclIndex ) const
140 if( nXclIndex >= EXC_COLOR_USEROFFSET )
142 sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET;
143 if( nIx < maColorTable.size() )
144 return maColorTable[ nIx ];
146 return GetDefColorData( nXclIndex );
149 void XclImpPalette::ReadPalette( XclImpStream& rStrm )
151 sal_uInt16 nCount;
152 nCount = rStrm.ReaduInt16();
154 const size_t nMinRecordSize = 4;
155 const size_t nMaxRecords = rStrm.GetRecLeft() / nMinRecordSize;
156 if (nCount > nMaxRecords)
158 SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
159 " max possible entries, but " << nCount << " claimed, truncating");
160 nCount = nMaxRecords;
163 maColorTable.resize( nCount );
164 Color aColor;
165 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
167 rStrm >> aColor;
168 maColorTable[ nIndex ] = aColor.GetColor();
170 ExportPalette();
173 // FONT record - font information =============================================
174 XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
175 XclImpRoot( rRoot ),
176 mbHasCharSet( false ),
177 mbHasWstrn( true ),
178 mbHasAsian( false ),
179 mbHasCmplx( false )
181 SetAllUsedFlags( false );
184 XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
185 XclImpRoot( rRoot )
187 SetFontData( rFontData, false );
190 void XclImpFont::SetAllUsedFlags( bool bUsed )
192 mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed =
193 mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed;
196 void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet )
198 maData = rFontData;
199 mbHasCharSet = bHasCharSet;
200 if( !maData.maStyle.isEmpty() )
202 if( SfxObjectShell* pDocShell = GetDocShell() )
204 if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
205 pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
207 if( const FontList* pFontList = pInfoItem->GetFontList() )
209 vcl::FontInfo aFontInfo( pFontList->Get( maData.maName, maData.maStyle ) );
210 maData.SetScWeight( aFontInfo.GetWeight() );
211 maData.SetScPosture( aFontInfo.GetItalic() );
215 maData.maStyle.clear();
217 GuessScriptType();
218 SetAllUsedFlags( true );
221 rtl_TextEncoding XclImpFont::GetFontEncoding() const
223 // #i63105# use text encoding from FONT record
224 // #i67768# BIFF2-BIFF4 FONT records do not contain character set
225 rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding();
226 return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc;
229 void XclImpFont::ReadFont( XclImpStream& rStrm )
231 switch( GetBiff() )
233 case EXC_BIFF2:
234 ReadFontData2( rStrm );
235 ReadFontName2( rStrm );
236 break;
237 case EXC_BIFF3:
238 case EXC_BIFF4:
239 ReadFontData2( rStrm );
240 ReadFontColor( rStrm );
241 ReadFontName2( rStrm );
242 break;
243 case EXC_BIFF5:
244 ReadFontData5( rStrm );
245 ReadFontName2( rStrm );
246 break;
247 case EXC_BIFF8:
248 ReadFontData5( rStrm );
249 ReadFontName8( rStrm );
250 break;
251 default:
252 DBG_ERROR_BIFF();
253 return;
255 GuessScriptType();
256 SetAllUsedFlags( true );
259 void XclImpFont::ReadEfont( XclImpStream& rStrm )
261 ReadFontColor( rStrm );
264 void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm )
266 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
267 if( GetBiff() != EXC_BIFF8 )
268 return;
270 rStrm.Ignore( 64 );
271 sal_uInt32 nHeight = rStrm.ReaduInt32();
272 sal_uInt32 nStyle = rStrm.ReaduInt32();
273 sal_uInt16 nWeight = rStrm.ReaduInt16();
274 rStrm.Ignore( 2 ); //nEscapem
275 sal_uInt8 nUnderl = rStrm.ReaduInt8();
276 rStrm.Ignore( 3 );
277 sal_uInt32 nColor = rStrm.ReaduInt32();
278 rStrm.Ignore( 4 );
279 sal_uInt32 nFontFlags1 = rStrm.ReaduInt32();
280 rStrm.Ignore( 4 ); //nFontFlags2
281 sal_uInt32 nFontFlags3 = rStrm.ReaduInt32();
282 rStrm.Ignore( 18 );
284 if( (mbHeightUsed = (nHeight <= 0x7FFF)) )
285 maData.mnHeight = static_cast< sal_uInt16 >( nHeight );
286 if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) )
287 maData.mnWeight = static_cast< sal_uInt16 >( nWeight );
288 if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) )
289 maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE );
290 if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) )
291 maData.mnUnderline = nUnderl;
292 if( (mbColorUsed = (nColor <= 0x7FFF)) )
293 maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) );
294 if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) )
295 maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT );
298 void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const
300 // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
301 bool bEE = eType != EXC_FONTITEM_CELL;
303 // item = the item to put into the item set
304 // sc_which = the Calc Which-ID of the item
305 // ee_which = the edit engine Which-ID of the item
306 #define PUTITEM( item, sc_which, ee_which ) \
307 ScfTools::PutItem( rItemSet, item, (bEE ? (ee_which) : (sc_which)), bSkipPoolDefs )
309 // Font item
310 // #i36997# do not set default Tahoma font from notes
311 bool bDefNoteFont = (eType == EXC_FONTITEM_NOTE) && (maData.maName.equalsIgnoreAsciiCase( "Tahoma" ));
312 if( mbFontNameUsed && !bDefNoteFont )
314 rtl_TextEncoding eFontEnc = maData.GetFontEncoding();
315 rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ?
316 ScfTools::GetSystemTextEncoding() : eFontEnc;
318 //add corresponding pitch for FontFamily
319 FontPitch ePitch = PITCH_DONTKNOW;
320 FontFamily eFtFamily = maData.GetScFamily( GetTextEncoding() );
321 switch( eFtFamily ) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx
323 case FAMILY_ROMAN: ePitch = PITCH_VARIABLE; break;
324 case FAMILY_SWISS: ePitch = PITCH_VARIABLE; break;
325 case FAMILY_MODERN: ePitch = PITCH_FIXED; break;
326 default: break;
328 SvxFontItem aFontItem( eFtFamily , maData.maName, EMPTY_OUSTRING, ePitch, eTempTextEnc, ATTR_FONT );
330 // set only for valid script types
331 if( mbHasWstrn )
332 PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO );
333 if( mbHasAsian )
334 PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK );
335 if( mbHasCmplx )
336 PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL );
339 // Font height (for all script types)
340 if( mbHeightUsed )
342 sal_Int32 nHeight = maData.mnHeight;
343 if( bEE && (eType != EXC_FONTITEM_HF) ) // do not convert header/footer height
344 nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH; // 1 in == 72 pt
346 SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT );
347 PUTITEM( aHeightItem, ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT );
348 PUTITEM( aHeightItem, ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK );
349 PUTITEM( aHeightItem, ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL );
352 // Font color - pass AUTO_COL to item
353 if( mbColorUsed )
354 PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
356 // Font weight (for all script types)
357 if( mbWeightUsed )
359 SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT );
360 PUTITEM( aWeightItem, ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT );
361 PUTITEM( aWeightItem, ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK );
362 PUTITEM( aWeightItem, ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL );
365 // Font underline
366 if( mbUnderlUsed )
368 SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
369 PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE );
372 // Font posture (for all script types)
373 if( mbItalicUsed )
375 SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE );
376 PUTITEM( aPostItem, ATTR_FONT_POSTURE, EE_CHAR_ITALIC );
377 PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK );
378 PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL );
381 // Boolean attributes crossed out, contoured, shadowed
382 if( mbStrikeUsed )
383 PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
384 if( mbOutlineUsed )
385 PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
386 if( mbShadowUsed )
387 PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW );
389 // Super-/subscript: only on edit engine objects
390 if( mbEscapemUsed && bEE )
391 rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) );
393 #undef PUTITEM
396 void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet,
397 XclFontPropSetType eType, const Color* pFontColor ) const
399 GetFontPropSetHelper().WriteFontProperties(
400 rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor );
403 void XclImpFont::ReadFontData2( XclImpStream& rStrm )
405 sal_uInt16 nFlags;
406 maData.mnHeight = rStrm.ReaduInt16();
407 nFlags = rStrm.ReaduInt16();
409 maData.mnWeight = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL );
410 maData.mnUnderline = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE );
411 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
412 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
413 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
414 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
415 mbHasCharSet = false;
418 void XclImpFont::ReadFontData5( XclImpStream& rStrm )
420 sal_uInt16 nFlags;
422 maData.mnHeight = rStrm.ReaduInt16();
423 nFlags = rStrm.ReaduInt16();
424 ReadFontColor( rStrm );
425 maData.mnWeight = rStrm.ReaduInt16();
426 maData.mnEscapem = rStrm.ReaduInt16();
427 maData.mnUnderline = rStrm.ReaduInt8();
428 maData.mnFamily = rStrm.ReaduInt8();
429 maData.mnCharSet = rStrm.ReaduInt8();
430 rStrm.Ignore( 1 );
432 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
433 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
434 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
435 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
436 mbHasCharSet = true;
439 void XclImpFont::ReadFontColor( XclImpStream& rStrm )
441 maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() );
444 void XclImpFont::ReadFontName2( XclImpStream& rStrm )
446 maData.maName = rStrm.ReadByteString( false );
449 void XclImpFont::ReadFontName8( XclImpStream& rStrm )
451 maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() );
454 void XclImpFont::GuessScriptType()
456 mbHasWstrn = true;
457 mbHasAsian = mbHasCmplx = false;
459 // find the script types for which the font contains characters
460 if( OutputDevice* pPrinter = GetPrinter() )
462 vcl::Font aFont( maData.maName, Size( 0, 10 ) );
463 FontCharMapPtr pCharMap;
465 pPrinter->SetFont( aFont );
466 if( pPrinter->GetFontCharMap( pCharMap ) )
468 // CJK fonts
469 mbHasAsian =
470 pCharMap->HasChar( 0x3041 ) || // 3040-309F: Hiragana
471 pCharMap->HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
472 pCharMap->HasChar( 0x3111 ) || // 3100-312F: Bopomofo
473 pCharMap->HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
474 pCharMap->HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
475 pCharMap->HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
476 pCharMap->HasChar( 0x4E01 ) || // 4E00-9FAF: CJK Unified Ideographs
477 pCharMap->HasChar( 0x7E01 ) || // 4E00-9FAF: CJK unified ideographs
478 pCharMap->HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
479 pCharMap->HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
480 pCharMap->HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
481 pCharMap->HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
482 pCharMap->HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
483 // CTL fonts
484 mbHasCmplx =
485 pCharMap->HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
486 pCharMap->HasChar( 0x0631 ) || // 0600-06FF: Arabic
487 pCharMap->HasChar( 0x0721 ) || // 0700-074F: Syriac
488 pCharMap->HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
489 pCharMap->HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
490 pCharMap->HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
491 pCharMap->HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
492 pCharMap->HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
493 // Western fonts
494 mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || pCharMap->HasChar( 'A' );
497 pCharMap = 0;
501 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
502 XclImpRoot( rRoot ),
503 maFont4( rRoot ),
504 maCtrlFont( rRoot )
506 Initialize();
508 // default font for form controls without own font information
509 XclFontData aCtrlFontData;
510 switch( GetBiff() )
512 case EXC_BIFF2:
513 case EXC_BIFF3:
514 case EXC_BIFF4:
515 case EXC_BIFF5:
516 aCtrlFontData.maName = "Helv";
517 aCtrlFontData.mnHeight = 160;
518 aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
519 break;
520 case EXC_BIFF8:
521 aCtrlFontData.maName = "Tahoma";
522 aCtrlFontData.mnHeight = 160;
523 aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
524 break;
525 default:
526 DBG_ERROR_BIFF();
528 maCtrlFont.SetFontData( aCtrlFontData, false );
531 void XclImpFontBuffer::Initialize()
533 maFontList.clear();
535 // application font for column width calculation, later filled with first font from font list
536 XclFontData aAppFontData;
537 aAppFontData.maName = "Arial";
538 aAppFontData.mnHeight = 200;
539 aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL;
540 UpdateAppFont( aAppFontData, false );
543 const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const
545 /* Font with index 4 is not stored in an Excel file, but used e.g. by
546 BIFF5 form pushbutton objects. It is the bold default font.
547 This also means that entries above 4 are out by one in the list. */
549 if (nFontIndex == 4)
550 return &maFont4;
552 if (nFontIndex < 4)
554 // Font ID is zero-based when it's less than 4.
555 return nFontIndex >= maFontList.size() ? NULL : &maFontList[nFontIndex];
558 // Font ID is greater than 4. It is now 1-based.
559 return nFontIndex > maFontList.size() ? NULL : &maFontList[nFontIndex-1];
562 void XclImpFontBuffer::ReadFont( XclImpStream& rStrm )
564 XclImpFont* pFont = new XclImpFont( GetRoot() );
565 pFont->ReadFont( rStrm );
566 maFontList.push_back( pFont );
568 if( maFontList.size() == 1 )
570 UpdateAppFont( pFont->GetFontData(), pFont->HasCharSet() );
571 // #i71033# set text encoding from application font, if CODEPAGE is missing
572 SetAppFontEncoding( pFont->GetFontEncoding() );
576 void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm )
578 if( !maFontList.empty() )
579 maFontList.back().ReadEfont( rStrm );
582 void XclImpFontBuffer::FillToItemSet(
583 SfxItemSet& rItemSet, XclFontItemType eType,
584 sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const
586 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
587 pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs );
590 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet,
591 XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const
593 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
594 pFont->WriteFontProperties( rPropSet, eType, pFontColor );
597 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const
599 maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL );
602 void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet )
604 maAppFont = rFontData;
605 // #i3006# Calculate the width of '0' from first font and current printer.
606 SetCharWidth( maAppFont );
608 // font 4 is bold font 0
609 XclFontData aFont4Data( maAppFont );
610 aFont4Data.mnWeight = EXC_FONTWGHT_BOLD;
611 maFont4.SetFontData( aFont4Data, bHasCharSet );
614 // FORMAT record - number formats =============================================
616 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) :
617 XclNumFmtBuffer( rRoot ),
618 XclImpRoot( rRoot ),
619 mnNextXclIdx( 0 )
623 void XclImpNumFmtBuffer::Initialize()
625 maIndexMap.clear();
626 mnNextXclIdx = 0;
627 InitializeImport(); // base class
630 void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
632 OUString aFormat;
633 switch( GetBiff() )
635 case EXC_BIFF2:
636 case EXC_BIFF3:
637 aFormat = rStrm.ReadByteString( false );
638 break;
640 case EXC_BIFF4:
641 rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
642 aFormat = rStrm.ReadByteString( false );
643 break;
645 case EXC_BIFF5:
646 mnNextXclIdx = rStrm.ReaduInt16();
647 aFormat = rStrm.ReadByteString( false );
648 break;
650 case EXC_BIFF8:
651 mnNextXclIdx = rStrm.ReaduInt16();
652 aFormat = rStrm.ReadUniString();
653 break;
655 default:
656 DBG_ERROR_BIFF();
657 return;
660 if( mnNextXclIdx < 0xFFFF )
662 InsertFormat( mnNextXclIdx, aFormat );
663 ++mnNextXclIdx;
667 sal_uInt16 XclImpNumFmtBuffer::ReadCFFormat( XclImpStream& rStrm, bool bIFmt )
669 // internal number format ?
670 if(bIFmt)
672 rStrm.Ignore(1);
673 sal_uInt8 nIndex;
674 nIndex = rStrm.ReaduInt8();
675 return nIndex;
677 else
679 OUString aFormat = rStrm.ReadUniString();
680 InsertFormat( mnNextXclIdx, aFormat );
681 ++mnNextXclIdx;
682 return mnNextXclIdx - 1;
686 void XclImpNumFmtBuffer::CreateScFormats()
688 OSL_ENSURE( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
690 SvNumberFormatter& rFormatter = GetFormatter();
691 for( XclNumFmtMap::const_iterator aIt = GetFormatMap().begin(), aEnd = GetFormatMap().end(); aIt != aEnd; ++aIt )
693 const XclNumFmt& rNumFmt = aIt->second;
695 // insert/convert the Excel number format
696 sal_Int32 nCheckPos;
697 short nType = css::util::NumberFormat::DEFINED;
698 sal_uInt32 nKey;
699 if( !rNumFmt.maFormat.isEmpty() )
701 OUString aFormat( rNumFmt.maFormat );
702 rFormatter.PutandConvertEntry( aFormat, nCheckPos,
703 nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage );
705 else
706 nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage );
708 // insert the resulting format key into the Excel->Calc index map
709 maIndexMap[ aIt->first ] = nKey;
713 sal_uLong XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const
715 XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt );
716 return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND;
719 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const
721 sal_uLong nScNumFmt = GetScFormat( nXclNumFmt );
722 if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND )
723 nScNumFmt = GetStdScNumFmt();
724 FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs );
727 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, sal_uLong nScNumFmt, bool bSkipPoolDefs ) const
729 OSL_ENSURE( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
730 ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
731 if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, false ) == SfxItemState::SET )
732 ScGlobal::AddLanguage( rItemSet, GetFormatter() );
735 // XF, STYLE record - Cell formatting =========================================
737 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt )
739 mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED );
740 mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN );
743 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt )
745 mbLocked = ::get_flag( nProt, EXC_XF_LOCKED );
746 mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN );
749 void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
751 ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs );
754 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags )
756 mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 );
759 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign )
761 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
762 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); // new in BIFF3
765 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign )
767 FillFromXF3( nAlign );
768 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 ); // new in BIFF4
769 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 ); // new in BIFF4
772 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign )
774 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
775 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
776 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
777 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 );
780 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
782 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
783 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
784 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
785 mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 ); // new in BIFF8
786 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
787 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK ); // new in BIFF8
788 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 ); // new in BIFF8
791 void XclImpCellAlign::FillFromCF( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
793 mnHorAlign = extract_value< sal_uInt8 >( nAlign, 0, 3 );
794 mbLineBreak = get_flag< sal_uInt8 >( nAlign, EXC_XF_LINEBREAK );
795 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
796 mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 );
797 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 );
798 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK );
799 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 );
802 void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const
804 // horizontal alignment
805 ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs );
806 ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD ), bSkipPoolDefs );
808 // text wrap (#i74508# always if vertical alignment is justified or distributed)
809 bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB);
810 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs );
812 // vertical alignment
813 ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs );
814 ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD ), bSkipPoolDefs );
816 // indent
817 sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
818 ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs );
820 // shrink to fit
821 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs );
823 // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
824 sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient );
825 bool bStacked = (nXclRot == EXC_ROT_STACKED);
826 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs );
827 // set an angle in the range from -90 to 90 degrees
828 sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 );
829 ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs );
830 // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
831 bool bAsianVert = bStacked && pFont && pFont->HasAsianChars();
832 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs );
834 // CTL text direction
835 ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs );
838 XclImpCellBorder::XclImpCellBorder()
840 SetUsedFlags( false, false );
843 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed )
845 mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed;
846 mbDiagUsed = bDiagUsed;
849 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags )
851 mnLeftLine = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
852 mnRightLine = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
853 mnTopLine = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE, EXC_LINE_THIN, EXC_LINE_NONE );
854 mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE );
855 mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK;
856 SetUsedFlags( true, false );
859 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder )
861 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
862 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 8, 3 );
863 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder, 16, 3 );
864 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 24, 3 );
865 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 3, 5 );
866 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 11, 5 );
867 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 );
868 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 27, 5 );
869 SetUsedFlags( true, false );
872 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea )
874 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
875 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 3, 3 );
876 mnBottomLine = ::extract_value< sal_uInt8 >( nArea, 22, 3 );
877 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 6, 3 );
878 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 9, 7 );
879 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 16, 7 );
880 mnBottomColor = ::extract_value< sal_uInt16 >( nArea, 25, 7 );
881 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 23, 7 );
882 SetUsedFlags( true, false );
885 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
887 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder1, 0, 4 );
888 mnRightLine = ::extract_value< sal_uInt8 >( nBorder1, 4, 4 );
889 mnTopLine = ::extract_value< sal_uInt8 >( nBorder1, 8, 4 );
890 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder1, 12, 4 );
891 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 );
892 mnRightColor = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 );
893 mnTopColor = ::extract_value< sal_uInt16 >( nBorder2, 0, 7 );
894 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2, 7, 7 );
895 mbDiagTLtoBR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR );
896 mbDiagBLtoTR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR );
897 if( mbDiagTLtoBR || mbDiagBLtoTR )
899 mnDiagLine = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 );
900 mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 );
902 SetUsedFlags( true, true );
905 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags )
907 mnLeftLine = ::extract_value< sal_uInt8 >( nLineStyle, 0, 4 );
908 mnRightLine = ::extract_value< sal_uInt8 >( nLineStyle, 4, 4 );
909 mnTopLine = ::extract_value< sal_uInt8 >( nLineStyle, 8, 4 );
910 mnBottomLine = ::extract_value< sal_uInt8 >( nLineStyle, 12, 4 );
911 mnLeftColor = ::extract_value< sal_uInt16 >( nLineColor, 0, 7 );
912 mnRightColor = ::extract_value< sal_uInt16 >( nLineColor, 7, 7 );
913 mnTopColor = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 );
914 mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 );
915 mbLeftUsed = !::get_flag( nFlags, EXC_CF_BORDER_LEFT );
916 mbRightUsed = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT );
917 mbTopUsed = !::get_flag( nFlags, EXC_CF_BORDER_TOP );
918 mbBottomUsed = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM );
919 mbDiagUsed = false;
922 bool XclImpCellBorder::HasAnyOuterBorder() const
924 return
925 (mbLeftUsed && (mnLeftLine != EXC_LINE_NONE)) ||
926 (mbRightUsed && (mnRightLine != EXC_LINE_NONE)) ||
927 (mbTopUsed && (mnTopLine != EXC_LINE_NONE)) ||
928 (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE));
931 namespace {
933 /** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
934 bool lclConvertBorderLine( ::editeng::SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor )
936 static const sal_uInt16 ppnLineParam[][ 4 ] =
938 // outer width, type
939 { 0, table::BorderLineStyle::SOLID }, // 0 = none
940 { EXC_BORDER_THIN, table::BorderLineStyle::SOLID }, // 1 = thin
941 { EXC_BORDER_MEDIUM, table::BorderLineStyle::SOLID }, // 2 = medium
942 { EXC_BORDER_THIN, table::BorderLineStyle::FINE_DASHED }, // 3 = dashed
943 { EXC_BORDER_THIN, table::BorderLineStyle::DOTTED }, // 4 = dotted
944 { EXC_BORDER_THICK, table::BorderLineStyle::SOLID }, // 5 = thick
945 { EXC_BORDER_THICK, table::BorderLineStyle::DOUBLE_THIN }, // 6 = double
946 { EXC_BORDER_HAIR, table::BorderLineStyle::SOLID }, // 7 = hair
947 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASHED }, // 8 = med dash
948 { EXC_BORDER_THIN, table::BorderLineStyle::DASH_DOT }, // 9 = thin dashdot
949 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT }, // A = med dashdot
950 { EXC_BORDER_THIN, table::BorderLineStyle::DASH_DOT_DOT }, // B = thin dashdotdot
951 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT_DOT }, // C = med dashdotdot
952 { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASH_DOT } // D = med slant dashdot
955 if( nXclLine == EXC_LINE_NONE )
956 return false;
957 if( nXclLine >= SAL_N_ELEMENTS( ppnLineParam ) )
958 nXclLine = EXC_LINE_THIN;
960 rLine.SetColor( rPalette.GetColor( nXclColor ) );
961 rLine.SetWidth( ppnLineParam[ nXclLine ][ 0 ] );
962 rLine.SetBorderLineStyle( static_cast< ::editeng::SvxBorderStyle>(
963 ppnLineParam[ nXclLine ][ 1 ]) );
964 return true;
967 } // namespace
969 void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
971 if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed )
973 SvxBoxItem aBoxItem( ATTR_BORDER );
974 ::editeng::SvxBorderLine aLine;
975 if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) )
976 aBoxItem.SetLine( &aLine, SvxBoxItemLine::LEFT );
977 if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) )
978 aBoxItem.SetLine( &aLine, SvxBoxItemLine::RIGHT );
979 if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) )
980 aBoxItem.SetLine( &aLine, SvxBoxItemLine::TOP );
981 if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) )
982 aBoxItem.SetLine( &aLine, SvxBoxItemLine::BOTTOM );
983 ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs );
985 if( mbDiagUsed )
987 SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
988 SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
989 ::editeng::SvxBorderLine aLine;
990 if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
992 if( mbDiagTLtoBR )
993 aTLBRItem.SetLine( &aLine );
994 if( mbDiagBLtoTR )
995 aBLTRItem.SetLine( &aLine );
997 ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs );
998 ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs );
1002 XclImpCellArea::XclImpCellArea()
1004 SetUsedFlags( false );
1007 void XclImpCellArea::SetUsedFlags( bool bUsed )
1009 mbForeUsed = mbBackUsed = mbPattUsed = bUsed;
1012 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags )
1014 mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE );
1015 mnForeColor = EXC_COLOR_BIFF2_BLACK;
1016 mnBackColor = EXC_COLOR_BIFF2_WHITE;
1017 SetUsedFlags( true );
1020 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea )
1022 mnPattern = ::extract_value< sal_uInt8 >( nArea, 0, 6 );
1023 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 6, 5 );
1024 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 );
1025 SetUsedFlags( true );
1028 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea )
1030 mnPattern = ::extract_value< sal_uInt8 >( nArea, 16, 6 );
1031 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
1032 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
1033 SetUsedFlags( true );
1036 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea )
1038 mnPattern = ::extract_value< sal_uInt8 >( nBorder2, 26, 6 );
1039 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
1040 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
1041 SetUsedFlags( true );
1044 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags )
1046 mnForeColor = ::extract_value< sal_uInt16 >( nColor, 0, 7 );
1047 mnBackColor = ::extract_value< sal_uInt16 >( nColor, 7, 7 );
1048 mnPattern = ::extract_value< sal_uInt8 >( nPattern, 10, 6 );
1049 mbForeUsed = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR );
1050 mbBackUsed = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR );
1051 mbPattUsed = !::get_flag( nFlags, EXC_CF_AREA_PATTERN );
1053 if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) )
1055 mnForeColor = mnBackColor;
1056 mnPattern = EXC_PATT_SOLID;
1057 mbForeUsed = mbPattUsed = true;
1059 else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) )
1061 mbPattUsed = false;
1065 void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
1067 if( mbPattUsed ) // colors may be both unused in cond. formats
1069 SvxBrushItem aBrushItem( ATTR_BACKGROUND );
1071 // do not use IsTransparent() - old Calc filter writes tranparency with different color indexes
1072 if( mnPattern == EXC_PATT_NONE )
1074 aBrushItem.SetColor( Color( COL_TRANSPARENT ) );
1076 else
1078 Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) );
1079 Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) );
1080 aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) );
1083 ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs );
1087 XclImpXF::XclImpXF( const XclImpRoot& rRoot ) :
1088 XclXFBase( true ), // default is cell XF
1089 XclImpRoot( rRoot ),
1090 mpStyleSheet( 0 ),
1091 mnXclNumFmt( 0 ),
1092 mnXclFont( 0 )
1096 XclImpXF::~XclImpXF()
1100 void XclImpXF::ReadXF2( XclImpStream& rStrm )
1102 sal_uInt8 nReadFont, nReadNumFmt, nFlags;
1103 nReadFont = rStrm.ReaduInt8();
1104 rStrm.Ignore( 1 );
1105 nReadNumFmt = rStrm.ReaduInt8();
1106 nFlags = rStrm.ReaduInt8();
1108 // XF type always cell, no parent, used flags always true
1109 SetAllUsedFlags( true );
1111 // attributes
1112 maProtection.FillFromXF2( nReadNumFmt );
1113 mnXclFont = nReadFont;
1114 mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK;
1115 maAlignment.FillFromXF2( nFlags );
1116 maBorder.FillFromXF2( nFlags );
1117 maArea.FillFromXF2( nFlags );
1120 void XclImpXF::ReadXF3( XclImpStream& rStrm )
1122 sal_uInt32 nBorder;
1123 sal_uInt16 nTypeProt, nAlign, nArea;
1124 sal_uInt8 nReadFont, nReadNumFmt;
1125 nReadFont = rStrm.ReaduInt8();
1126 nReadNumFmt = rStrm.ReaduInt8();
1127 nTypeProt = rStrm.ReaduInt16();
1128 nAlign = rStrm.ReaduInt16();
1129 nArea = rStrm.ReaduInt16();
1130 nBorder = rStrm.ReaduInt32();
1132 // XF type/parent, attribute used flags
1133 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); // new in BIFF3
1134 mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 ); // new in BIFF3
1135 SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) );
1137 // attributes
1138 maProtection.FillFromXF3( nTypeProt );
1139 mnXclFont = nReadFont;
1140 mnXclNumFmt = nReadNumFmt;
1141 maAlignment.FillFromXF3( nAlign );
1142 maBorder.FillFromXF3( nBorder );
1143 maArea.FillFromXF3( nArea ); // new in BIFF3
1146 void XclImpXF::ReadXF4( XclImpStream& rStrm )
1148 sal_uInt32 nBorder;
1149 sal_uInt16 nTypeProt, nAlign, nArea;
1150 sal_uInt8 nReadFont, nReadNumFmt;
1151 nReadFont = rStrm.ReaduInt8();
1152 nReadNumFmt = rStrm.ReaduInt8();
1153 nTypeProt = rStrm.ReaduInt16();
1154 nAlign = rStrm.ReaduInt16();
1155 nArea = rStrm.ReaduInt16();
1156 nBorder = rStrm.ReaduInt32();
1158 // XF type/parent, attribute used flags
1159 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1160 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1161 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1163 // attributes
1164 maProtection.FillFromXF3( nTypeProt );
1165 mnXclFont = nReadFont;
1166 mnXclNumFmt = nReadNumFmt;
1167 maAlignment.FillFromXF4( nAlign );
1168 maBorder.FillFromXF3( nBorder );
1169 maArea.FillFromXF3( nArea );
1172 void XclImpXF::ReadXF5( XclImpStream& rStrm )
1174 sal_uInt32 nArea, nBorder;
1175 sal_uInt16 nTypeProt, nAlign;
1176 mnXclFont = rStrm.ReaduInt16();
1177 mnXclNumFmt = rStrm.ReaduInt16();
1178 nTypeProt = rStrm.ReaduInt16();
1179 nAlign = rStrm.ReaduInt16();
1180 nArea = rStrm.ReaduInt32();
1181 nBorder = rStrm.ReaduInt32();
1183 // XF type/parent, attribute used flags
1184 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1185 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1186 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1188 // attributes
1189 maProtection.FillFromXF3( nTypeProt );
1190 maAlignment.FillFromXF5( nAlign );
1191 maBorder.FillFromXF5( nBorder, nArea );
1192 maArea.FillFromXF5( nArea );
1195 void XclImpXF::ReadXF8( XclImpStream& rStrm )
1197 sal_uInt32 nBorder1, nBorder2;
1198 sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea;
1199 mnXclFont = rStrm.ReaduInt16();
1200 mnXclNumFmt = rStrm.ReaduInt16();
1201 nTypeProt = rStrm.ReaduInt16();
1202 nAlign = rStrm.ReaduInt16();
1203 nMiscAttrib = rStrm.ReaduInt16();
1204 nBorder1 = rStrm.ReaduInt32();
1205 nBorder2 = rStrm.ReaduInt32( );
1206 nArea = rStrm.ReaduInt16();
1208 // XF type/parent, attribute used flags
1209 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1210 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1211 SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
1213 // attributes
1214 maProtection.FillFromXF3( nTypeProt );
1215 maAlignment.FillFromXF8( nAlign, nMiscAttrib );
1216 maBorder.FillFromXF8( nBorder1, nBorder2 );
1217 maArea.FillFromXF8( nBorder2, nArea );
1220 void XclImpXF::ReadXF( XclImpStream& rStrm )
1222 switch( GetBiff() )
1224 case EXC_BIFF2: ReadXF2( rStrm ); break;
1225 case EXC_BIFF3: ReadXF3( rStrm ); break;
1226 case EXC_BIFF4: ReadXF4( rStrm ); break;
1227 case EXC_BIFF5: ReadXF5( rStrm ); break;
1228 case EXC_BIFF8: ReadXF8( rStrm ); break;
1229 default: DBG_ERROR_BIFF();
1233 const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs )
1235 if( mpPattern.get() )
1236 return *mpPattern;
1238 // create new pattern attribute set
1239 mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) );
1240 SfxItemSet& rItemSet = mpPattern->GetItemSet();
1241 XclImpXF* pParentXF = IsCellXF() ? GetXFBuffer().GetXF( mnParent ) : 0;
1243 // parent cell style
1244 if( IsCellXF() && !mpStyleSheet )
1246 mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent );
1248 /* Enables mb***Used flags, if the formatting attributes differ from
1249 the passed XF record. In cell XFs Excel uses the cell attributes,
1250 if they differ from the parent style XF.
1251 ...or if the respective flag is not set in parent style XF. */
1252 if( pParentXF )
1254 if( !mbProtUsed )
1255 mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection);
1256 if( !mbFontUsed )
1257 mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont);
1258 if( !mbFmtUsed )
1259 mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt);
1260 if( !mbAlignUsed )
1261 mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment);
1262 if( !mbBorderUsed )
1263 mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder);
1264 if( !mbAreaUsed )
1265 mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea);
1269 // cell protection
1270 if( mbProtUsed )
1271 maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
1273 // font
1274 if( mbFontUsed )
1275 GetFontBuffer().FillToItemSet( rItemSet, EXC_FONTITEM_CELL, mnXclFont, bSkipPoolDefs );
1277 // value format
1278 if( mbFmtUsed )
1280 GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
1281 // Trace occurrences of Windows date formats
1282 GetTracer().TraceDates( mnXclNumFmt );
1285 // alignment
1286 if( mbAlignUsed )
1287 maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
1289 // border
1290 if( mbBorderUsed )
1292 maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1293 GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR ||
1294 maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR ||
1295 maBorder.mnBottomLine > EXC_LINE_HAIR );
1298 // area
1299 if( mbAreaUsed )
1301 maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1302 GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE &&
1303 maArea.mnPattern != EXC_PATT_SOLID);
1306 /* #i38709# Decide which rotation reference mode to use. If any outer
1307 border line of the cell is set (either explicitly or via cell style),
1308 and the cell contents are rotated, set rotation reference to bottom of
1309 cell. This causes the borders to be painted rotated with the text. */
1310 if( mbAlignUsed || mbBorderUsed )
1312 SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD;
1313 const XclImpCellAlign* pAlign = mbAlignUsed ? &maAlignment : (pParentXF ? &pParentXF->maAlignment : 0);
1314 const XclImpCellBorder* pBorder = mbBorderUsed ? &maBorder : (pParentXF ? &pParentXF->maBorder : 0);
1315 if( pAlign && pBorder && (0 < pAlign->mnRotation) && (pAlign->mnRotation <= 180) && pBorder->HasAnyOuterBorder() )
1316 eRotateMode = SVX_ROTATE_MODE_BOTTOM;
1317 ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs );
1320 // Excel's cell margins are different from Calc's default margins.
1321 SvxMarginItem aItem(40, 40, 40, 40, ATTR_MARGIN);
1322 ScfTools::PutItem(rItemSet, aItem, bSkipPoolDefs);
1324 return *mpPattern;
1327 void XclImpXF::ApplyPatternToAttrList(
1328 list<ScAttrEntry>& rAttrs, SCROW nRow1, SCROW nRow2, sal_uInt32 nForceScNumFmt)
1330 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1331 CreatePattern();
1332 ScPatternAttr& rPat = *mpPattern;
1334 // insert into document
1335 ScDocument& rDoc = GetDoc();
1337 if (IsCellXF())
1339 if (mpStyleSheet)
1341 // Apply style sheet. Don't clear the direct formats.
1342 rPat.SetStyleSheet(mpStyleSheet, false);
1344 else
1346 // When the cell format is not associated with any style, use the
1347 // 'Default' style. Some buggy XLS docs generated by apps other
1348 // than Excel (such as 1C) may not have any built-in styles at
1349 // all.
1350 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
1351 if (pStylePool)
1353 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>(
1354 pStylePool->Find(
1355 ScGlobal::GetRscString(STR_STYLENAME_STANDARD), SFX_STYLE_FAMILY_PARA));
1357 if (pStyleSheet)
1358 rPat.SetStyleSheet(pStyleSheet, false);
1364 if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
1366 ScPatternAttr aNumPat(rDoc.GetPool());
1367 GetNumFmtBuffer().FillScFmtToItemSet(aNumPat.GetItemSet(), nForceScNumFmt);
1368 rPat.GetItemSet().Put(aNumPat.GetItemSet());
1371 // Make sure we skip unnamed styles.
1372 if (rPat.GetStyleName())
1374 // Check for a gap between the last entry and this one.
1375 bool bHasGap = false;
1376 if (rAttrs.empty() && nRow1 > 0)
1377 // First attribute range doesn't start at row 0.
1378 bHasGap = true;
1380 if (!rAttrs.empty() && rAttrs.back().nRow + 1 < nRow1)
1381 bHasGap = true;
1383 if (bHasGap)
1385 // Fill this gap with the default pattern.
1386 ScAttrEntry aEntry;
1387 aEntry.nRow = nRow1 - 1;
1388 aEntry.pPattern = rDoc.GetDefPattern();
1389 rAttrs.push_back(aEntry);
1392 ScAttrEntry aEntry;
1393 aEntry.nRow = nRow2;
1394 aEntry.pPattern = static_cast<const ScPatternAttr*>(&rDoc.GetPool()->Put(rPat));
1395 rAttrs.push_back(aEntry);
1399 void XclImpXF::ApplyPattern(
1400 SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2,
1401 SCTAB nScTab, sal_uLong nForceScNumFmt )
1403 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1404 const ScPatternAttr& rPattern = CreatePattern();
1406 // insert into document
1407 ScDocument& rDoc = GetDoc();
1408 if( IsCellXF() && mpStyleSheet )
1409 rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet );
1410 if( HasUsedFlags() )
1411 rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern );
1413 // #108770# apply special number format
1414 if( nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
1416 ScPatternAttr aPattern( GetDoc().GetPool() );
1417 GetNumFmtBuffer().FillScFmtToItemSet( aPattern.GetItemSet(), nForceScNumFmt );
1418 rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, aPattern );
1422 /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot& rRoot,
1423 const ScAddress& rScPos, sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 )
1425 /* Create an XF object and let it do the work. We will have access to its
1426 private members here. */
1427 XclImpXF aXF( rRoot );
1429 // no used flags available in BIFF2 (always true)
1430 aXF.SetAllUsedFlags( true );
1432 // set the attributes
1433 aXF.maProtection.FillFromXF2( nFlags1 );
1434 aXF.maAlignment.FillFromXF2( nFlags3 );
1435 aXF.maBorder.FillFromXF2( nFlags3 );
1436 aXF.maArea.FillFromXF2( nFlags3 );
1437 aXF.mnXclNumFmt = ::extract_value< sal_uInt16 >( nFlags2, 0, 6 );
1438 aXF.mnXclFont = ::extract_value< sal_uInt16 >( nFlags2, 6, 2 );
1440 // write the attributes to the cell
1441 aXF.ApplyPattern( rScPos.Col(), rScPos.Row(), rScPos.Col(), rScPos.Row(), rScPos.Tab() );
1444 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags )
1446 /* Notes about finding the mb***Used flags:
1447 - In cell XFs a *set* bit means a used attribute.
1448 - In style XFs a *cleared* bit means a used attribute.
1449 The mb***Used members always store true, if the attribute is used.
1450 The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1451 both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1453 mbProtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT ));
1454 mbFontUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT ));
1455 mbFmtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT ));
1456 mbAlignUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN ));
1457 mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER ));
1458 mbAreaUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA ));
1461 XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) :
1462 XclImpRoot( rRoot ),
1463 mnXfId( EXC_XF_NOTFOUND ),
1464 mnBuiltinId( EXC_STYLE_USERDEF ),
1465 mnLevel( EXC_STYLE_NOLEVEL ),
1466 mbBuiltin( false ),
1467 mbCustom( false ),
1468 mbHidden( false ),
1469 mpStyleSheet( 0 )
1473 void XclImpStyle::ReadStyle( XclImpStream& rStrm )
1475 OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3 );
1477 sal_uInt16 nXFIndex;
1478 nXFIndex = rStrm.ReaduInt16();
1479 mnXfId = nXFIndex & EXC_STYLE_XFMASK;
1480 mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN );
1482 if( mbBuiltin )
1484 mnBuiltinId = rStrm.ReaduInt8();
1485 mnLevel = rStrm.ReaduInt8();
1487 else
1489 maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
1490 // #i103281# check if this is a new built-in style introduced in XL2007
1491 if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() )
1493 sal_uInt8 nExtFlags;
1494 rStrm.Ignore( 12 );
1495 nExtFlags = rStrm.ReaduInt8();
1496 mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN );
1497 mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM );
1498 mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN );
1499 if( mbBuiltin )
1501 rStrm.Ignore( 1 ); // category
1502 mnBuiltinId = rStrm.ReaduInt8();
1503 mnLevel = rStrm.ReaduInt8();
1509 ScStyleSheet* XclImpStyle::CreateStyleSheet()
1511 // #i1624# #i1768# ignore unnamed user styles
1512 if( !mpStyleSheet && (!maFinalName.isEmpty()) )
1514 bool bCreatePattern = false;
1515 XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId );
1517 bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL);
1518 if( bDefStyle )
1520 // set all flags to true to get all items in XclImpXF::CreatePattern()
1521 if( pXF ) pXF->SetAllUsedFlags( true );
1522 // use existing "Default" style sheet
1523 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find(
1524 ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) );
1525 OSL_ENSURE( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" );
1526 bCreatePattern = true;
1528 else
1530 /* #i103281# do not create another style sheet of the same name,
1531 if it exists already. This is needed to prevent that styles
1532 pasted from clipboard get duplicated over and over. */
1533 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SFX_STYLE_FAMILY_PARA ) );
1534 if( !mpStyleSheet )
1536 mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ) );
1537 bCreatePattern = true;
1541 // bDefStyle==true omits default pool items in CreatePattern()
1542 if( bCreatePattern && mpStyleSheet && pXF )
1543 mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() );
1545 return mpStyleSheet;
1548 void XclImpStyle::CreateUserStyle( const OUString& rFinalName )
1550 maFinalName = rFinalName;
1551 if( !IsBuiltin() || mbCustom )
1552 CreateStyleSheet();
1555 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
1556 XclImpRoot( rRoot )
1560 void XclImpXFBuffer::Initialize()
1562 maXFList.clear();
1563 maBuiltinStyles.clear();
1564 maUserStyles.clear();
1565 maStylesByXf.clear();
1568 void XclImpXFBuffer::ReadXF( XclImpStream& rStrm )
1570 XclImpXF* pXF = new XclImpXF( GetRoot() );
1571 pXF->ReadXF( rStrm );
1572 maXFList.push_back( pXF );
1575 void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm )
1577 XclImpStyle* pStyle = new XclImpStyle( GetRoot() );
1578 pStyle->ReadStyle( rStrm );
1579 (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).push_back( pStyle );
1580 OSL_ENSURE( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1581 maStylesByXf[ pStyle->GetXfId() ] = pStyle;
1584 sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const
1586 const XclImpXF* pXF = GetXF( nXFIndex );
1587 return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND;
1590 const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const
1592 return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) );
1595 namespace {
1597 /** Functor for case-insensitive string comparison, usable in maps etc. */
1598 struct IgnoreCaseCompare
1600 inline bool operator()( const OUString& rName1, const OUString& rName2 ) const
1601 { return rName1.compareToIgnoreAsciiCase( rName2 ) < 0; }
1604 } // namespace
1606 void XclImpXFBuffer::CreateUserStyles()
1608 // calculate final names of all styles
1609 typedef ::std::map< OUString, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap;
1610 typedef ::std::vector< XclImpStyle* > XclImpStyleVector;
1612 CellStyleNameMap aCellStyles;
1613 XclImpStyleVector aConflictNameStyles;
1615 /* First, reserve style names that are built-in in Calc. This causes that
1616 imported cell styles get different unused names and thus do not try to
1617 overwrite these built-in styles. For BIFF4 workbooks (which contain a
1618 separate list of cell styles per sheet), reserve all existing styles if
1619 current sheet is not the first sheet (this styles buffer will be
1620 initialized again for every new sheet). This will create unique names
1621 for styles in different sheets with the same name. Assuming that the
1622 BIFF4W import filter is never used to import from clipboard... */
1623 bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0);
1624 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
1625 OUString aStandardName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD );
1626 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
1627 if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) )
1628 if( aCellStyles.count( pStyleSheet->GetName() ) == 0 )
1629 aCellStyles[ pStyleSheet->GetName() ] = 0;
1631 /* Calculate names of built-in styles. Store styles with reserved names
1632 in the aConflictNameStyles list. */
1633 for( XclImpStyleList::iterator itStyle = maBuiltinStyles.begin(); itStyle != maBuiltinStyles.end(); ++itStyle )
1635 OUString aStyleName = XclTools::GetBuiltInStyleName( itStyle->GetBuiltinId(), itStyle->GetName(), itStyle->GetLevel() );
1636 OSL_ENSURE( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
1637 "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1638 if( aCellStyles.count( aStyleName ) > 0 )
1639 aConflictNameStyles.push_back( &(*itStyle) );
1640 else
1641 aCellStyles[ aStyleName ] = &(*itStyle);
1644 /* Calculate names of user defined styles. Store styles with reserved
1645 names in the aConflictNameStyles list. */
1646 for( XclImpStyleList::iterator itStyle = maUserStyles.begin(); itStyle != maUserStyles.end(); ++itStyle )
1648 // #i1624# #i1768# ignore unnamed user styles
1649 if( !itStyle->GetName().isEmpty() )
1651 if( aCellStyles.count( itStyle->GetName() ) > 0 )
1652 aConflictNameStyles.push_back( &(*itStyle) );
1653 else
1654 aCellStyles[ itStyle->GetName() ] = &(*itStyle);
1658 // find unused names for all styles with conflicting names
1659 for( XclImpStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt )
1661 XclImpStyle* pStyle = *aIt;
1662 OUString aUnusedName;
1663 sal_Int32 nIndex = 0;
1666 aUnusedName = pStyle->GetName() + " " + OUString::number( ++nIndex );
1668 while( aCellStyles.count( aUnusedName ) > 0 );
1669 aCellStyles[ aUnusedName ] = pStyle;
1672 // set final names and create user-defined and modified built-in cell styles
1673 for( CellStyleNameMap::iterator aIt = aCellStyles.begin(), aEnd = aCellStyles.end(); aIt != aEnd; ++aIt )
1674 if( aIt->second )
1675 aIt->second->CreateUserStyle( aIt->first );
1678 ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex )
1680 XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex );
1681 return (aIt == maStylesByXf.end()) ? 0 : aIt->second->CreateStyleSheet();
1684 // Buffer for XF indexes in cells =============================================
1686 IMPL_FIXEDMEMPOOL_NEWDEL( XclImpXFRange )
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 )
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( new XclImpXFRange( 0, 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 ]) : 0;
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, 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 = 0;
1808 rnNextIndex = 0;
1809 return;
1812 rpPrevRange = &maIndexList.front();
1813 rpNextRange = &maIndexList.back();
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 = 0;
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 = 0;
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];
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];
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 ].reset( new 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 )
1912 const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex );
1913 if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) )
1915 // expand last merged range if this attribute is set repeatedly
1916 ScRange* pRange = maMergeList.empty() ? NULL : maMergeList.back();
1917 if (pRange && (pRange->aEnd.Row() == nScRow) && (pRange->aEnd.Col() + 1 == nScCol) && (eMode == xlXFModeBlank))
1918 pRange->aEnd.IncCol();
1919 else if( eMode != xlXFModeBlank ) // do not merge empty cells
1920 SetMerge( nScCol, nScRow );
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 <= 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 ].reset( new XclImpXFRangeColumn );
1954 maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) );
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 = static_cast< const SvxBoxItem* >(
1964 rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
1965 const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
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.push_back( XclImpHyperlinkRange( rXclRange, rUrl ) );
1978 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol, SCROW nScRow )
1980 maMergeList.Append( ScRange( nScCol, nScRow, 0 ) );
1983 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 )
1985 if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) )
1986 maMergeList.Append( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) );
1989 void XclImpXFRangeBuffer::Finalize()
1991 ScDocumentImport& rDoc = GetDocImport();
1992 SCTAB nScTab = GetCurrScTab();
1994 // apply patterns
1995 XclImpXFBuffer& rXFBuffer = GetXFBuffer();
1996 for( XclImpXFRangeColumnVec::const_iterator aVBeg = maColumns.begin(), aVEnd = maColumns.end(), aVIt = aVBeg; aVIt != aVEnd; ++aVIt )
1998 // apply all cell styles of an existing column
1999 if( aVIt->get() )
2001 XclImpXFRangeColumn& rColumn = **aVIt;
2002 SCCOL nScCol = static_cast< SCCOL >( aVIt - aVBeg );
2003 list<ScAttrEntry> aAttrs;
2005 for (XclImpXFRangeColumn::IndexList::iterator itr = rColumn.begin(), itrEnd = rColumn.end();
2006 itr != itrEnd; ++itr)
2008 XclImpXFRange& rStyle = *itr;
2009 const XclImpXFIndex& rXFIndex = rStyle.maXFIndex;
2010 XclImpXF* pXF = rXFBuffer.GetXF( rXFIndex.GetXFIndex() );
2011 if (!pXF)
2012 continue;
2014 sal_uInt32 nForceScNumFmt = rXFIndex.IsBoolCell() ?
2015 GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND;
2017 pXF->ApplyPatternToAttrList(aAttrs, rStyle.mnScRow1, rStyle.mnScRow2, nForceScNumFmt);
2020 if (aAttrs.empty() || aAttrs.back().nRow != MAXROW)
2022 ScAttrEntry aEntry;
2023 aEntry.nRow = MAXROW;
2024 aEntry.pPattern = rDoc.getDoc().GetDefPattern();
2025 aAttrs.push_back(aEntry);
2028 ScDocumentImport::Attrs aAttrParam;
2029 aAttrParam.mnSize = aAttrs.size();
2030 assert(aAttrParam.mnSize > 0);
2031 aAttrParam.mpData = new ScAttrEntry[aAttrParam.mnSize];
2032 aAttrParam.mbLatinNumFmtOnly = false; // when unsure, set it to false.
2033 list<ScAttrEntry>::const_iterator itr = aAttrs.begin(), itrEnd = aAttrs.end();
2034 for (size_t i = 0; itr != itrEnd; ++itr, ++i)
2035 aAttrParam.mpData[i] = *itr;
2037 rDoc.setAttrEntries(nScTab, nScCol, aAttrParam);
2041 // insert hyperlink cells
2042 for( XclImpHyperlinkList::const_iterator aLIt = maHyperlinks.begin(), aLEnd = maHyperlinks.end(); aLIt != aLEnd; ++aLIt )
2043 XclImpHyperlink::InsertUrl( GetRoot(), aLIt->first, aLIt->second );
2045 // apply cell merging
2046 for ( size_t i = 0, nRange = maMergeList.size(); i < nRange; ++i )
2048 const ScRange* pRange = maMergeList[ i ];
2049 const ScAddress& rStart = pRange->aStart;
2050 const ScAddress& rEnd = pRange->aEnd;
2051 bool bMultiCol = rStart.Col() != rEnd.Col();
2052 bool bMultiRow = rStart.Row() != rEnd.Row();
2053 // set correct right border
2054 if( bMultiCol )
2055 SetBorderLine( *pRange, nScTab, SvxBoxItemLine::RIGHT );
2056 // set correct lower border
2057 if( bMultiRow )
2058 SetBorderLine( *pRange, nScTab, SvxBoxItemLine::BOTTOM );
2059 // do merge
2060 if( bMultiCol || bMultiRow )
2061 rDoc.getDoc().DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
2062 // #i93609# merged range in a single row: test if manual row height is needed
2063 if( !bMultiRow )
2065 bool bTextWrap = static_cast<const SfxBoolItem*>( rDoc.getDoc().GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue();
2066 if( !bTextWrap && (rDoc.getDoc().GetCellType( rStart ) == CELLTYPE_EDIT) )
2067 if (const EditTextObject* pEditObj = rDoc.getDoc().GetEditText(rStart))
2068 bTextWrap = pEditObj->GetParagraphCount() > 1;
2069 if( bTextWrap )
2070 GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
2075 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */