merge the formfield patch from ooo-build
[ooovba.git] / sc / source / filter / excel / xistyle.cxx
blob9744666172b1f49b02e4fec888eb6020a83daa49
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xistyle.cxx,v $
10 * $Revision: 1.38.14.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 #include "xistyle.hxx"
34 #include <sfx2/printer.hxx>
35 #include <sfx2/objsh.hxx>
36 #include <svtools/ctrltool.hxx>
37 #include <svx/editobj.hxx>
38 #include "scitems.hxx"
39 #include <svx/fontitem.hxx>
40 #include <svx/fhgtitem.hxx>
41 #include <svx/wghtitem.hxx>
42 #include <svx/udlnitem.hxx>
43 #include <svx/postitem.hxx>
44 #include <svx/crsditem.hxx>
45 #include <svx/cntritem.hxx>
46 #include <svx/shdditem.hxx>
47 #include <svx/escpitem.hxx>
48 #include <svx/algitem.hxx>
49 #include <svx/boxitem.hxx>
50 #include <svx/bolnitem.hxx>
51 #include <svx/rotmodit.hxx>
52 #include <svx/colritem.hxx>
53 #include <svx/brshitem.hxx>
54 #include <svx/frmdiritem.hxx>
55 #include <svx/eeitem.hxx>
56 #include <svx/flstitem.hxx>
57 #include "document.hxx"
58 #include "docpool.hxx"
59 #include "attrib.hxx"
60 #include "stlpool.hxx"
61 #include "stlsheet.hxx"
62 #include "cell.hxx"
63 #include "globstr.hrc"
64 #include "xltracer.hxx"
65 #include "xistream.hxx"
66 #include "xicontent.hxx"
68 #include "root.hxx"
69 #include "colrowst.hxx"
71 #include <cppuhelper/implbase1.hxx>
72 #include <com/sun/star/container/XIndexAccess.hpp>
73 #include <com/sun/star/beans/XPropertySet.hpp>
74 using namespace ::com::sun::star;
76 typedef ::cppu::WeakImplHelper1< container::XIndexAccess > XIndexAccess_BASE;
77 typedef ::std::vector< ColorData > ColorDataVec;
79 class PaletteIndex : public XIndexAccess_BASE
81 public:
82 PaletteIndex( const ColorDataVec& rColorDataTable ) : maColorData( rColorDataTable ) {}
84 // Methods XIndexAccess
85 virtual ::sal_Int32 SAL_CALL getCount() throw (uno::RuntimeException)
87 return maColorData.size();
90 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException)
92 //--Index; // apparently the palette is already 1 based
93 return uno::makeAny( sal_Int32( maColorData[ Index ] ) );
96 // Methods XElementAcess
97 virtual uno::Type SAL_CALL getElementType() throw (uno::RuntimeException)
99 return ::getCppuType( (sal_Int32*)0 );
101 virtual ::sal_Bool SAL_CALL hasElements() throw (uno::RuntimeException)
103 return (maColorData.size() > 0);
106 private:
107 ColorDataVec maColorData;
110 void
111 XclImpPalette::ExportPalette()
113 if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
115 // copy values in color palette
116 sal_Int16 nColors = maColorTable.size();
117 ColorDataVec aColors;
118 aColors.resize( nColors );
119 for( sal_uInt16 nIndex = 0; nIndex < nColors; ++nIndex )
120 aColors[ nIndex ] = GetColorData( nIndex );
122 uno::Reference< beans::XPropertySet > xProps( pDocShell->GetModel(), uno::UNO_QUERY );
123 if ( xProps.is() )
125 uno::Reference< container::XIndexAccess > xIndex( new PaletteIndex( aColors ) );
126 xProps->setPropertyValue( CREATE_OUSTRING("ColorPalette"), uno::makeAny( xIndex ) );
131 // PALETTE record - color information =========================================
133 XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) :
134 XclDefaultPalette( rRoot ), mrRoot( rRoot )
138 void XclImpPalette::Initialize()
140 maColorTable.clear();
143 ColorData XclImpPalette::GetColorData( sal_uInt16 nXclIndex ) const
145 if( nXclIndex >= EXC_COLOR_USEROFFSET )
147 sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET;
148 if( nIx < maColorTable.size() )
149 return maColorTable[ nIx ];
151 return GetDefColorData( nXclIndex );
154 void XclImpPalette::ReadPalette( XclImpStream& rStrm )
156 sal_uInt16 nCount;
157 rStrm >> nCount;
158 DBG_ASSERT( rStrm.GetRecLeft() == static_cast< sal_Size >( 4 * nCount ),
159 "XclImpPalette::ReadPalette - size mismatch" );
161 maColorTable.resize( nCount );
162 Color aColor;
163 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
165 rStrm >> aColor;
166 maColorTable[ nIndex ] = aColor.GetColor();
168 ExportPalette();
171 // FONT record - font information =============================================
173 XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
174 XclImpRoot( rRoot ),
175 mbHasCharSet( false ),
176 mbHasWstrn( true ),
177 mbHasAsian( false ),
178 mbHasCmplx( false )
180 SetAllUsedFlags( false );
183 XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
184 XclImpRoot( rRoot )
186 SetFontData( rFontData, false );
189 void XclImpFont::SetAllUsedFlags( bool bUsed )
191 mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed =
192 mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed;
195 void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet )
197 maData = rFontData;
198 mbHasCharSet = bHasCharSet;
199 if( maData.maStyle.Len() )
201 if( SfxObjectShell* pDocShell = GetDocShell() )
203 if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
204 pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
206 if( const FontList* pFontList = pInfoItem->GetFontList() )
208 FontInfo aFontInfo( pFontList->Get( maData.maName, maData.maStyle ) );
209 maData.SetScWeight( aFontInfo.GetWeight() );
210 maData.SetScPosture( aFontInfo.GetItalic() );
214 maData.maStyle.Erase();
216 GuessScriptType();
217 SetAllUsedFlags( true );
220 rtl_TextEncoding XclImpFont::GetFontEncoding() const
222 // #i63105# use text encoding from FONT record
223 // #i67768# BIFF2-BIFF4 FONT records do not contain character set
224 rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding();
225 return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc;
228 void XclImpFont::ReadFont( XclImpStream& rStrm )
230 switch( GetBiff() )
232 case EXC_BIFF2:
233 ReadFontData2( rStrm );
234 ReadFontName2( rStrm );
235 break;
236 case EXC_BIFF3:
237 case EXC_BIFF4:
238 ReadFontData2( rStrm );
239 ReadFontColor( rStrm );
240 ReadFontName2( rStrm );
241 break;
242 case EXC_BIFF5:
243 ReadFontData5( rStrm );
244 ReadFontName2( rStrm );
245 break;
246 case EXC_BIFF8:
247 ReadFontData5( rStrm );
248 ReadFontName8( rStrm );
249 break;
250 default:
251 DBG_ERROR_BIFF();
252 return;
254 GuessScriptType();
255 SetAllUsedFlags( true );
258 void XclImpFont::ReadEfont( XclImpStream& rStrm )
260 ReadFontColor( rStrm );
263 void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm )
265 DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
266 if( GetBiff() != EXC_BIFF8 )
267 return;
269 sal_uInt32 nHeight, nStyle, nColor, nFontFlags1, nFontFlags2, nFontFlags3;
270 sal_uInt16 nWeight, nEscapem;
271 sal_uInt8 nUnderl;
273 rStrm.Ignore( 64 );
274 rStrm >> nHeight >> nStyle >> nWeight >> nEscapem >> nUnderl;
275 rStrm.Ignore( 3 );
276 rStrm >> nColor;
277 rStrm.Ignore( 4 );
278 rStrm >> nFontFlags1 >> nFontFlags2 >> nFontFlags3;
279 rStrm.Ignore( 18 );
281 if( (mbHeightUsed = (nHeight <= 0x7FFF)) == true )
282 maData.mnHeight = static_cast< sal_uInt16 >( nHeight );
283 if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) == true )
284 maData.mnWeight = static_cast< sal_uInt16 >( nWeight );
285 if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) == true )
286 maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE );
287 if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) == true )
288 maData.mnUnderline = nUnderl;
289 if( (mbColorUsed = (nColor <= 0x7FFF)) == true )
290 maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) );
291 if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) == true )
292 maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT );
295 void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const
297 // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
298 bool bEE = eType != EXC_FONTITEM_CELL;
300 // item = the item to put into the item set
301 // sc_which = the Calc Which-ID of the item
302 // ee_which = the edit engine Which-ID of the item
303 #define PUTITEM( item, sc_which, ee_which ) \
304 ScfTools::PutItem( rItemSet, item, (bEE ? (ee_which) : (sc_which)), bSkipPoolDefs )
306 // Font item
307 // #i36997# do not set default Tahoma font from notes
308 bool bDefNoteFont = (eType == EXC_FONTITEM_NOTE) && (maData.maName.EqualsIgnoreCaseAscii( "Tahoma" ));
309 if( mbFontNameUsed && !bDefNoteFont )
311 rtl_TextEncoding eFontEnc = maData.GetFontEncoding();
312 rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ?
313 ScfTools::GetSystemTextEncoding() : eFontEnc;
315 SvxFontItem aFontItem( maData.GetScFamily( GetTextEncoding() ), maData.maName, EMPTY_STRING,
316 PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT );
317 // #91658# set only for valid script types
318 if( mbHasWstrn )
319 PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO );
320 if( mbHasAsian )
321 PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK );
322 if( mbHasCmplx )
323 PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL );
326 // Font height (for all script types)
327 if( mbHeightUsed )
329 sal_Int32 nHeight = maData.mnHeight;
330 if( bEE && (eType != EXC_FONTITEM_HF) ) // do not convert header/footer height
331 nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH; // #98527# 1 in == 72 pt
333 SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT );
334 PUTITEM( aHeightItem, ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT );
335 PUTITEM( aHeightItem, ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK );
336 PUTITEM( aHeightItem, ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL );
339 // Font color - pass AUTO_COL to item
340 if( mbColorUsed )
341 PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
343 // Font weight (for all script types)
344 if( mbWeightUsed )
346 SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT );
347 PUTITEM( aWeightItem, ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT );
348 PUTITEM( aWeightItem, ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK );
349 PUTITEM( aWeightItem, ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL );
352 // Font underline
353 if( mbUnderlUsed )
355 SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
356 PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE );
359 // Font posture (for all script types)
360 if( mbItalicUsed )
362 SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE );
363 PUTITEM( aPostItem, ATTR_FONT_POSTURE, EE_CHAR_ITALIC );
364 PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK );
365 PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL );
368 // Boolean attributes crossed out, contoured, shadowed
369 if( mbStrikeUsed )
370 PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
371 if( mbOutlineUsed )
372 PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
373 if( mbShadowUsed )
374 PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW );
376 // Super-/subscript: only on edit engine objects
377 if( mbEscapemUsed && bEE )
378 rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) );
380 #undef PUTITEM
383 void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet,
384 XclFontPropSetType eType, const Color* pFontColor ) const
386 GetFontPropSetHelper().WriteFontProperties(
387 rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor );
390 void XclImpFont::ReadFontData2( XclImpStream& rStrm )
392 sal_uInt16 nFlags;
393 rStrm >> maData.mnHeight >> nFlags;
395 maData.mnWeight = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL );
396 maData.mnUnderline = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE );
397 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
398 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
399 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
400 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
401 mbHasCharSet = false;
404 void XclImpFont::ReadFontData5( XclImpStream& rStrm )
406 sal_uInt16 nFlags;
408 rStrm >> maData.mnHeight >> nFlags;
409 ReadFontColor( rStrm );
410 rStrm >> maData.mnWeight >> maData.mnEscapem >> maData.mnUnderline >> maData.mnFamily >> maData.mnCharSet;
411 rStrm.Ignore( 1 );
413 maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
414 maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
415 maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
416 maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
417 mbHasCharSet = true;
420 void XclImpFont::ReadFontColor( XclImpStream& rStrm )
422 maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() );
425 void XclImpFont::ReadFontName2( XclImpStream& rStrm )
427 maData.maName = rStrm.ReadByteString( false );
430 void XclImpFont::ReadFontName8( XclImpStream& rStrm )
432 maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() );
435 void XclImpFont::GuessScriptType()
437 mbHasWstrn = true;
438 mbHasAsian = mbHasCmplx = false;
440 // #91658# #113783# find the script types for which the font contains characters
441 if( OutputDevice* pPrinter = GetPrinter() )
443 Font aFont( maData.maName, Size( 0, 10 ) );
444 FontCharMap aCharMap;
446 pPrinter->SetFont( aFont );
447 if( pPrinter->GetFontCharMap( aCharMap ) )
449 // #91658# CJK fonts
450 mbHasAsian =
451 aCharMap.HasChar( 0x3041 ) || // 3040-309F: Hiragana
452 aCharMap.HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
453 aCharMap.HasChar( 0x3111 ) || // 3100-312F: Bopomofo
454 aCharMap.HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
455 aCharMap.HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
456 aCharMap.HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
457 aCharMap.HasChar( 0x4E01 ) || // 4E00-9FAF: CJK Unified Ideographs
458 aCharMap.HasChar( 0x7E01 ) || // 4E00-9FAF: CJK unified ideographs
459 aCharMap.HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
460 aCharMap.HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
461 aCharMap.HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
462 aCharMap.HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
463 aCharMap.HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
464 // #113783# CTL fonts
465 mbHasCmplx =
466 aCharMap.HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
467 aCharMap.HasChar( 0x0631 ) || // 0600-06FF: Arabic
468 aCharMap.HasChar( 0x0721 ) || // 0700-074F: Syriac
469 aCharMap.HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
470 aCharMap.HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
471 aCharMap.HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
472 aCharMap.HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
473 aCharMap.HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
474 // Western fonts
475 mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || aCharMap.HasChar( 'A' );
480 // ----------------------------------------------------------------------------
482 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
483 XclImpRoot( rRoot ),
484 maFont4( rRoot ),
485 maCtrlFont( rRoot )
487 Initialize();
489 // default font for form controls without own font information
490 XclFontData aCtrlFontData;
491 switch( GetBiff() )
493 case EXC_BIFF2:
494 case EXC_BIFF3:
495 case EXC_BIFF4:
496 case EXC_BIFF5:
497 aCtrlFontData.maName.AssignAscii( "Helv" );
498 aCtrlFontData.mnHeight = 160;
499 aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
500 break;
501 case EXC_BIFF8:
502 aCtrlFontData.maName.AssignAscii( "Tahoma" );
503 aCtrlFontData.mnHeight = 160;
504 aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
505 break;
506 default:
507 DBG_ERROR_BIFF();
509 maCtrlFont.SetFontData( aCtrlFontData, false );
512 void XclImpFontBuffer::Initialize()
514 maFontList.Clear();
516 // application font for column width calculation, later filled with first font from font list
517 XclFontData aAppFontData;
518 aAppFontData.maName.AssignAscii( "Arial" );
519 aAppFontData.mnHeight = 200;
520 aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL;
521 UpdateAppFont( aAppFontData, false );
524 const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const
526 /* Font with index 4 is not stored in an Excel file, but used e.g. by
527 BIFF5 form pushbutton objects. It is the bold default font. */
528 return (nFontIndex == 4) ? &maFont4 :
529 maFontList.GetObject( (nFontIndex < 4) ? nFontIndex : (nFontIndex - 1) );
532 void XclImpFontBuffer::ReadFont( XclImpStream& rStrm )
534 XclImpFont* pFont = new XclImpFont( GetRoot() );
535 pFont->ReadFont( rStrm );
536 maFontList.Append( pFont );
538 if( maFontList.Count() == 1 )
540 UpdateAppFont( pFont->GetFontData(), pFont->HasCharSet() );
541 // #i71033# set text encoding from application font, if CODEPAGE is missing
542 SetAppFontEncoding( pFont->GetFontEncoding() );
546 void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm )
548 if( XclImpFont* pFont = maFontList.Last() )
549 pFont->ReadEfont( rStrm );
552 void XclImpFontBuffer::FillToItemSet(
553 SfxItemSet& rItemSet, XclFontItemType eType,
554 sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const
556 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
557 pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs );
560 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet,
561 XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const
563 if( const XclImpFont* pFont = GetFont( nFontIdx ) )
564 pFont->WriteFontProperties( rPropSet, eType, pFontColor );
567 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const
569 maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL );
572 void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet )
574 maAppFont = rFontData;
575 // #i3006# Calculate the width of '0' from first font and current printer.
576 SetCharWidth( maAppFont );
578 // font 4 is bold font 0
579 XclFontData aFont4Data( maAppFont );
580 aFont4Data.mnWeight = EXC_FONTWGHT_BOLD;
581 maFont4.SetFontData( aFont4Data, bHasCharSet );
584 // FORMAT record - number formats =============================================
586 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) :
587 XclNumFmtBuffer( rRoot ),
588 XclImpRoot( rRoot ),
589 mnNextXclIdx( 0 )
593 void XclImpNumFmtBuffer::Initialize()
595 maIndexMap.clear();
596 mnNextXclIdx = 0;
597 InitializeImport(); // base class
600 void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
602 String aFormat;
603 switch( GetBiff() )
605 case EXC_BIFF2:
606 case EXC_BIFF3:
607 aFormat = rStrm.ReadByteString( false );
608 break;
610 case EXC_BIFF4:
611 rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
612 aFormat = rStrm.ReadByteString( false );
613 break;
615 case EXC_BIFF5:
616 rStrm >> mnNextXclIdx;
617 aFormat = rStrm.ReadByteString( false );
618 break;
620 case EXC_BIFF8:
621 rStrm >> mnNextXclIdx;
622 aFormat = rStrm.ReadUniString();
623 break;
625 default:
626 DBG_ERROR_BIFF();
627 return;
630 if( mnNextXclIdx < 0xFFFF )
632 InsertFormat( mnNextXclIdx, aFormat );
633 ++mnNextXclIdx;
637 void XclImpNumFmtBuffer::CreateScFormats()
639 DBG_ASSERT( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
641 SvNumberFormatter& rFormatter = GetFormatter();
642 for( XclNumFmtMap::const_iterator aIt = GetFormatMap().begin(), aEnd = GetFormatMap().end(); aIt != aEnd; ++aIt )
644 const XclNumFmt& rNumFmt = aIt->second;
646 // insert/convert the Excel number format
647 xub_StrLen nCheckPos;
648 short nType = NUMBERFORMAT_DEFINED;
649 sal_uInt32 nKey;
650 if( rNumFmt.maFormat.Len() )
652 String aFormat( rNumFmt.maFormat );
653 rFormatter.PutandConvertEntry( aFormat, nCheckPos,
654 nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage );
656 else
657 nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage );
659 // insert the resulting format key into the Excel->Calc index map
660 maIndexMap[ aIt->first ] = nKey;
664 ULONG XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const
666 XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt );
667 return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND;
670 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const
672 ULONG nScNumFmt = GetScFormat( nXclNumFmt );
673 if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND )
674 nScNumFmt = GetStdScNumFmt();
675 FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs );
678 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, ULONG nScNumFmt, bool bSkipPoolDefs ) const
680 DBG_ASSERT( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
681 ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
682 if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, FALSE ) == SFX_ITEM_SET )
683 ScGlobal::AddLanguage( rItemSet, GetFormatter() );
686 // XF, STYLE record - Cell formatting =========================================
688 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt )
690 mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED );
691 mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN );
694 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt )
696 mbLocked = ::get_flag( nProt, EXC_XF_LOCKED );
697 mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN );
700 void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
702 ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs );
706 // ----------------------------------------------------------------------------
708 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags )
710 mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 );
713 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign )
715 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
716 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); // new in BIFF3
719 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign )
721 FillFromXF3( nAlign );
722 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 ); // new in BIFF4
723 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 ); // new in BIFF4
726 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign )
728 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
729 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
730 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
731 mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 );
734 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
736 mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
737 mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
738 mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
739 mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 ); // new in BIFF8
740 mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
741 mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK ); // new in BIFF8
742 mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 ); // new in BIFF8
745 void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const
747 // horizontal alignment
748 ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs );
750 // text wrap (#i74508# always if vertical alignment is justified or distributed)
751 bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB);
752 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs );
754 // vertical alignment
755 ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs );
757 // indent
758 sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
759 ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs );
761 // shrink to fit
762 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs );
764 // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
765 sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient );
766 bool bStacked = (nXclRot == EXC_ROT_STACKED);
767 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs );
768 ScfTools::PutItem( rItemSet, SvxRotateModeItem( SVX_ROTATE_MODE_STANDARD, ATTR_ROTATE_MODE ), bSkipPoolDefs );
769 // set an angle in the range from -90 to 90 degrees
770 sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 );
771 ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs );
772 // #105933# set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
773 bool bAsianVert = bStacked && pFont && pFont->HasAsianChars();
774 ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs );
776 // CTL text direction
777 ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs );
780 // ----------------------------------------------------------------------------
782 XclImpCellBorder::XclImpCellBorder()
784 SetUsedFlags( false, false );
787 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed )
789 mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed;
790 mbDiagUsed = bDiagUsed;
793 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags )
795 mnLeftLine = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
796 mnRightLine = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
797 mnTopLine = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE, EXC_LINE_THIN, EXC_LINE_NONE );
798 mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE );
799 mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK;
800 SetUsedFlags( true, false );
803 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder )
805 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
806 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 8, 3 );
807 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder, 16, 3 );
808 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 24, 3 );
809 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 3, 5 );
810 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 11, 5 );
811 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 );
812 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 27, 5 );
813 SetUsedFlags( true, false );
816 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea )
818 mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
819 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 3, 3 );
820 mnBottomLine = ::extract_value< sal_uInt8 >( nArea, 22, 3 );
821 mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 6, 3 );
822 mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 9, 7 );
823 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 16, 7 );
824 mnBottomColor = ::extract_value< sal_uInt16 >( nArea, 25, 7 );
825 mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 23, 7 );
826 SetUsedFlags( true, false );
829 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
831 mnLeftLine = ::extract_value< sal_uInt8 >( nBorder1, 0, 4 );
832 mnRightLine = ::extract_value< sal_uInt8 >( nBorder1, 4, 4 );
833 mnTopLine = ::extract_value< sal_uInt8 >( nBorder1, 8, 4 );
834 mnBottomLine = ::extract_value< sal_uInt8 >( nBorder1, 12, 4 );
835 mnLeftColor = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 );
836 mnRightColor = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 );
837 mnTopColor = ::extract_value< sal_uInt16 >( nBorder2, 0, 7 );
838 mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2, 7, 7 );
839 mbDiagTLtoBR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR );
840 mbDiagBLtoTR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR );
841 if( mbDiagTLtoBR || mbDiagBLtoTR )
843 mnDiagLine = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 );
844 mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 );
846 SetUsedFlags( true, true );
849 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags )
851 mnLeftLine = ::extract_value< sal_uInt8 >( nLineStyle, 0, 4 );
852 mnRightLine = ::extract_value< sal_uInt8 >( nLineStyle, 4, 4 );
853 mnTopLine = ::extract_value< sal_uInt8 >( nLineStyle, 8, 4 );
854 mnBottomLine = ::extract_value< sal_uInt8 >( nLineStyle, 12, 4 );
855 mnLeftColor = ::extract_value< sal_uInt16 >( nLineColor, 0, 7 );
856 mnRightColor = ::extract_value< sal_uInt16 >( nLineColor, 7, 7 );
857 mnTopColor = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 );
858 mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 );
859 mbLeftUsed = !::get_flag( nFlags, EXC_CF_BORDER_LEFT );
860 mbRightUsed = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT );
861 mbTopUsed = !::get_flag( nFlags, EXC_CF_BORDER_TOP );
862 mbBottomUsed = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM );
863 mbDiagUsed = false;
866 namespace {
868 /** Converts the passed line style to a SvxBorderLine, or returns false, if style is "no line". */
869 bool lclConvertBorderLine( SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor )
871 static const sal_uInt16 ppnLineParam[][ 3 ] =
873 // outer width, inner width, distance
874 { 0, 0, 0 }, // 0 = none
875 { DEF_LINE_WIDTH_1, 0, 0 }, // 1 = thin
876 { DEF_LINE_WIDTH_2, 0, 0 }, // 2 = medium
877 { DEF_LINE_WIDTH_1, 0, 0 }, // 3 = dashed
878 { DEF_LINE_WIDTH_0, 0, 0 }, // 4 = dotted
879 { DEF_LINE_WIDTH_3, 0, 0 }, // 5 = thick
880 { DEF_LINE_WIDTH_1, DEF_LINE_WIDTH_1, DEF_LINE_WIDTH_1 }, // 6 = double
881 { DEF_LINE_WIDTH_0, 0, 0 }, // 7 = hair
882 { DEF_LINE_WIDTH_2, 0, 0 }, // 8 = med dash
883 { DEF_LINE_WIDTH_1, 0, 0 }, // 9 = thin dashdot
884 { DEF_LINE_WIDTH_2, 0, 0 }, // A = med dashdot
885 { DEF_LINE_WIDTH_1, 0, 0 }, // B = thin dashdotdot
886 { DEF_LINE_WIDTH_2, 0, 0 }, // C = med dashdotdot
887 { DEF_LINE_WIDTH_2, 0, 0 } // D = med slant dashdot
890 if( nXclLine == EXC_LINE_NONE )
891 return false;
892 if( nXclLine >= STATIC_TABLE_SIZE( ppnLineParam ) )
893 nXclLine = EXC_LINE_THIN;
895 rLine.SetColor( rPalette.GetColor( nXclColor ) );
896 rLine.SetOutWidth( ppnLineParam[ nXclLine ][ 0 ] );
897 rLine.SetInWidth( ppnLineParam[ nXclLine ][ 1 ] );
898 rLine.SetDistance( ppnLineParam[ nXclLine ][ 2 ] );
899 return true;
902 } // namespace
904 void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
906 if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed )
908 SvxBoxItem aBoxItem( ATTR_BORDER );
909 SvxBorderLine aLine;
910 if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) )
911 aBoxItem.SetLine( &aLine, BOX_LINE_LEFT );
912 if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) )
913 aBoxItem.SetLine( &aLine, BOX_LINE_RIGHT );
914 if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) )
915 aBoxItem.SetLine( &aLine, BOX_LINE_TOP );
916 if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) )
917 aBoxItem.SetLine( &aLine, BOX_LINE_BOTTOM );
918 ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs );
920 if( mbDiagUsed )
922 SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
923 SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
924 SvxBorderLine aLine;
925 if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
927 if( mbDiagTLtoBR )
928 aTLBRItem.SetLine( &aLine );
929 if( mbDiagBLtoTR )
930 aBLTRItem.SetLine( &aLine );
932 ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs );
933 ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs );
937 // ----------------------------------------------------------------------------
939 XclImpCellArea::XclImpCellArea()
941 SetUsedFlags( false );
944 void XclImpCellArea::SetUsedFlags( bool bUsed )
946 mbForeUsed = mbBackUsed = mbPattUsed = bUsed;
949 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags )
951 mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE );
952 mnForeColor = EXC_COLOR_BIFF2_BLACK;
953 mnBackColor = EXC_COLOR_BIFF2_WHITE;
954 SetUsedFlags( true );
957 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea )
959 mnPattern = ::extract_value< sal_uInt8 >( nArea, 0, 6 );
960 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 6, 5 );
961 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 );
962 SetUsedFlags( true );
965 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea )
967 mnPattern = ::extract_value< sal_uInt8 >( nArea, 16, 6 );
968 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
969 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
970 SetUsedFlags( true );
973 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea )
975 mnPattern = ::extract_value< sal_uInt8 >( nBorder2, 26, 6 );
976 mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
977 mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
978 SetUsedFlags( true );
981 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags )
983 mnForeColor = ::extract_value< sal_uInt16 >( nColor, 0, 7 );
984 mnBackColor = ::extract_value< sal_uInt16 >( nColor, 7, 7 );
985 mnPattern = ::extract_value< sal_uInt8 >( nPattern, 10, 6 );
986 mbForeUsed = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR );
987 mbBackUsed = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR );
988 mbPattUsed = !::get_flag( nFlags, EXC_CF_AREA_PATTERN );
990 if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) )
992 mnForeColor = mnBackColor;
993 mnPattern = EXC_PATT_SOLID;
994 mbForeUsed = mbPattUsed = true;
996 else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) )
998 mbPattUsed = false;
1002 void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
1004 if( mbPattUsed ) // colors may be both unused in cond. formats
1006 SvxBrushItem aBrushItem( ATTR_BACKGROUND );
1008 // #108935# do not use IsTransparent() - old Calc filter writes tranparency with different color indexes
1009 if( mnPattern == EXC_PATT_NONE )
1011 aBrushItem.SetColor( Color( COL_TRANSPARENT ) );
1013 else
1015 Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) );
1016 Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) );
1017 aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) );
1020 ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs );
1025 // ----------------------------------------------------------------------------
1027 XclImpXF::XclImpXF( const XclImpRoot& rRoot ) :
1028 XclXFBase( true ), // default is cell XF
1029 XclImpRoot( rRoot ),
1030 mpStyleSheet( 0 ),
1031 mnXclNumFmt( 0 ),
1032 mnXclFont( 0 )
1036 XclImpXF::~XclImpXF()
1040 void XclImpXF::ReadXF2( XclImpStream& rStrm )
1042 sal_uInt8 nReadFont, nReadNumFmt, nFlags;
1043 rStrm >> nReadFont;
1044 rStrm.Ignore( 1 );
1045 rStrm >> nReadNumFmt >> nFlags;
1047 // XF type always cell, no parent, used flags always true
1048 SetAllUsedFlags( true );
1050 // attributes
1051 maProtection.FillFromXF2( nReadNumFmt );
1052 mnXclFont = nReadFont;
1053 mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK;
1054 maAlignment.FillFromXF2( nFlags );
1055 maBorder.FillFromXF2( nFlags );
1056 maArea.FillFromXF2( nFlags );
1059 void XclImpXF::ReadXF3( XclImpStream& rStrm )
1061 sal_uInt32 nBorder;
1062 sal_uInt16 nTypeProt, nAlign, nArea;
1063 sal_uInt8 nReadFont, nReadNumFmt;
1064 rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
1066 // XF type/parent, attribute used flags
1067 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); // new in BIFF3
1068 mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 ); // new in BIFF3
1069 SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) );
1071 // attributes
1072 maProtection.FillFromXF3( nTypeProt );
1073 mnXclFont = nReadFont;
1074 mnXclNumFmt = nReadNumFmt;
1075 maAlignment.FillFromXF3( nAlign );
1076 maBorder.FillFromXF3( nBorder );
1077 maArea.FillFromXF3( nArea ); // new in BIFF3
1080 void XclImpXF::ReadXF4( XclImpStream& rStrm )
1082 sal_uInt32 nBorder;
1083 sal_uInt16 nTypeProt, nAlign, nArea;
1084 sal_uInt8 nReadFont, nReadNumFmt;
1085 rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
1087 // XF type/parent, attribute used flags
1088 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1089 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1090 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1092 // attributes
1093 maProtection.FillFromXF3( nTypeProt );
1094 mnXclFont = nReadFont;
1095 mnXclNumFmt = nReadNumFmt;
1096 maAlignment.FillFromXF4( nAlign );
1097 maBorder.FillFromXF3( nBorder );
1098 maArea.FillFromXF3( nArea );
1101 void XclImpXF::ReadXF5( XclImpStream& rStrm )
1103 sal_uInt32 nArea, nBorder;
1104 sal_uInt16 nTypeProt, nAlign;
1105 rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
1107 // XF type/parent, attribute used flags
1108 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1109 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1110 SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1112 // attributes
1113 maProtection.FillFromXF3( nTypeProt );
1114 maAlignment.FillFromXF5( nAlign );
1115 maBorder.FillFromXF5( nBorder, nArea );
1116 maArea.FillFromXF5( nArea );
1119 void XclImpXF::ReadXF8( XclImpStream& rStrm )
1121 sal_uInt32 nBorder1, nBorder2;
1122 sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea;
1123 rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nMiscAttrib >> nBorder1 >> nBorder2 >> nArea;
1125 // XF type/parent, attribute used flags
1126 mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1127 mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1128 SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
1130 // attributes
1131 maProtection.FillFromXF3( nTypeProt );
1132 maAlignment.FillFromXF8( nAlign, nMiscAttrib );
1133 maBorder.FillFromXF8( nBorder1, nBorder2 );
1134 maArea.FillFromXF8( nBorder2, nArea );
1137 void XclImpXF::ReadXF( XclImpStream& rStrm )
1139 switch( GetBiff() )
1141 case EXC_BIFF2: ReadXF2( rStrm ); break;
1142 case EXC_BIFF3: ReadXF3( rStrm ); break;
1143 case EXC_BIFF4: ReadXF4( rStrm ); break;
1144 case EXC_BIFF5: ReadXF5( rStrm ); break;
1145 case EXC_BIFF8: ReadXF8( rStrm ); break;
1146 default: DBG_ERROR_BIFF();
1150 const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs )
1152 if( mpPattern.get() )
1153 return *mpPattern;
1155 // create new pattern attribute set
1156 mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) );
1157 SfxItemSet& rItemSet = mpPattern->GetItemSet();
1159 // parent cell style
1160 if( IsCellXF() && !mpStyleSheet )
1162 mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent );
1163 if( XclImpXF* pParentXF = GetXFBuffer().GetXF( mnParent ) )
1164 UpdateUsedFlags( *pParentXF );
1167 // cell protection
1168 if( mbProtUsed )
1169 maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
1171 // font
1172 if( mbFontUsed )
1173 GetFontBuffer().FillToItemSet( rItemSet, EXC_FONTITEM_CELL, mnXclFont, bSkipPoolDefs );
1175 // value format
1176 if( mbFmtUsed )
1178 GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
1179 // Trace occurrences of Windows date formats
1180 GetTracer().TraceDates( mnXclNumFmt );
1183 // alignment
1184 if( mbAlignUsed )
1185 maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
1187 // border
1188 if( mbBorderUsed )
1190 maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1191 GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR ||
1192 maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR ||
1193 maBorder.mnBottomLine > EXC_LINE_HAIR );
1196 // area
1197 if( mbAreaUsed )
1199 maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1200 GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE &&
1201 maArea.mnPattern != EXC_PATT_SOLID);
1204 return *mpPattern;
1207 void XclImpXF::ApplyPattern(
1208 SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2,
1209 SCTAB nScTab, ULONG nForceScNumFmt )
1211 // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1212 const ScPatternAttr& rPattern = CreatePattern();
1214 // insert into document
1215 ScDocument& rDoc = GetDoc();
1216 if( IsCellXF() && mpStyleSheet )
1217 rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet );
1218 if( HasUsedFlags() )
1219 rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern );
1221 // #108770# apply special number format
1222 if( nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
1224 ScPatternAttr aPattern( GetDoc().GetPool() );
1225 GetNumFmtBuffer().FillScFmtToItemSet( aPattern.GetItemSet(), nForceScNumFmt );
1226 rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, aPattern );
1230 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags )
1232 /* Notes about finding the mb***Used flags:
1233 - In cell XFs a *set* bit means a used attribute.
1234 - In style XFs a *cleared* bit means a used attribute.
1235 The mb***Used members always store true, if the attribute is used.
1236 The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1237 both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1239 mbProtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT ));
1240 mbFontUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT ));
1241 mbFmtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT ));
1242 mbAlignUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN ));
1243 mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER ));
1244 mbAreaUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA ));
1247 void XclImpXF::UpdateUsedFlags( const XclImpXF& rParentXF )
1249 /* Enables mb***Used flags, if the formatting attributes differ from
1250 the passed XF record. In cell XFs Excel uses the cell attributes,
1251 if they differ from the parent style XF.
1252 #109899# ...or if the respective flag is not set in parent style XF. */
1253 if( !mbProtUsed )
1254 mbProtUsed = !rParentXF.mbProtUsed || !(maProtection == rParentXF.maProtection);
1255 if( !mbFontUsed )
1256 mbFontUsed = !rParentXF.mbFontUsed || (mnXclFont != rParentXF.mnXclFont);
1257 if( !mbFmtUsed )
1258 mbFmtUsed = !rParentXF.mbFmtUsed || (mnXclNumFmt != rParentXF.mnXclNumFmt);
1259 if( !mbAlignUsed )
1260 mbAlignUsed = !rParentXF.mbAlignUsed || !(maAlignment == rParentXF.maAlignment);
1261 if( !mbBorderUsed )
1262 mbBorderUsed = !rParentXF.mbBorderUsed || !(maBorder == rParentXF.maBorder);
1263 if( !mbAreaUsed )
1264 mbAreaUsed = !rParentXF.mbAreaUsed || !(maArea == rParentXF.maArea);
1267 // ----------------------------------------------------------------------------
1269 XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) :
1270 XclImpRoot( rRoot ),
1271 mnXfId( EXC_XF_NOTFOUND ),
1272 mnBuiltinId( EXC_STYLE_USERDEF ),
1273 mnLevel( EXC_STYLE_NOLEVEL ),
1274 mbBuiltin( false ),
1275 mbCustom( false ),
1276 mbHidden( false ),
1277 mpStyleSheet( 0 )
1281 void XclImpStyle::ReadStyle( XclImpStream& rStrm )
1283 DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF3 );
1285 sal_uInt16 nXFIndex;
1286 rStrm >> nXFIndex;
1287 mnXfId = nXFIndex & EXC_STYLE_XFMASK;
1288 mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN );
1290 if( mbBuiltin )
1292 rStrm >> mnBuiltinId >> mnLevel;
1294 else
1296 maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
1297 // #i103281# check if this is a new built-in style introduced in XL2007
1298 if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() )
1300 sal_uInt8 nExtFlags;
1301 rStrm.Ignore( 12 );
1302 rStrm >> nExtFlags;
1303 mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN );
1304 mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM );
1305 mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN );
1306 if( mbBuiltin )
1308 rStrm.Ignore( 1 ); // category
1309 rStrm >> mnBuiltinId >> mnLevel;
1315 ScStyleSheet* XclImpStyle::CreateStyleSheet()
1317 // #i1624# #i1768# ignore unnamed user styles
1318 if( !mpStyleSheet && (maFinalName.Len() > 0) )
1320 bool bCreatePattern = false;
1321 XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId );
1323 bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL);
1324 if( bDefStyle )
1326 // set all flags to true to get all items in XclImpXF::CreatePattern()
1327 if( pXF ) pXF->SetAllUsedFlags( true );
1328 // use existing "Default" style sheet
1329 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find(
1330 ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) );
1331 DBG_ASSERT( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" );
1332 bCreatePattern = true;
1334 else
1336 /* #i103281# do not create another style sheet of the same name,
1337 if it exists already. This is needed to prevent that styles
1338 pasted from clipboard get duplicated over and over. */
1339 mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SFX_STYLE_FAMILY_PARA ) );
1340 if( !mpStyleSheet )
1342 mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ) );
1343 bCreatePattern = true;
1347 // bDefStyle==true omits default pool items in CreatePattern()
1348 if( bCreatePattern && mpStyleSheet && pXF )
1349 mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() );
1351 return mpStyleSheet;
1354 void XclImpStyle::CreateUserStyle( const String& rFinalName )
1356 maFinalName = rFinalName;
1357 if( !IsBuiltin() || mbCustom )
1358 CreateStyleSheet();
1361 // ----------------------------------------------------------------------------
1363 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
1364 XclImpRoot( rRoot )
1368 void XclImpXFBuffer::Initialize()
1370 maXFList.Clear();
1371 maBuiltinStyles.Clear();
1372 maUserStyles.Clear();
1373 maStylesByXf.clear();
1376 void XclImpXFBuffer::ReadXF( XclImpStream& rStrm )
1378 XclImpXF* pXF = new XclImpXF( GetRoot() );
1379 pXF->ReadXF( rStrm );
1380 maXFList.Append( pXF );
1383 void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm )
1385 XclImpStyle* pStyle = new XclImpStyle( GetRoot() );
1386 pStyle->ReadStyle( rStrm );
1387 (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).Append( pStyle );
1388 DBG_ASSERT( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1389 maStylesByXf[ pStyle->GetXfId() ] = pStyle;
1392 sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const
1394 const XclImpXF* pXF = GetXF( nXFIndex );
1395 return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND;
1398 const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const
1400 return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) );
1403 namespace {
1405 /** Functor for case-insensitive string comparison, usable in maps etc. */
1406 struct IgnoreCaseCompare
1408 inline bool operator()( const String& rName1, const String& rName2 ) const
1409 { return rName1.CompareIgnoreCaseToAscii( rName2 ) == COMPARE_LESS; }
1412 } // namespace
1414 void XclImpXFBuffer::CreateUserStyles()
1416 // calculate final names of all styles
1417 typedef ::std::map< String, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap;
1418 typedef ::std::vector< XclImpStyle* > XclImpStyleVector;
1420 CellStyleNameMap aCellStyles;
1421 XclImpStyleVector aConflictNameStyles;
1423 /* First, reserve style names that are built-in in Calc. This causes that
1424 imported cell styles get different unused names and thus do not try to
1425 overwrite these built-in styles. For BIFF4 workbooks (which contain a
1426 separate list of cell styles per sheet), reserve all existing styles if
1427 current sheet is not the first sheet (this styles buffer will be
1428 initialized again for every new sheet). This will create unique names
1429 for styles in different sheets with the same name. Assuming that the
1430 BIFF4W import filter is never used to import from clipboard... */
1431 bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0);
1432 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
1433 String aStandardName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD );
1434 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
1435 if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) )
1436 if( aCellStyles.count( pStyleSheet->GetName() ) == 0 )
1437 aCellStyles[ pStyleSheet->GetName() ] = 0;
1439 /* Calculate names of built-in styles. Store styles with reserved names
1440 in the aConflictNameStyles list. */
1441 for( XclImpStyle* pStyle = maBuiltinStyles.First(); pStyle; pStyle = maBuiltinStyles.Next() )
1443 String aStyleName = XclTools::GetBuiltInStyleName( pStyle->GetBuiltinId(), pStyle->GetName(), pStyle->GetLevel() );
1444 DBG_ASSERT( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
1445 "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1446 if( aCellStyles.count( aStyleName ) > 0 )
1447 aConflictNameStyles.push_back( pStyle );
1448 else
1449 aCellStyles[ aStyleName ] = pStyle;
1452 /* Calculate names of user defined styles. Store styles with reserved
1453 names in the aConflictNameStyles list. */
1454 for( XclImpStyle* pStyle = maUserStyles.First(); pStyle; pStyle = maUserStyles.Next() )
1456 // #i1624# #i1768# ignore unnamed user styles
1457 if( pStyle->GetName().Len() > 0 )
1459 if( aCellStyles.count( pStyle->GetName() ) > 0 )
1460 aConflictNameStyles.push_back( pStyle );
1461 else
1462 aCellStyles[ pStyle->GetName() ] = pStyle;
1466 // find unused names for all styles with conflicting names
1467 for( XclImpStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt )
1469 XclImpStyle* pStyle = *aIt;
1470 String aUnusedName;
1471 sal_Int32 nIndex = 0;
1474 aUnusedName.Assign( pStyle->GetName() ).Append( ' ' ).Append( String::CreateFromInt32( ++nIndex ) );
1476 while( aCellStyles.count( aUnusedName ) > 0 );
1477 aCellStyles[ aUnusedName ] = pStyle;
1480 // set final names and create user-defined and modified built-in cell styles
1481 for( CellStyleNameMap::iterator aIt = aCellStyles.begin(), aEnd = aCellStyles.end(); aIt != aEnd; ++aIt )
1482 if( aIt->second )
1483 aIt->second->CreateUserStyle( aIt->first );
1486 ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex )
1488 XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex );
1489 return (aIt == maStylesByXf.end()) ? 0 : aIt->second->CreateStyleSheet();
1492 void XclImpXFBuffer::ApplyPattern(
1493 SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2,
1494 SCTAB nScTab, const XclImpXFIndex& rXFIndex )
1496 if( XclImpXF* pXF = GetXF( rXFIndex.GetXFIndex() ) )
1498 // #108770# set 'Standard' number format for all Boolean cells
1499 ULONG nForceScNumFmt = rXFIndex.IsBoolCell() ? GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND;
1500 pXF->ApplyPattern( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, nForceScNumFmt );
1504 // Buffer for XF indexes in cells =============================================
1506 IMPL_FIXEDMEMPOOL_NEWDEL( XclImpXFRange, 100, 500 )
1508 bool XclImpXFRange::Expand( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1510 if( maXFIndex != rXFIndex )
1511 return false;
1513 if( mnScRow2 + 1 == nScRow )
1515 ++mnScRow2;
1516 return true;
1518 if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) )
1520 --mnScRow1;
1521 return true;
1524 return false;
1527 bool XclImpXFRange::Expand( const XclImpXFRange& rNextRange )
1529 DBG_ASSERT( mnScRow2 < rNextRange.mnScRow1, "XclImpXFRange::Expand - rows out of order" );
1530 if( (maXFIndex == rNextRange.maXFIndex) && (mnScRow2 + 1 == rNextRange.mnScRow1) )
1532 mnScRow2 = rNextRange.mnScRow2;
1533 return true;
1535 return false;
1538 // ----------------------------------------------------------------------------
1540 void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex& rXFIndex )
1542 // List should be empty when inserting the default column format.
1543 // Later explicit SetXF() calls will break up this range.
1544 DBG_ASSERT( maIndexList.Empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
1546 // insert a complete row range with one insert.
1547 maIndexList.Append( new XclImpXFRange( 0, MAXROW, rXFIndex ) );
1550 // ----------------------------------------------------------------------------
1552 void XclImpXFRangeColumn::SetXF( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1554 XclImpXFRange* pPrevRange;
1555 XclImpXFRange* pNextRange;
1556 ULONG nNextIndex;
1558 Find( pPrevRange, pNextRange, nNextIndex, nScRow );
1560 // previous range:
1561 // try to overwrite XF (if row is contained in) or try to expand range
1562 if( pPrevRange )
1564 if( pPrevRange->Contains( nScRow ) ) // overwrite old XF
1566 if( rXFIndex == pPrevRange->maXFIndex )
1567 return;
1569 SCROW nFirstScRow = pPrevRange->mnScRow1;
1570 SCROW nLastScRow = pPrevRange->mnScRow2;
1571 ULONG nIndex = nNextIndex - 1;
1572 XclImpXFRange* pThisRange = pPrevRange;
1573 pPrevRange = nIndex ? maIndexList.GetObject( nIndex - 1 ) : 0;
1575 if( nFirstScRow == nLastScRow ) // replace solely XF
1577 pThisRange->maXFIndex = rXFIndex;
1578 TryConcatPrev( nNextIndex ); // try to concat. next with this
1579 TryConcatPrev( nIndex ); // try to concat. this with previous
1581 else if( nFirstScRow == nScRow ) // replace first XF
1583 ++(pThisRange->mnScRow1);
1584 // try to concatenate with previous of this
1585 if( !pPrevRange || !pPrevRange->Expand( nScRow, rXFIndex ) )
1586 maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1588 else if( nLastScRow == nScRow ) // replace last XF
1590 --(pThisRange->mnScRow2);
1591 if( !pNextRange || !pNextRange->Expand( nScRow, rXFIndex ) )
1592 maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1594 else // insert in the middle of the range
1596 pThisRange->mnScRow1 = nScRow + 1;
1597 // List::Insert() moves entries towards end of list, so insert twice at nIndex
1598 maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1599 maIndexList.Insert( new XclImpXFRange( nFirstScRow, nScRow - 1, pThisRange->maXFIndex ), nIndex );
1601 return;
1603 else if( pPrevRange->Expand( nScRow, rXFIndex ) ) // try to expand
1605 TryConcatPrev( nNextIndex ); // try to concatenate next with expanded
1606 return;
1610 // try to expand next range
1611 if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) )
1612 return;
1614 // create new range
1615 maIndexList.Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1618 void XclImpXFRangeColumn::Find(
1619 XclImpXFRange*& rpPrevRange, XclImpXFRange*& rpNextRange,
1620 ULONG& rnNextIndex, SCROW nScRow ) const
1623 // test whether list is empty
1624 if( maIndexList.Empty() )
1626 rpPrevRange = rpNextRange = 0;
1627 rnNextIndex = 0;
1628 return;
1631 rpPrevRange = maIndexList.GetObject( 0 );
1632 rpNextRange = maIndexList.GetObject( maIndexList.Count() - 1 );
1634 // test whether row is at end of list (contained in or behind last range)
1635 // rpPrevRange will contain a possible existing row
1636 if( rpNextRange->mnScRow1 <= nScRow )
1638 rpPrevRange = rpNextRange;
1639 rpNextRange = 0;
1640 rnNextIndex = maIndexList.Count();
1641 return;
1644 // test whether row is at beginning of list (really before first range)
1645 if( nScRow < rpPrevRange->mnScRow1 )
1647 rpNextRange = rpPrevRange;
1648 rpPrevRange = 0;
1649 rnNextIndex = 0;
1650 return;
1653 // loop: find range entries before and after new row
1654 // break the loop if there is no more range between first and last -or-
1655 // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
1656 ULONG nPrevIndex = 0;
1657 ULONG nMidIndex;
1658 rnNextIndex = maIndexList.Count() - 1;
1659 XclImpXFRange* pMidRange;
1660 while( ((rnNextIndex - nPrevIndex) > 1) && (rpPrevRange->mnScRow2 < nScRow) )
1662 nMidIndex = (nPrevIndex + rnNextIndex) / 2;
1663 pMidRange = maIndexList.GetObject( nMidIndex );
1664 DBG_ASSERT( pMidRange, "XclImpXFRangeColumn::Find - missing XF index range" );
1665 if( nScRow < pMidRange->mnScRow1 ) // row is really before pMidRange
1667 rpNextRange = pMidRange;
1668 rnNextIndex = nMidIndex;
1670 else // row is in or after pMidRange
1672 rpPrevRange = pMidRange;
1673 nPrevIndex = nMidIndex;
1677 // find next rpNextRange if rpPrevRange contains nScRow
1678 if( nScRow <= rpPrevRange->mnScRow2 )
1680 rnNextIndex = nPrevIndex + 1;
1681 rpNextRange = maIndexList.GetObject( rnNextIndex );
1685 void XclImpXFRangeColumn::TryConcatPrev( ULONG nIndex )
1687 if( !nIndex )
1688 return;
1690 XclImpXFRange* pPrevRange = maIndexList.GetObject( nIndex - 1 );
1691 XclImpXFRange* pNextRange = maIndexList.GetObject( nIndex );
1692 if( !pPrevRange || !pNextRange )
1693 return;
1695 if( pPrevRange->Expand( *pNextRange ) )
1696 maIndexList.Delete( nIndex );
1699 // ----------------------------------------------------------------------------
1701 XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot& rRoot ) :
1702 XclImpRoot( rRoot )
1706 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1710 void XclImpXFRangeBuffer::Initialize()
1712 maColumns.clear();
1713 maHyperlinks.clear();
1714 maMergeList.RemoveAll();
1717 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex, XclImpXFInsertMode eMode )
1719 SCCOL nScCol = rScPos.Col();
1720 SCROW nScRow = rScPos.Row();
1722 // set cell XF's
1723 size_t nIndex = static_cast< size_t >( nScCol );
1724 if( maColumns.size() <= nIndex )
1725 maColumns.resize( nIndex + 1 );
1726 if( !maColumns[ nIndex ] )
1727 maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1728 // #108770# remember all Boolean cells, they will get 'Standard' number format
1729 maColumns[ nIndex ]->SetXF( nScRow, XclImpXFIndex( nXFIndex, eMode == xlXFModeBoolCell ) );
1731 // set "center across selection" and "fill" attribute for all following empty cells
1732 // #97130# ignore it on row default XFs
1733 if( eMode != xlXFModeRow )
1735 const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex );
1736 if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) )
1738 // expand last merged range if this attribute is set repeatedly
1739 ScRange* pRange = maMergeList.Last();
1740 if( pRange && (pRange->aEnd.Row() == nScRow) && (pRange->aEnd.Col() + 1 == nScCol)
1741 && (eMode == xlXFModeBlank) )
1742 pRange->aEnd.IncCol();
1743 else if( eMode != xlXFModeBlank ) // #108781# do not merge empty cells
1744 SetMerge( nScCol, nScRow );
1749 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1751 SetXF( rScPos, nXFIndex, xlXFModeCell );
1754 void XclImpXFRangeBuffer::SetBlankXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1756 SetXF( rScPos, nXFIndex, xlXFModeBlank );
1759 void XclImpXFRangeBuffer::SetBoolXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1761 SetXF( rScPos, nXFIndex, xlXFModeBoolCell );
1764 void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow, sal_uInt16 nXFIndex )
1766 for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
1767 SetXF( ScAddress( nScCol, nScRow, 0 ), nXFIndex, xlXFModeRow );
1770 void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol, sal_uInt16 nXFIndex )
1772 // our array should not have values when creating the default column format.
1773 size_t nIndex = static_cast< size_t >( nScCol );
1774 if( maColumns.size() <= nIndex )
1775 maColumns.resize( nIndex + 1 );
1776 DBG_ASSERT( !maColumns[ nIndex ], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
1777 maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1778 maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) );
1781 void XclImpXFRangeBuffer::SetBorderLine( const ScRange& rRange, SCTAB nScTab, USHORT nLine )
1783 SCCOL nFromScCol = (nLine == BOX_LINE_RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
1784 SCROW nFromScRow = (nLine == BOX_LINE_BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
1785 ScDocument& rDoc = GetDoc();
1787 const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >(
1788 rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
1789 const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
1790 rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) );
1792 SvxBoxItem aNewItem( *pToItem );
1793 aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
1794 rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
1797 void XclImpXFRangeBuffer::SetHyperlink( const XclRange& rXclRange, const String& rUrl )
1799 maHyperlinks.push_back( XclImpHyperlinkRange( rXclRange, rUrl ) );
1802 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol, SCROW nScRow )
1804 maMergeList.Append( ScRange( nScCol, nScRow, 0 ) );
1807 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 )
1809 if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) )
1810 maMergeList.Append( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) );
1813 void XclImpXFRangeBuffer::Finalize()
1815 ScDocument& rDoc = GetDoc();
1816 SCTAB nScTab = GetCurrScTab();
1818 // apply patterns
1819 XclImpXFBuffer& rXFBuffer = GetXFBuffer();
1820 for( XclImpXFRangeColumnVec::const_iterator aVBeg = maColumns.begin(), aVEnd = maColumns.end(), aVIt = aVBeg; aVIt != aVEnd; ++aVIt )
1822 // apply all cell styles of an existing column
1823 if( aVIt->is() )
1825 XclImpXFRangeColumn& rColumn = **aVIt;
1826 SCCOL nScCol = static_cast< SCCOL >( aVIt - aVBeg );
1827 for( XclImpXFRange* pStyle = rColumn.First(); pStyle; pStyle = rColumn.Next() )
1828 rXFBuffer.ApplyPattern( nScCol, pStyle->mnScRow1, nScCol, pStyle->mnScRow2, nScTab, pStyle->maXFIndex );
1832 // insert hyperlink cells
1833 for( XclImpHyperlinkList::const_iterator aLIt = maHyperlinks.begin(), aLEnd = maHyperlinks.end(); aLIt != aLEnd; ++aLIt )
1834 XclImpHyperlink::InsertUrl( GetRoot(), aLIt->first, aLIt->second );
1836 // apply cell merging
1837 for( const ScRange* pRange = maMergeList.First(); pRange; pRange = maMergeList.Next() )
1839 const ScAddress& rStart = pRange->aStart;
1840 const ScAddress& rEnd = pRange->aEnd;
1841 bool bMultiCol = rStart.Col() != rEnd.Col();
1842 bool bMultiRow = rStart.Row() != rEnd.Row();
1843 // set correct right border
1844 if( bMultiCol )
1845 SetBorderLine( *pRange, nScTab, BOX_LINE_RIGHT );
1846 // set correct lower border
1847 if( bMultiRow )
1848 SetBorderLine( *pRange, nScTab, BOX_LINE_BOTTOM );
1849 // do merge
1850 if( bMultiCol || bMultiRow )
1851 rDoc.DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
1852 // #i93609# merged range in a single row: test if manual row height is needed
1853 if( !bMultiRow )
1855 bool bTextWrap = static_cast< const SfxBoolItem* >( rDoc.GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue();
1856 if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
1857 if( const EditTextObject* pEditObj = static_cast< const ScEditCell* >( rDoc.GetCell( rStart ) )->GetData() )
1858 bTextWrap = pEditObj->GetParagraphCount() > 1;
1859 if( bTextWrap )
1860 GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
1865 // ============================================================================