bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xestyle.cxx
blob486481a710fb3a113c0aca3fd7a7e86e0367cd9d
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 "xestyle.hxx"
22 #include <iostream>
23 #include <algorithm>
24 #include <iterator>
25 #include <set>
26 #include <com/sun/star/i18n/ScriptType.hpp>
27 #include <vcl/font.hxx>
28 #include <svl/zformat.hxx>
29 #include <svl/itempool.hxx>
30 #include <svl/languageoptions.hxx>
31 #include <sfx2/printer.hxx>
32 #include "scitems.hxx"
33 #include <svx/algitem.hxx>
34 #include <editeng/boxitem.hxx>
35 #include <editeng/lineitem.hxx>
36 #include <svx/rotmodit.hxx>
37 #include <editeng/colritem.hxx>
38 #include <editeng/brushitem.hxx>
39 #include <editeng/frmdiritem.hxx>
40 #include <editeng/eeitem.hxx>
41 #include <editeng/escapementitem.hxx>
42 #include <editeng/justifyitem.hxx>
43 #include "document.hxx"
44 #include "stlpool.hxx"
45 #include "stlsheet.hxx"
46 #include "patattr.hxx"
47 #include "attrib.hxx"
48 #include "globstr.hrc"
49 #include "xestring.hxx"
50 #include "conditio.hxx"
52 #include <oox/token/tokens.hxx>
53 #include <boost/ptr_container/ptr_vector.hpp>
55 using namespace ::com::sun::star;
56 using namespace oox;
58 // PALETTE record - color information =========================================
60 namespace {
62 sal_uInt32 lclGetWeighting( XclExpColorType eType )
64 switch( eType )
66 case EXC_COLOR_CHARTLINE: return 1;
67 case EXC_COLOR_CELLBORDER:
68 case EXC_COLOR_CHARTAREA: return 2;
69 case EXC_COLOR_CELLTEXT:
70 case EXC_COLOR_CHARTTEXT:
71 case EXC_COLOR_CTRLTEXT: return 10;
72 case EXC_COLOR_TABBG:
73 case EXC_COLOR_CELLAREA: return 20;
74 case EXC_COLOR_GRID: return 50;
75 default: OSL_FAIL( "lclGetWeighting - unknown color type" );
77 return 1;
80 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
82 sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
83 nDist *= nDist * 77;
84 sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
85 nDist += nDummy * nDummy * 151;
86 nDummy = rColor1.GetBlue() - rColor2.GetBlue();
87 nDist += nDummy * nDummy * 28;
88 return nDist;
91 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
93 sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
94 sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
95 if( nComp1Dist != nComp2Dist )
97 /* #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
98 Increase its weighting to prevent fading of the colors during reduction. */
99 const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
100 sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
101 rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
103 sal_uInt32 nWSum = nWeight1 + nWeight2;
104 return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
107 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
109 rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
110 rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
111 rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
114 } // namespace
116 // additional classes for color reduction -------------------------------------
118 namespace {
120 /** Represents an entry in a color list.
122 The color stores a weighting value, which increases the more the color is
123 used in the document. Heavy-weighted colors will change less than others on
124 color reduction.
126 class XclListColor
128 DECL_FIXEDMEMPOOL_NEWDEL( XclListColor )
130 private:
131 Color maColor; /// The color value of this palette entry.
132 sal_uInt32 mnColorId; /// Unique color ID for color reduction.
133 sal_uInt32 mnWeight; /// Weighting for color reduction.
134 bool mbBaseColor; /// true = Handle as base color, (don't remove/merge).
136 public:
137 explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
139 /** Returns the RGB color value of the color. */
140 inline const Color& GetColor() const { return maColor; }
141 /** Returns the unique ID of the color. */
142 inline sal_uInt32 GetColorId() const { return mnColorId; }
143 /** Returns the current weighting of the color. */
144 inline sal_uInt32 GetWeighting() const { return mnWeight; }
145 /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
146 inline bool IsBaseColor() const { return mbBaseColor; }
148 /** Adds the passed weighting to this color. */
149 inline void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
150 /** Merges this color with rColor, regarding weighting settings. */
151 void Merge( const XclListColor& rColor );
154 IMPL_FIXEDMEMPOOL_NEWDEL( XclListColor )
156 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
157 maColor( rColor ),
158 mnColorId( nColorId ),
159 mnWeight( 0 )
161 mbBaseColor =
162 ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
163 ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
164 ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
167 void XclListColor::Merge( const XclListColor& rColor )
169 sal_uInt32 nWeight2 = rColor.GetWeighting();
170 // do not change RGB value of base colors
171 if( !mbBaseColor )
173 maColor.SetRed( lclGetMergedColorComp( maColor.GetRed(), mnWeight, rColor.maColor.GetRed(), nWeight2 ) );
174 maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
175 maColor.SetBlue( lclGetMergedColorComp( maColor.GetBlue(), mnWeight, rColor.maColor.GetBlue(), nWeight2 ) );
177 AddWeighting( nWeight2 );
180 // ----------------------------------------------------------------------------
182 /** Data for each inserted original color, represented by a color ID. */
183 struct XclColorIdData
185 Color maColor; /// The original inserted color.
186 sal_uInt32 mnIndex; /// Maps current color ID to color list or export color vector.
187 /** Sets the contents of this struct. */
188 inline void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
191 /** A color that will be written to the Excel file. */
192 struct XclPaletteColor
194 Color maColor; /// Resulting color to export.
195 bool mbUsed; /// true = Entry is used in the document.
197 inline explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
198 inline void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
201 /** Maps a color list index to a palette index.
202 @descr Used to remap the color ID data vector from list indexes to palette indexes. */
203 struct XclRemap
205 sal_uInt32 mnPalIndex; /// Index to palette.
206 bool mbProcessed; /// true = List color already processed.
208 inline explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
209 inline void SetIndex( sal_uInt32 nPalIndex )
210 { mnPalIndex = nPalIndex; mbProcessed = true; }
213 /** Stores the nearest palette color index of a list color. */
214 struct XclNearest
216 sal_uInt32 mnPalIndex; /// Index to nearest palette color.
217 sal_Int32 mnDist; /// Distance to palette color.
219 inline explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
222 typedef ::std::vector< XclRemap > XclRemapVec;
223 typedef ::std::vector< XclNearest > XclNearestVec;
225 } // namespace
227 // ----------------------------------------------------------------------------
229 class XclExpPaletteImpl
231 public:
232 explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
234 /** Inserts the color into the list and updates weighting.
235 @param nAutoDefault The Excel palette index for automatic color.
236 @return A unique ID for this color. */
237 sal_uInt32 InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
238 /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
239 static sal_uInt32 GetColorIdFromIndex( sal_uInt16 nIndex );
241 /** Reduces the color list to the maximum count of the current BIFF version. */
242 void Finalize();
244 /** Returns the Excel palette index of the color with passed color ID. */
245 sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
247 /** Returns a foreground and background color for the two passed color IDs.
248 @descr If rnXclPattern contains a solid pattern, this function tries to find
249 the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
250 This will result in a better approximation to the passed foreground color. */
251 void GetMixedColors(
252 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
253 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
255 /** Returns the RGB color data for a (non-zero-based) Excel palette entry.
256 @return The color from current or default palette or COL_AUTO, if nothing else found. */
257 ColorData GetColorData( sal_uInt16 nXclIndex ) const;
258 /** Returns the color for a (non-zero-based) Excel palette entry.
259 @return The color from current or default palette or COL_AUTO, if nothing else found. */
260 inline Color GetColor( sal_uInt16 nXclIndex ) const
261 { return Color( GetColorData( nXclIndex ) ); }
263 /** Returns true, if all colors of the palette are equal to default palette colors. */
264 bool IsDefaultPalette() const;
265 /** Writes the color list (contents of the palette record) to the passed stream. */
266 void WriteBody( XclExpStream& rStrm );
267 void SaveXml( XclExpXmlStream& rStrm );
269 private:
270 /** Returns the Excel index of a 0-based color index. */
271 inline sal_uInt16 GetXclIndex( sal_uInt32 nIndex ) const
272 { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
274 /** Returns the original inserted color represented by the color ID nColorId. */
275 const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
277 /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
278 XclListColor* SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
279 /** Creates and inserts a new color list entry at the specified list position. */
280 XclListColor* CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
282 /** Raw and fast reduction of the palette. */
283 void RawReducePalette( sal_uInt32 nPass );
284 /** Reduction of one color using advanced color merging based on color weighting. */
285 void ReduceLeastUsedColor();
287 /** Finds the least used color and returns its current list index. */
288 sal_uInt32 GetLeastUsedListColor() const;
289 /** Returns the list index of the color nearest to rColor.
290 @param nIgnore List index of a color which will be ignored.
291 @return The list index of the found color. */
292 sal_uInt32 GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
293 /** Returns the list index of the color nearest to the color with list index nIndex. */
294 sal_uInt32 GetNearestListColor( sal_uInt32 nIndex ) const;
296 /** Returns in rnIndex the palette index of the color nearest to rColor.
297 @param bDefaultOnly true = Searches for default colors only (colors never replaced).
298 @return The distance from passed color to found color. */
299 sal_Int32 GetNearestPaletteColor(
300 sal_uInt32& rnIndex,
301 const Color& rColor, bool bDefaultOnly ) const;
302 /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
303 @return The minimum distance from passed color to found colors. */
304 sal_Int32 GetNearPaletteColors(
305 sal_uInt32& rnFirst, sal_uInt32& rnSecond,
306 const Color& rColor ) const;
308 private:
309 typedef boost::ptr_vector< XclListColor > XclListColorList;
310 typedef boost::shared_ptr< XclListColorList > XclListColorListRef;
311 typedef ::std::vector< XclColorIdData > XclColorIdDataVec;
312 typedef ::std::vector< XclPaletteColor > XclPaletteColorVec;
314 const XclDefaultPalette& mrDefPal; /// The default palette for the current BIFF version.
315 XclListColorListRef mxColorList; /// Working color list.
316 XclColorIdDataVec maColorIdDataVec; /// Data of all CIDs.
317 XclPaletteColorVec maPalette; /// Contains resulting colors to export.
318 sal_uInt32 mnLastIdx; /// Last insertion index for search opt.
321 // ----------------------------------------------------------------------------
323 const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
324 const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
326 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
327 mrDefPal( rDefPal ),
328 mxColorList( new XclListColorList ),
329 mnLastIdx( 0 )
331 // initialize maPalette with default colors
332 sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
333 maPalette.reserve( nCount );
334 for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
335 maPalette.push_back( XclPaletteColor( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) ) );
337 InsertColor( Color( COL_BLACK ), EXC_COLOR_CELLTEXT );
340 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
342 if( rColor.GetColor() == COL_AUTO )
343 return GetColorIdFromIndex( nAutoDefault );
345 sal_uInt32 nFoundIdx = 0;
346 XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
347 if( !pEntry || (pEntry->GetColor() != rColor) )
348 pEntry = CreateListEntry( rColor, nFoundIdx );
349 pEntry->AddWeighting( lclGetWeighting( eType ) );
351 return pEntry->GetColorId();
354 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
356 return EXC_PAL_INDEXBASE | nIndex;
359 void XclExpPaletteImpl::Finalize()
361 // --- build initial color ID data vector (maColorIdDataVec) ---
363 sal_uInt32 nCount = mxColorList->size();
364 maColorIdDataVec.resize( nCount );
365 for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
367 const XclListColor& listColor = mxColorList->at( nIdx );
368 maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
371 // --- loop as long as current color count does not fit into palette of current BIFF ---
373 // phase 1: raw reduction (performance reasons, #i36945#)
374 sal_uInt32 nPass = 0;
375 while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
376 RawReducePalette( nPass++ );
378 // phase 2: precise reduction using advanced color merging based on color weighting
379 while( mxColorList->size() > mrDefPal.GetColorCount() )
380 ReduceLeastUsedColor();
382 // --- use default palette and replace colors with nearest used colors ---
384 nCount = mxColorList->size();
385 XclRemapVec aRemapVec( nCount );
386 XclNearestVec aNearestVec( nCount );
388 // in each run: search the best fitting color and replace a default color with it
389 for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
391 sal_uInt32 nIndex;
392 // find nearest unused default color for each unprocessed list color
393 for( nIndex = 0; nIndex < nCount; ++nIndex )
394 aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
395 GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->at( nIndex ).GetColor(), true );
396 // find the list color which is nearest to a default color
397 sal_uInt32 nFound = 0;
398 for( nIndex = 1; nIndex < nCount; ++nIndex )
399 if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
400 nFound = nIndex;
401 // replace default color with list color
402 sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
403 OSL_ENSURE( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
404 maPalette[ nNearest ].SetColor( mxColorList->at( nFound ).GetColor() );
405 aRemapVec[ nFound ].SetIndex( nNearest );
408 // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
409 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
410 aIt->mnIndex = aRemapVec[ aIt->mnIndex ].mnPalIndex;
413 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
415 sal_uInt16 nRet = 0;
416 if( nColorId >= EXC_PAL_INDEXBASE )
417 nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
418 else if( nColorId < maColorIdDataVec.size() )
419 nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
420 return nRet;
423 void XclExpPaletteImpl::GetMixedColors(
424 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
425 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
427 rnXclForeIx = GetColorIndex( nForeColorId );
428 rnXclBackIx = GetColorIndex( nBackColorId );
429 if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
430 return;
432 // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
434 sal_uInt32 nIndex1, nIndex2;
435 Color aForeColor( GetOriginalColor( nForeColorId ) );
436 sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
437 if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
438 return;
440 Color aColorArr[ 5 ];
441 aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
442 aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
443 lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
444 lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
445 lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
447 sal_Int32 nMinDist = nFirstDist;
448 sal_uInt32 nMinIndex = 0;
449 for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
451 sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
452 if( nDist < nMinDist )
454 nMinDist = nDist;
455 nMinIndex = nCnt;
458 rnXclForeIx = GetXclIndex( nIndex1 );
459 rnXclBackIx = GetXclIndex( nIndex2 );
460 if( nMinDist < nFirstDist )
462 switch( nMinIndex )
464 case 1: rnXclPattern = EXC_PATT_75_PERC; break;
465 case 2: rnXclPattern = EXC_PATT_50_PERC; break;
466 case 3: rnXclPattern = EXC_PATT_25_PERC; break;
471 ColorData XclExpPaletteImpl::GetColorData( sal_uInt16 nXclIndex ) const
473 if( nXclIndex >= EXC_COLOR_USEROFFSET )
475 sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
476 if( nIdx < maPalette.size() )
477 return maPalette[ nIdx ].maColor.GetColor();
479 return mrDefPal.GetDefColorData( nXclIndex );
482 bool XclExpPaletteImpl::IsDefaultPalette() const
484 bool bDefault = true;
485 for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
486 bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
487 return bDefault;
490 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
492 rStrm << static_cast< sal_uInt16 >( maPalette.size() );
493 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
494 rStrm << aIt->maColor;
497 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
499 if( !maPalette.size() )
500 return;
502 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
503 rStyleSheet->startElement( XML_colors, FSEND );
504 rStyleSheet->startElement( XML_indexedColors, FSEND );
505 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
506 rStyleSheet->singleElement( XML_rgbColor,
507 XML_rgb, XclXmlUtils::ToOString( aIt->maColor ).getStr(),
508 FSEND );
509 rStyleSheet->endElement( XML_indexedColors );
510 rStyleSheet->endElement( XML_colors );
513 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
515 if( nColorId < maColorIdDataVec.size() )
516 return maColorIdDataVec[ nColorId ].maColor;
517 return maPalette[ 0 ].maColor;
520 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
522 rnIndex = mnLastIdx;
523 XclListColor* pEntry = NULL;
525 if (mxColorList->empty())
526 return NULL;
528 // search optimization for equal-colored objects occurring repeatedly
529 if (rnIndex < mxColorList->size())
531 pEntry = &(*mxColorList)[rnIndex];
532 if( pEntry->GetColor() == rColor )
533 return pEntry;
536 // binary search for color
537 sal_uInt32 nBegIdx = 0;
538 sal_uInt32 nEndIdx = mxColorList->size();
539 bool bFound = false;
540 while( !bFound && (nBegIdx < nEndIdx) )
542 rnIndex = (nBegIdx + nEndIdx) / 2;
543 pEntry = &(*mxColorList)[rnIndex];
544 bFound = pEntry->GetColor() == rColor;
545 if( !bFound )
547 if( pEntry->GetColor().GetColor() < rColor.GetColor() )
548 nBegIdx = rnIndex + 1;
549 else
550 nEndIdx = rnIndex;
554 // not found - use end of range as new insertion position
555 if( !bFound )
556 rnIndex = nEndIdx;
558 mnLastIdx = rnIndex;
559 return pEntry;
562 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
564 XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
565 XclListColorList::iterator itr = mxColorList->begin();
566 ::std::advance(itr, nIndex);
567 mxColorList->insert(itr, pEntry);
568 return pEntry;
571 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
573 /* Fast palette reduction - in each call of this function one RGB component
574 of each color is reduced to a lower number of distinct values.
575 Pass 0: Blue is reduced to 128 distinct values.
576 Pass 1: Red is reduced to 128 distinct values.
577 Pass 2: Green is reduced to 128 distinct values.
578 Pass 3: Blue is reduced to 64 distinct values.
579 Pass 4: Red is reduced to 64 distinct values.
580 Pass 5: Green is reduced to 64 distinct values.
581 And so on...
584 XclListColorListRef xOldList = mxColorList;
585 mxColorList.reset( new XclListColorList );
587 // maps old list indexes to new list indexes, used to update maColorIdDataVec
588 ScfUInt32Vec aListIndexMap;
589 aListIndexMap.reserve( xOldList->size() );
591 // preparations
592 sal_uInt8 nR, nG, nB;
593 sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
594 nPass /= 3;
595 OSL_ENSURE( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
597 static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
598 sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
599 sal_uInt8 nFactor2 = spnFactor2[ nPass ];
600 sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
602 // process each color in the old color list
603 for( sal_uInt32 nIdx = 0, nCount = xOldList->size(); nIdx < nCount; ++nIdx )
605 // get the old list entry
606 const XclListColor* pOldEntry = &(xOldList->at( nIdx ));
607 nR = pOldEntry->GetColor().GetRed();
608 nG = pOldEntry->GetColor().GetGreen();
609 nB = pOldEntry->GetColor().GetBlue();
611 /* Calculate the new RGB component (rnComp points to one of nR, nG, nB).
612 Using integer arithmetic with its rounding errors, the results of
613 this calculation are always exactly in the range 0x00 to 0xFF
614 (simply cutting the lower bits would darken the colors slightly). */
615 sal_uInt32 nNewComp = rnComp;
616 nNewComp /= nFactor1;
617 nNewComp *= nFactor2;
618 nNewComp /= nFactor3;
619 rnComp = static_cast< sal_uInt8 >( nNewComp );
620 Color aNewColor( nR, nG, nB );
622 // find or insert the new color
623 sal_uInt32 nFoundIdx = 0;
624 XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
625 if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
626 pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
627 pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
628 aListIndexMap.push_back( nFoundIdx );
631 // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
632 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
633 aIt->mnIndex = aListIndexMap[ aIt->mnIndex ];
636 void XclExpPaletteImpl::ReduceLeastUsedColor()
638 // find a list color to remove
639 sal_uInt32 nRemove = GetLeastUsedListColor();
640 // find its nearest neighbor
641 sal_uInt32 nKeep = GetNearestListColor( nRemove );
643 // merge both colors to one color, remove one color from list
644 XclListColor* pKeepEntry = &mxColorList->at(nKeep);
645 XclListColor* pRemoveEntry = &mxColorList->at(nRemove);
646 if( pKeepEntry && pRemoveEntry )
648 // merge both colors (if pKeepEntry is a base color, it will not change)
649 pKeepEntry->Merge( *pRemoveEntry );
650 // remove the less used color, adjust nKeep index if kept color follows removed color
651 XclListColorList::iterator itr = mxColorList->begin();
652 ::std::advance(itr, nRemove);
653 mxColorList->erase(itr);
654 if( nKeep > nRemove ) --nKeep;
656 // recalculate color ID data map (maps color IDs to color list indexes)
657 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
659 if( aIt->mnIndex > nRemove )
660 --aIt->mnIndex;
661 else if( aIt->mnIndex == nRemove )
662 aIt->mnIndex = nKeep;
667 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
669 sal_uInt32 nFound = 0;
670 sal_uInt32 nMinW = SAL_MAX_UINT32;
672 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
674 XclListColor& pEntry = mxColorList->at( nIdx );
675 // ignore the base colors
676 if( !pEntry.IsBaseColor() && (pEntry.GetWeighting() < nMinW) )
678 nFound = nIdx;
679 nMinW = pEntry.GetWeighting();
682 return nFound;
685 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
687 sal_uInt32 nFound = 0;
688 sal_Int32 nMinD = SAL_MAX_INT32;
690 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
692 if( nIdx != nIgnore )
694 if( XclListColor* pEntry = &mxColorList->at(nIdx) )
696 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
697 if( nDist < nMinD )
699 nFound = nIdx;
700 nMinD = nDist;
705 return nFound;
708 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
710 if (nIndex >= mxColorList->size())
711 return 0;
712 XclListColor* pEntry = &mxColorList->at(nIndex);
713 return GetNearestListColor( pEntry->GetColor(), nIndex );
716 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
717 sal_uInt32& rnIndex, const Color& rColor, bool bDefaultOnly ) const
719 rnIndex = 0;
720 sal_Int32 nDist = SAL_MAX_INT32;
722 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
723 aIt != aEnd; ++aIt )
725 if( !bDefaultOnly || !aIt->mbUsed )
727 sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
728 if( nCurrDist < nDist )
730 rnIndex = aIt - maPalette.begin();
731 nDist = nCurrDist;
735 return nDist;
738 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
739 sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
741 rnFirst = rnSecond = 0;
742 sal_Int32 nDist1 = SAL_MAX_INT32;
743 sal_Int32 nDist2 = SAL_MAX_INT32;
745 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
746 aIt != aEnd; ++aIt )
748 sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
749 if( nCurrDist < nDist1 )
751 rnSecond = rnFirst;
752 nDist2 = nDist1;
753 rnFirst = aIt - maPalette.begin();
754 nDist1 = nCurrDist;
756 else if( nCurrDist < nDist2 )
758 rnSecond = aIt - maPalette.begin();
759 nDist2 = nCurrDist;
762 return nDist1;
765 // ----------------------------------------------------------------------------
767 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
768 XclDefaultPalette( rRoot ),
769 XclExpRecord( EXC_ID_PALETTE )
771 mxImpl.reset( new XclExpPaletteImpl( *this ) );
772 SetRecSize( GetColorCount() * 4 + 2 );
775 XclExpPalette::~XclExpPalette()
779 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
781 return mxImpl->InsertColor( rColor, eType, nAutoDefault );
784 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
786 return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
789 void XclExpPalette::Finalize()
791 mxImpl->Finalize();
794 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
796 return mxImpl->GetColorIndex( nColorId );
799 void XclExpPalette::GetMixedColors(
800 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
801 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
803 return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
806 ColorData XclExpPalette::GetColorData( sal_uInt16 nXclIndex ) const
808 return mxImpl->GetColorData( nXclIndex );
811 void XclExpPalette::Save( XclExpStream& rStrm )
813 if( !mxImpl->IsDefaultPalette() )
814 XclExpRecord::Save( rStrm );
817 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
819 if( !mxImpl->IsDefaultPalette() )
820 mxImpl->SaveXml( rStrm );
823 void XclExpPalette::WriteBody( XclExpStream& rStrm )
825 mxImpl->WriteBody( rStrm );
828 // FONT record - font information =============================================
830 namespace {
832 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
834 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
835 const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
837 if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
838 if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
839 if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
840 return 0;
843 } // namespace
845 sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
847 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
849 /* #i17050# #i107170# We need to determine which font items are set in the
850 item set, and which script type we should prefer according to the
851 current language settings. */
853 static const WhichAndScript WAS_LATIN( ATTR_FONT, ::com::sun::star::i18n::ScriptType::LATIN );
854 static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, ::com::sun::star::i18n::ScriptType::ASIAN );
855 static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, ::com::sun::star::i18n::ScriptType::COMPLEX );
857 /* do not let a font from a parent style override an explicit
858 cell font. */
860 sal_Int16 nDefScript = rRoot.GetDefApiScript();
861 sal_Int16 nScript = 0;
862 const SfxItemSet* pCurrSet = &rItemSet;
864 while( (nScript == 0) && pCurrSet )
866 switch( nDefScript )
868 case ApiScriptType::LATIN:
869 nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
870 break;
871 case ApiScriptType::ASIAN:
872 nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
873 break;
874 case ApiScriptType::COMPLEX:
875 nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
876 break;
877 default:
878 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
879 nScript = ApiScriptType::LATIN;
881 pCurrSet = pCurrSet->GetParent();
884 return nScript;
887 Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
889 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
891 // if WEAK is passed, guess script type from existing items in the item set
892 if( nScript == ApiScriptType::WEAK )
893 nScript = GetFirstUsedScript( rRoot, rItemSet );
895 // convert to core script type constants
896 sal_uInt8 nScScript = SCRIPTTYPE_LATIN;
897 switch( nScript )
899 case ApiScriptType::LATIN: nScScript = SCRIPTTYPE_LATIN; break;
900 case ApiScriptType::ASIAN: nScScript = SCRIPTTYPE_ASIAN; break;
901 case ApiScriptType::COMPLEX: nScScript = SCRIPTTYPE_COMPLEX; break;
902 default: OSL_FAIL( "XclExpFontHelper::GetFontFromItemSet - unknown script type" );
905 // fill the font object
906 Font aFont;
907 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, 0, 0, 0, nScScript );
908 return aFont;
911 bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
913 static const sal_uInt16 pnCommonIds[] = {
914 ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
915 ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
916 static const sal_uInt16 pnLatinIds[] = {
917 ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
918 static const sal_uInt16 pnAsianIds[] = {
919 ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
920 static const sal_uInt16 pnComplexIds[] = {
921 ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
923 bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
924 if( !bUsed )
926 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
927 // if WEAK is passed, guess script type from existing items in the item set
928 if( nScript == ApiScriptType::WEAK )
929 nScript = GetFirstUsedScript( rRoot, rItemSet );
930 // check the correct items
931 switch( nScript )
933 case ApiScriptType::LATIN: bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep ); break;
934 case ApiScriptType::ASIAN: bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep ); break;
935 case ApiScriptType::COMPLEX: bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep ); break;
936 default: OSL_FAIL( "XclExpFontHelper::CheckItems - unknown script type" );
939 return bUsed;
942 // ----------------------------------------------------------------------------
944 namespace {
946 sal_uInt32 lclCalcHash( const XclFontData& rFontData )
948 sal_uInt32 nHash = rFontData.maName.Len();
949 nHash += rFontData.maColor.GetColor() * 2;
950 nHash += rFontData.mnWeight * 3;
951 nHash += rFontData.mnCharSet * 5;
952 nHash += rFontData.mnFamily * 7;
953 nHash += rFontData.mnHeight * 11;
954 nHash += rFontData.mnUnderline * 13;
955 nHash += rFontData.mnEscapem * 17;
956 if( rFontData.mbItalic ) nHash += 19;
957 if( rFontData.mbStrikeout ) nHash += 23;
958 if( rFontData.mbOutline ) nHash += 29;
959 if( rFontData.mbShadow ) nHash += 31;
960 return nHash;
963 } // namespace
965 // ----------------------------------------------------------------------------
967 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
968 const XclFontData& rFontData, XclExpColorType eColorType ) :
969 XclExpRecord( EXC_ID2_FONT, 14 ),
970 XclExpRoot( rRoot ),
971 maData( rFontData )
973 // insert font color into palette
974 mnColorId = rRoot.GetPalette().InsertColor( rFontData.maColor, eColorType, EXC_COLOR_FONTAUTO );
975 // hash value for faster comparison
976 mnHash = lclCalcHash( maData );
977 // record size
978 sal_Size nStrLen = maData.maName.Len();
979 SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
982 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
984 return (mnHash == nHash) && (maData == rFontData);
987 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
989 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
990 rStyleSheet->startElement( XML_font, FSEND );
991 XclXmlUtils::WriteFontData( rStyleSheet, maData, XML_name );
992 // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
993 rStyleSheet->endElement( XML_font );
996 // private --------------------------------------------------------------------
998 void XclExpFont::WriteBody( XclExpStream& rStrm )
1000 sal_uInt16 nAttr = EXC_FONTATTR_NONE;
1001 ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
1002 ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
1003 ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
1004 ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
1006 OSL_ENSURE( maData.maName.Len() < 256, "XclExpFont::WriteBody - font name too long" );
1007 XclExpString aFontName;
1008 if( GetBiff() <= EXC_BIFF5 )
1009 aFontName.AssignByte( maData.maName, GetTextEncoding(), EXC_STR_8BITLENGTH );
1010 else
1011 aFontName.Assign( maData.maName, EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH );
1013 rStrm << maData.mnHeight
1014 << nAttr
1015 << GetPalette().GetColorIndex( mnColorId )
1016 << maData.mnWeight
1017 << maData.mnEscapem
1018 << maData.mnUnderline
1019 << maData.mnFamily
1020 << maData.mnCharSet
1021 << sal_uInt8( 0 )
1022 << aFontName;
1025 // ----------------------------------------------------------------------------
1027 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1028 XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1032 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1034 return false;
1037 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1039 // do nothing
1042 // ============================================================================
1044 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1045 XclExpRoot( rRoot ),
1046 mnXclMaxSize( 0 )
1048 switch( GetBiff() )
1050 case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4; break;
1051 case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5; break;
1052 case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8; break;
1053 default: DBG_ERROR_BIFF();
1055 InitDefaultFonts();
1058 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1060 return maFontList.GetRecord( nXclFont ).get();
1063 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1065 return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1068 sal_uInt16 XclExpFontBuffer::Insert(
1069 const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1071 if( bAppFont )
1073 XclExpFontRef xFont( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1074 maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
1075 // set width of '0' character for column width export
1076 SetCharWidth( xFont->GetFontData() );
1077 return EXC_FONT_APP;
1080 size_t nPos = Find( rFontData );
1081 if( nPos == EXC_FONTLIST_NOTFOUND )
1083 // not found in buffer - create new font
1084 size_t nSize = maFontList.GetSize();
1085 if( nSize < mnXclMaxSize )
1087 // possible to insert
1088 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1089 nPos = nSize; // old size is last position now
1091 else
1093 // buffer is full - ignore new font, use default font
1094 nPos = EXC_FONT_APP;
1097 return static_cast< sal_uInt16 >( nPos );
1100 sal_uInt16 XclExpFontBuffer::Insert(
1101 const Font& rFont, XclExpColorType eColorType, bool bAppFont )
1103 return Insert( XclFontData( rFont ), eColorType, bAppFont );
1106 sal_uInt16 XclExpFontBuffer::Insert(
1107 const SvxFont& rFont, XclExpColorType eColorType, bool bAppFont )
1109 return Insert( XclFontData( rFont ), eColorType, bAppFont );
1112 sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
1113 sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1115 // #i17050# script type now provided by caller
1116 Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
1117 return Insert( aFont, eColorType, bAppFont );
1120 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1122 maFontList.Save( rStrm );
1125 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1127 if( maFontList.IsEmpty() )
1128 return;
1130 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1131 rStyleSheet->startElement( XML_fonts,
1132 XML_count, OString::valueOf( (sal_Int32) maFontList.GetSize() ).getStr(),
1133 FSEND );
1135 maFontList.SaveXml( rStrm );
1137 rStyleSheet->endElement( XML_fonts );
1140 // private --------------------------------------------------------------------
1142 void XclExpFontBuffer::InitDefaultFonts()
1144 XclFontData aFontData;
1145 aFontData.maName.AssignAscii( "Arial" );
1146 aFontData.SetScFamily( FAMILY_DONTKNOW );
1147 aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
1148 aFontData.SetScHeight( 200 ); // 200 twips = 10 pt
1149 aFontData.SetScWeight( WEIGHT_NORMAL );
1151 switch( GetBiff() )
1153 case EXC_BIFF5:
1155 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1156 aFontData.SetScWeight( WEIGHT_BOLD );
1157 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1158 aFontData.SetScWeight( WEIGHT_NORMAL );
1159 aFontData.SetScPosture( ITALIC_NORMAL );
1160 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1161 aFontData.SetScWeight( WEIGHT_BOLD );
1162 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1163 // the blind font with index 4
1164 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1165 // already add the first user defined font (Excel does it too)
1166 aFontData.SetScWeight( WEIGHT_NORMAL );
1167 aFontData.SetScPosture( ITALIC_NONE );
1168 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1170 break;
1171 case EXC_BIFF8:
1173 XclExpFontRef xFont( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1174 maFontList.AppendRecord( xFont );
1175 maFontList.AppendRecord( xFont );
1176 maFontList.AppendRecord( xFont );
1177 maFontList.AppendRecord( xFont );
1178 if( GetOutput() == EXC_OUTPUT_BINARY )
1179 // the blind font with index 4
1180 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1182 break;
1183 default:
1184 DBG_ERROR_BIFF();
1188 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
1190 sal_uInt32 nHash = lclCalcHash( rFontData );
1191 for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
1192 if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
1193 return nPos;
1194 return EXC_FONTLIST_NOTFOUND;
1197 // FORMAT record - number formats =============================================
1199 /** Predicate for search algorithm. */
1200 struct XclExpNumFmtPred
1202 sal_uLong mnScNumFmt;
1203 inline explicit XclExpNumFmtPred( sal_uLong nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
1204 inline bool operator()( const XclExpNumFmt& rFormat ) const
1205 { return rFormat.mnScNumFmt == mnScNumFmt; }
1208 // ----------------------------------------------------------------------------
1210 void XclExpNumFmt::SaveXml( XclExpXmlStream& rStrm )
1212 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1213 rStyleSheet->singleElement( XML_numFmt,
1214 XML_numFmtId, OString::number( mnXclNumFmt ).getStr(),
1215 XML_formatCode, OUStringToOString(maNumFmtString, RTL_TEXTENCODING_UTF8).getStr(),
1216 FSEND );
1219 // ----------------------------------------------------------------------------
1221 XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
1222 XclExpRoot( rRoot ),
1223 /* Compiler needs a hint, this doesn't work: new NfKeywordTable;
1224 cannot convert from 'class String *' to 'class String (*)[54]'
1225 The effective result here is class String (*)[54*1] */
1226 mxFormatter( new SvNumberFormatter( comphelper::getComponentContext(rRoot.GetDoc().GetServiceManager()), LANGUAGE_ENGLISH_US ) ),
1227 mpKeywordTable( new NfKeywordTable ),
1228 mnStdFmt( GetFormatter().GetStandardFormat( ScGlobal::eLnge ) )
1230 switch( GetBiff() )
1232 case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5; break;
1233 case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8; break;
1234 default: DBG_ERROR_BIFF();
1237 mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
1238 // remap codes unknown to Excel
1239 (*mpKeywordTable)[ NF_KEY_NN ] = "DDD";
1240 (*mpKeywordTable)[ NF_KEY_NNN ] = "DDDD";
1241 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
1242 (*mpKeywordTable)[ NF_KEY_NNNN ] = "DDDD";
1243 // Export the Thai T NatNum modifier.
1244 (*mpKeywordTable)[ NF_KEY_THAI_T ] = "T";
1247 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1251 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uLong nScNumFmt )
1253 XclExpNumFmtVec::const_iterator aIt =
1254 ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1255 if( aIt != maFormatMap.end() )
1256 return aIt->mnXclNumFmt;
1258 size_t nSize = maFormatMap.size();
1259 if( nSize < static_cast< size_t >( 0xFFFF - mnXclOffset ) )
1261 sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1262 maFormatMap.push_back( XclExpNumFmt( nScNumFmt, nXclNumFmt, GetFormatCode( nScNumFmt ) ) );
1263 return nXclNumFmt;
1266 return 0;
1269 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1271 for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1272 WriteFormatRecord( rStrm, *aIt );
1275 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1277 if( !maFormatMap.size() )
1278 return;
1280 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1281 rStyleSheet->startElement( XML_numFmts,
1282 XML_count, OString::valueOf( (sal_Int32) maFormatMap.size() ).getStr(),
1283 FSEND );
1284 for( XclExpNumFmtVec::iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1286 aIt->SaveXml( rStrm );
1288 rStyleSheet->endElement( XML_numFmts );
1291 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const String& rFormatStr )
1293 XclExpString aExpStr;
1294 if( GetBiff() <= EXC_BIFF5 )
1295 aExpStr.AssignByte( rFormatStr, GetTextEncoding(), EXC_STR_8BITLENGTH );
1296 else
1297 aExpStr.Assign( rFormatStr );
1299 rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1300 rStrm << nXclNumFmt << aExpStr;
1301 rStrm.EndRecord();
1304 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1306 WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat.mnScNumFmt ) );
1309 namespace {
1311 String GetNumberFormatCode(XclRoot& rRoot, const sal_uInt16 nScNumFmt, SvNumberFormatter* xFormatter, NfKeywordTable* pKeywordTable)
1313 String aFormatStr;
1315 if( const SvNumberformat* pEntry = rRoot.GetFormatter().GetEntry( nScNumFmt ) )
1317 if( pEntry->GetType() == NUMBERFORMAT_LOGICAL )
1319 // build Boolean number format
1320 Color* pColor = 0;
1321 OUString aTemp;
1322 const_cast< SvNumberformat* >( pEntry )->GetOutputString( 1.0, aTemp, &pColor );
1323 aFormatStr.Append( '"' ).Append( aTemp ).AppendAscii( "\";\"" ).Append( aTemp ).AppendAscii( "\";\"" );
1324 const_cast< SvNumberformat* >( pEntry )->GetOutputString( 0.0, aTemp, &pColor );
1325 aFormatStr.Append( aTemp ).Append( '"' );
1327 else
1329 LanguageType eLang = pEntry->GetLanguage();
1330 if( eLang != LANGUAGE_ENGLISH_US )
1332 sal_Int32 nCheckPos;
1333 short nType = NUMBERFORMAT_DEFINED;
1334 sal_uInt32 nKey;
1335 OUString aTemp( pEntry->GetFormatstring() );
1336 xFormatter->PutandConvertEntry( aTemp, nCheckPos, nType, nKey, eLang, LANGUAGE_ENGLISH_US );
1337 OSL_ENSURE( nCheckPos == 0, "XclExpNumFmtBuffer::WriteFormatRecord - format code not convertible" );
1338 pEntry = xFormatter->GetEntry( nKey );
1341 aFormatStr = pEntry->GetMappedFormatstring( *pKeywordTable, *xFormatter->GetLocaleData() );
1342 if( aFormatStr.EqualsAscii( "Standard" ) )
1343 aFormatStr.AssignAscii( "General" );
1346 else
1348 OSL_FAIL( "XclExpNumFmtBuffer::WriteFormatRecord - format not found" );
1349 aFormatStr.AssignAscii( "General" );
1352 return aFormatStr;
1357 String XclExpNumFmtBuffer::GetFormatCode( sal_uInt16 nScNumFmt )
1359 return GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() );
1362 // XF, STYLE record - Cell formatting =========================================
1364 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
1366 const ScProtectionAttr& rProtItem = GETITEM( rItemSet, ScProtectionAttr, ATTR_PROTECTION );
1367 mbLocked = rProtItem.GetProtection();
1368 mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
1369 return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
1372 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1374 ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1375 ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1378 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1380 rStrm.GetCurrentStream()->singleElement( XML_protection,
1381 XML_locked, XclXmlUtils::ToPsz( mbLocked ),
1382 XML_hidden, XclXmlUtils::ToPsz( mbHidden ),
1383 FSEND );
1386 // ----------------------------------------------------------------------------
1388 bool XclExpCellAlign::FillFromItemSet(
1389 const SfxItemSet& rItemSet, bool bForceLineBreak, XclBiff eBiff, bool bStyle )
1391 bool bUsed = false;
1392 SvxCellHorJustify eHorAlign = GETITEMVALUE( rItemSet, SvxHorJustifyItem, ATTR_HOR_JUSTIFY, SvxCellHorJustify );
1393 SvxCellVerJustify eVerAlign = GETITEMVALUE( rItemSet, SvxVerJustifyItem, ATTR_VER_JUSTIFY, SvxCellVerJustify );
1395 switch( eBiff )
1397 // ALL 'case's - run through!
1399 case EXC_BIFF8: // attributes new in BIFF8
1401 // text indent
1402 long nTmpIndent = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_INDENT, sal_Int32 );
1403 (nTmpIndent += 100) /= 200; // 1 Excel unit == 10 pt == 200 twips
1404 mnIndent = limit_cast< sal_uInt8 >( nTmpIndent, 0, 15 );
1405 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
1407 // shrink to fit
1408 mbShrink = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_SHRINKTOFIT, sal_Bool );
1409 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1411 // CTL text direction
1412 SetScFrameDir( GETITEMVALUE( rItemSet, SvxFrameDirectionItem, ATTR_WRITINGDIR, SvxFrameDirection ) );
1413 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1416 case EXC_BIFF5: // attributes new in BIFF5
1417 case EXC_BIFF4: // attributes new in BIFF4
1419 // vertical alignment
1420 SetScVerAlign( eVerAlign );
1421 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1423 // stacked/rotation
1424 bool bStacked = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_STACKED, sal_Bool );
1425 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1426 if( bStacked )
1428 mnRotation = EXC_ROT_STACKED;
1430 else
1432 // rotation
1433 sal_Int32 nScRot = GETITEMVALUE( rItemSet, SfxInt32Item, ATTR_ROTATE_VALUE, sal_Int32 );
1434 mnRotation = XclTools::GetXclRotation( nScRot );
1435 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
1437 mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1440 case EXC_BIFF3: // attributes new in BIFF3
1442 // text wrap
1443 mbLineBreak = bForceLineBreak || GETITEMBOOL( rItemSet, ATTR_LINEBREAK );
1444 bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1447 case EXC_BIFF2: // attributes new in BIFF2
1449 // horizontal alignment
1450 SetScHorAlign( eHorAlign );
1451 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1454 break;
1455 default: DBG_ERROR_BIFF();
1458 if (eBiff == EXC_BIFF8)
1460 // Adjust for distributed alignments.
1461 if (eHorAlign == SVX_HOR_JUSTIFY_BLOCK)
1463 SvxCellJustifyMethod eHorJustMethod = GETITEMVALUE(
1464 rItemSet, SvxJustifyMethodItem, ATTR_HOR_JUSTIFY_METHOD, SvxCellJustifyMethod);
1465 if (eHorJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
1466 mnHorAlign = EXC_XF_HOR_DISTRIB;
1469 if (eVerAlign == SVX_VER_JUSTIFY_BLOCK)
1471 SvxCellJustifyMethod eVerJustMethod = GETITEMVALUE(
1472 rItemSet, SvxJustifyMethodItem, ATTR_VER_JUSTIFY_METHOD, SvxCellJustifyMethod);
1473 if (eVerJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
1474 mnVerAlign = EXC_XF_VER_DISTRIB;
1478 return bUsed;
1481 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
1483 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1484 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1485 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1486 ::insert_value( rnAlign, mnOrient, 8, 2 );
1489 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
1491 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1492 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1493 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1494 ::insert_value( rnAlign, mnRotation, 8, 8 );
1495 ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
1496 ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
1497 ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
1500 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1502 switch( nHorAlign )
1504 case EXC_XF_HOR_GENERAL: return "general";
1505 case EXC_XF_HOR_LEFT: return "left";
1506 case EXC_XF_HOR_CENTER: return "center";
1507 case EXC_XF_HOR_RIGHT: return "right";
1508 case EXC_XF_HOR_FILL: return "fill";
1509 case EXC_XF_HOR_JUSTIFY: return "justify";
1510 case EXC_XF_HOR_CENTER_AS: return "centerContinuous";
1511 case EXC_XF_HOR_DISTRIB: return "distributed";
1513 return "*unknown*";
1516 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1518 switch( nVerAlign )
1520 case EXC_XF_VER_TOP: return "top";
1521 case EXC_XF_VER_CENTER: return "center";
1522 case EXC_XF_VER_BOTTOM: return "bottom";
1523 case EXC_XF_VER_JUSTIFY: return "justify";
1524 case EXC_XF_VER_DISTRIB: return "distributed";
1526 return "*unknown*";
1529 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
1531 rStrm.GetCurrentStream()->singleElement( XML_alignment,
1532 XML_horizontal, ToHorizontalAlignment( mnHorAlign ),
1533 XML_vertical, ToVerticalAlignment( mnVerAlign ),
1534 XML_textRotation, OString::valueOf( (sal_Int32) mnRotation ).getStr(),
1535 XML_wrapText, XclXmlUtils::ToPsz( mbLineBreak ),
1536 XML_indent, OString::valueOf( (sal_Int32) mnIndent ).getStr(),
1537 // OOXTODO: XML_relativeIndent, mnIndent?
1538 // OOXTODO: XML_justifyLastLine,
1539 XML_shrinkToFit, XclXmlUtils::ToPsz( mbShrink ),
1540 // OOXTODO: XML_readingOrder,
1541 FSEND );
1544 // ----------------------------------------------------------------------------
1546 namespace {
1548 void lclGetBorderLine(
1549 sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
1550 const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1552 rnXclLine = EXC_LINE_NONE;
1553 if( pLine )
1555 sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1556 sal_uInt16 nDistance = pLine->GetDistance();
1557 if( nDistance > 0 )
1558 rnXclLine = EXC_LINE_DOUBLE;
1559 else if( nOuterWidth >= EXC_BORDER_THICK )
1560 rnXclLine = EXC_LINE_THICK;
1561 else if( nOuterWidth >= EXC_BORDER_MEDIUM )
1563 rnXclLine = EXC_LINE_MEDIUM;
1564 if (pLine->GetBorderLineStyle( ) == table::BorderLineStyle::DASHED)
1565 rnXclLine = EXC_LINE_MEDIUMDASHED;
1567 else if( nOuterWidth >= EXC_BORDER_THIN )
1569 rnXclLine = EXC_LINE_THIN;
1570 switch (pLine->GetBorderLineStyle())
1572 case table::BorderLineStyle::DASHED:
1573 rnXclLine = EXC_LINE_DASHED;
1574 break;
1575 case table::BorderLineStyle::DOTTED:
1576 rnXclLine = EXC_LINE_DOTTED;
1577 break;
1578 case table::BorderLineStyle::FINE_DASHED:
1579 rnXclLine = EXC_LINE_HAIR;
1580 break;
1581 default:
1582 break;
1585 else
1586 rnXclLine = EXC_LINE_NONE;
1588 if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1589 rnXclLine = EXC_LINE_THIN;
1591 rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
1592 rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
1593 XclExpPalette::GetColorIdFromIndex( 0 );
1596 } // namespace
1598 // ----------------------------------------------------------------------------
1600 XclExpCellBorder::XclExpCellBorder() :
1601 mnLeftColorId( XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
1602 mnRightColorId( XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
1603 mnTopColorId( XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
1604 mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
1605 mnDiagColorId( XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
1609 bool XclExpCellBorder::FillFromItemSet(
1610 const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1612 bool bUsed = false;
1614 switch( eBiff )
1616 // ALL 'case's - run through!
1618 case EXC_BIFF8: // attributes new in BIFF8
1620 const SvxLineItem& rTLBRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_TLBR );
1621 sal_uInt8 nTLBRLine;
1622 sal_uInt32 nTLBRColorId;
1623 lclGetBorderLine( nTLBRLine, nTLBRColorId, rTLBRItem.GetLine(), rPalette, eBiff );
1624 mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
1626 const SvxLineItem& rBLTRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_BLTR );
1627 sal_uInt8 nBLTRLine;
1628 sal_uInt32 nBLTRColorId;
1629 lclGetBorderLine( nBLTRLine, nBLTRColorId, rBLTRItem.GetLine(), rPalette, eBiff );
1630 mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
1632 if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1634 mnDiagLine = nTLBRLine;
1635 mnDiagColorId = nTLBRColorId;
1637 else
1639 mnDiagLine = nBLTRLine;
1640 mnDiagColorId = nBLTRColorId;
1643 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1644 ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1647 case EXC_BIFF5:
1648 case EXC_BIFF4:
1649 case EXC_BIFF3:
1650 case EXC_BIFF2:
1652 const SvxBoxItem& rBoxItem = GETITEM( rItemSet, SvxBoxItem, ATTR_BORDER );
1653 lclGetBorderLine( mnLeftLine, mnLeftColorId, rBoxItem.GetLeft(), rPalette, eBiff );
1654 lclGetBorderLine( mnRightLine, mnRightColorId, rBoxItem.GetRight(), rPalette, eBiff );
1655 lclGetBorderLine( mnTopLine, mnTopColorId, rBoxItem.GetTop(), rPalette, eBiff );
1656 lclGetBorderLine( mnBottomLine, mnBottomColorId, rBoxItem.GetBottom(), rPalette, eBiff );
1657 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
1660 break;
1661 default: DBG_ERROR_BIFF();
1664 return bUsed;
1667 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
1669 mnLeftColor = rPalette.GetColorIndex( mnLeftColorId );
1670 mnRightColor = rPalette.GetColorIndex( mnRightColorId );
1671 mnTopColor = rPalette.GetColorIndex( mnTopColorId );
1672 mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
1673 mnDiagColor = rPalette.GetColorIndex( mnDiagColorId );
1677 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
1679 ::insert_value( rnBorder, mnTopLine, 0, 3 );
1680 ::insert_value( rnBorder, mnLeftLine, 3, 3 );
1681 ::insert_value( rnArea, mnBottomLine, 22, 3 );
1682 ::insert_value( rnBorder, mnRightLine, 6, 3 );
1683 ::insert_value( rnBorder, mnTopColor, 9, 7 );
1684 ::insert_value( rnBorder, mnLeftColor, 16, 7 );
1685 ::insert_value( rnArea, mnBottomColor, 25, 7 );
1686 ::insert_value( rnBorder, mnRightColor, 23, 7 );
1689 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
1691 ::insert_value( rnBorder1, mnLeftLine, 0, 4 );
1692 ::insert_value( rnBorder1, mnRightLine, 4, 4 );
1693 ::insert_value( rnBorder1, mnTopLine, 8, 4 );
1694 ::insert_value( rnBorder1, mnBottomLine, 12, 4 );
1695 ::insert_value( rnBorder1, mnLeftColor, 16, 7 );
1696 ::insert_value( rnBorder1, mnRightColor, 23, 7 );
1697 ::insert_value( rnBorder2, mnTopColor, 0, 7 );
1698 ::insert_value( rnBorder2, mnBottomColor, 7, 7 );
1699 ::insert_value( rnBorder2, mnDiagColor, 14, 7 );
1700 ::insert_value( rnBorder2, mnDiagLine, 21, 4 );
1701 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
1702 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
1705 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
1707 ::insert_value( rnLine, mnLeftLine, 0, 4 );
1708 ::insert_value( rnLine, mnRightLine, 4, 4 );
1709 ::insert_value( rnLine, mnTopLine, 8, 4 );
1710 ::insert_value( rnLine, mnBottomLine, 12, 4 );
1711 ::insert_value( rnColor, mnLeftColor, 0, 7 );
1712 ::insert_value( rnColor, mnRightColor, 7, 7 );
1713 ::insert_value( rnColor, mnTopColor, 16, 7 );
1714 ::insert_value( rnColor, mnBottomColor, 23, 7 );
1717 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1719 switch( nLineStyle )
1721 case EXC_LINE_NONE: return "none";
1722 case EXC_LINE_THIN: return "thin";
1723 case EXC_LINE_MEDIUM: return "medium";
1724 case EXC_LINE_THICK: return "thick";
1725 case EXC_LINE_DOUBLE: return "double";
1726 case EXC_LINE_HAIR: return "hair";
1727 case EXC_LINE_DOTTED: return "dotted";
1728 case EXC_LINE_DASHED: return "dashed";
1729 case EXC_LINE_MEDIUMDASHED: return "mediumdashed";
1731 return "*unknown*";
1734 static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
1736 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1737 if( nLineStyle == EXC_LINE_NONE )
1738 rStyleSheet->singleElement( nElement, FSEND );
1739 else if( rColor == Color( 0, 0, 0, 0 ) )
1740 rStyleSheet->singleElement( nElement,
1741 XML_style, ToLineStyle( nLineStyle ),
1742 FSEND );
1743 else
1745 rStyleSheet->startElement( nElement,
1746 XML_style, ToLineStyle( nLineStyle ),
1747 FSEND );
1748 rStyleSheet->singleElement( XML_color,
1749 XML_rgb, XclXmlUtils::ToOString( rColor ).getStr(),
1750 FSEND );
1751 rStyleSheet->endElement( nElement );
1755 void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
1757 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1759 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1761 rStyleSheet->startElement( XML_border,
1762 XML_diagonalUp, XclXmlUtils::ToPsz( mbDiagBLtoTR ),
1763 XML_diagonalDown, XclXmlUtils::ToPsz( mbDiagTLtoBR ),
1764 // OOXTODO: XML_outline,
1765 FSEND );
1766 lcl_WriteBorder( rStrm, XML_left, mnLeftLine, rPalette.GetColor( mnLeftColor ) );
1767 lcl_WriteBorder( rStrm, XML_right, mnRightLine, rPalette.GetColor( mnRightColor ) );
1768 lcl_WriteBorder( rStrm, XML_top, mnTopLine, rPalette.GetColor( mnTopColor ) );
1769 lcl_WriteBorder( rStrm, XML_bottom, mnBottomLine, rPalette.GetColor( mnBottomColor ) );
1770 lcl_WriteBorder( rStrm, XML_diagonal, mnDiagLine, rPalette.GetColor( mnDiagColor ) );
1771 // OOXTODO: XML_vertical, XML_horizontal
1772 rStyleSheet->endElement( XML_border );
1775 // ----------------------------------------------------------------------------
1777 XclExpCellArea::XclExpCellArea() :
1778 mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
1779 mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) )
1783 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1785 const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
1786 if( rBrushItem.GetColor().GetTransparency() )
1788 mnPattern = EXC_PATT_NONE;
1789 mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1790 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1792 else
1794 mnPattern = EXC_PATT_SOLID;
1795 mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1796 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1798 return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1801 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1803 rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1806 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1808 ::insert_value( rnArea, mnPattern, 16, 6 );
1809 ::insert_value( rnArea, mnForeColor, 0, 7 );
1810 ::insert_value( rnArea, mnBackColor, 7, 7 );
1813 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1815 ::insert_value( rnBorder2, mnPattern, 26, 6 );
1816 ::insert_value( rnArea, mnForeColor, 0, 7 );
1817 ::insert_value( rnArea, mnBackColor, 7, 7 );
1820 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
1822 XclCellArea aTmp( *this );
1823 if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
1824 aTmp.mnBackColor = 0;
1825 if( aTmp.mnPattern == EXC_PATT_SOLID )
1826 ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
1827 ::insert_value( rnColor, aTmp.mnForeColor, 0, 7 );
1828 ::insert_value( rnColor, aTmp.mnBackColor, 7, 7 );
1829 ::insert_value( rnPattern, aTmp.mnPattern, 10, 6 );
1832 static const char* ToPatternType( sal_uInt8 nPattern )
1834 switch( nPattern )
1836 case EXC_PATT_NONE: return "none";
1837 case EXC_PATT_SOLID: return "solid";
1838 case EXC_PATT_50_PERC: return "mediumGray";
1839 case EXC_PATT_75_PERC: return "darkGray";
1840 case EXC_PATT_25_PERC: return "lightGray";
1841 case EXC_PATT_12_5_PERC: return "gray125";
1842 case EXC_PATT_6_25_PERC: return "gray0625";
1844 return "*unknown*";
1847 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1849 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1850 rStyleSheet->startElement( XML_fill,
1851 FSEND );
1853 // OOXTODO: XML_gradientFill
1855 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1857 if( mnPattern == EXC_PATT_NONE || ( mnForeColor == 0 && mnBackColor == 0 ) )
1858 rStyleSheet->singleElement( XML_patternFill,
1859 XML_patternType, ToPatternType( mnPattern ),
1860 FSEND );
1861 else
1863 rStyleSheet->startElement( XML_patternFill,
1864 XML_patternType, ToPatternType( mnPattern ),
1865 FSEND );
1866 rStyleSheet->singleElement( XML_fgColor,
1867 XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnForeColor ) ).getStr(),
1868 FSEND );
1869 rStyleSheet->singleElement( XML_bgColor,
1870 XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnBackColor ) ).getStr(),
1871 FSEND );
1872 rStyleSheet->endElement( XML_patternFill );
1875 rStyleSheet->endElement( XML_fill );
1879 bool XclExpColor::FillFromItemSet( const SfxItemSet& rItemSet )
1881 if( !ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true ) )
1882 return false;
1884 const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
1885 maColor = rBrushItem.GetColor();
1887 return true;
1890 void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const
1892 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1893 rStyleSheet->startElement( XML_fill,
1894 FSEND );
1895 rStyleSheet->startElement( XML_patternFill,
1896 FSEND );
1897 rStyleSheet->singleElement( XML_bgColor,
1898 XML_rgb, XclXmlUtils::ToOString(maColor).getStr(),
1899 FSEND );
1901 rStyleSheet->endElement( XML_patternFill );
1902 rStyleSheet->endElement( XML_fill );
1905 // ----------------------------------------------------------------------------
1907 XclExpXFId::XclExpXFId() :
1908 mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
1909 mnXFIndex( EXC_XF_DEFAULTCELL )
1913 XclExpXFId::XclExpXFId( sal_uInt32 nXFId ) :
1914 mnXFId( nXFId ),
1915 mnXFIndex( EXC_XF_DEFAULTCELL )
1919 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
1921 mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
1924 // ----------------------------------------------------------------------------
1926 XclExpXF::XclExpXF(
1927 const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
1928 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) :
1929 XclXFBase( true ),
1930 XclExpRoot( rRoot )
1932 mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
1933 Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
1936 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
1937 XclXFBase( false ),
1938 XclExpRoot( rRoot ),
1939 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
1941 bool bDefStyle = (rStyleSheet.GetName() == ScGlobal::GetRscString( STR_STYLENAME_STANDARD ));
1942 sal_Int16 nScript = bDefStyle ? GetDefApiScript() : ::com::sun::star::i18n::ScriptType::WEAK;
1943 Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
1944 NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
1947 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
1948 XclXFBase( bCellXF ),
1949 XclExpRoot( rRoot ),
1950 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
1952 InitDefault();
1955 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
1956 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
1958 return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
1959 (!bForceLineBreak || maAlignment.mbLineBreak) &&
1960 ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
1961 ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
1964 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
1966 return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
1969 void XclExpXF::SetFinalColors()
1971 maBorder.SetFinalColors( GetPalette() );
1972 maArea.SetFinalColors( GetPalette() );
1975 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
1977 return XclXFBase::Equals( rCmpXF ) &&
1978 (maProtection == rCmpXF.maProtection) && (maAlignment == rCmpXF.maAlignment) &&
1979 (maBorder == rCmpXF.maBorder) && (maArea == rCmpXF.maArea) &&
1980 (mnXclFont == rCmpXF.mnXclFont) && (mnXclNumFmt == rCmpXF.mnXclNumFmt) &&
1981 (mnParentXFId == rCmpXF.mnParentXFId);
1984 void XclExpXF::InitDefault()
1986 SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
1987 mpItemSet = 0;
1988 mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
1989 mnXclFont = mnXclNumFmt = 0;
1992 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
1993 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
1995 InitDefault();
1996 mpItemSet = &rItemSet;
1998 // cell protection
1999 mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2001 // font
2002 if( nForceXclFont == EXC_FONT_NOTFOUND )
2004 mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2005 mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2007 else
2009 mnXclFont = nForceXclFont;
2010 mbFontUsed = true;
2013 // number format
2014 mnScNumFmt = (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) ?
2015 GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) : nForceScNumFmt;
2016 mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2017 mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2018 // alignment
2019 mbAlignUsed = maAlignment.FillFromItemSet( rItemSet, bForceLineBreak, GetBiff(), IsStyleXF() );
2021 // cell border
2022 mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2024 // background area
2025 mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2027 // set all b***Used flags to true in "Default"/"Normal" style
2028 if( bDefStyle )
2029 SetAllUsedFlags( true );
2032 sal_uInt8 XclExpXF::GetUsedFlags() const
2034 sal_uInt8 nUsedFlags = 0;
2035 /* In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
2036 "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
2037 ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT, mbCellXF == mbProtUsed );
2038 ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT, mbCellXF == mbFontUsed );
2039 ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
2040 ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN, mbCellXF == mbAlignUsed );
2041 ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
2042 ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA, mbCellXF == mbAreaUsed );
2043 return nUsedFlags;
2046 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2048 sal_uInt16 nTypeProt = 0, nAlign = 0;
2049 sal_uInt32 nArea = 0, nBorder = 0;
2051 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2052 ::insert_value( nTypeProt, mnParent, 4, 12 );
2053 ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2055 maProtection.FillToXF3( nTypeProt );
2056 maAlignment.FillToXF5( nAlign );
2057 maBorder.FillToXF5( nBorder, nArea );
2058 maArea.FillToXF5( nArea );
2060 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2063 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2065 sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2066 sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2068 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2069 ::insert_value( nTypeProt, mnParent, 4, 12 );
2070 ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2072 maProtection.FillToXF3( nTypeProt );
2073 maAlignment.FillToXF8( nAlign, nMiscAttrib );
2074 maBorder.FillToXF8( nBorder1, nBorder2 );
2075 maArea.FillToXF8( nBorder2, nArea );
2077 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2080 void XclExpXF::WriteBody( XclExpStream& rStrm )
2082 XclExpXFId aParentId( mnParentXFId );
2083 aParentId.ConvertXFIndex( GetRoot() );
2084 mnParent = aParentId.mnXFIndex;
2085 switch( GetBiff() )
2087 case EXC_BIFF5: WriteBody5( rStrm ); break;
2088 case EXC_BIFF8: WriteBody8( rStrm ); break;
2089 default: DBG_ERROR_BIFF();
2093 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2095 mnBorderId = nBorderId;
2096 mnFillId = nFillId;
2099 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2101 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2103 sal_Int32 nXfId = 0;
2104 const XclExpXF* pStyleXF = NULL;
2105 if( IsCellXF() )
2107 sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2108 nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2109 pStyleXF = rStrm.GetRoot().GetXFBuffer().GetXFById( mnParentXFId );
2112 rStyleSheet->startElement( XML_xf,
2113 XML_numFmtId, OString::valueOf( (sal_Int32) mnXclNumFmt ).getStr(),
2114 XML_fontId, OString::valueOf( (sal_Int32) mnXclFont ).getStr(),
2115 XML_fillId, OString::valueOf( (sal_Int32) mnFillId ).getStr(),
2116 XML_borderId, OString::valueOf( (sal_Int32) mnBorderId ).getStr(),
2117 XML_xfId, IsStyleXF() ? NULL : OString::valueOf( nXfId ).getStr(),
2118 // OOXTODO: XML_quotePrefix,
2119 // OOXTODO: XML_pivotButton,
2120 // OOXTODO: XML_applyNumberFormat, ;
2121 XML_applyFont, XclXmlUtils::ToPsz( mbFontUsed ),
2122 // OOXTODO: XML_applyFill,
2123 XML_applyBorder, XclXmlUtils::ToPsz( mbBorderUsed ),
2124 XML_applyAlignment, XclXmlUtils::ToPsz( mbAlignUsed ),
2125 XML_applyProtection, XclXmlUtils::ToPsz( mbProtUsed ),
2126 FSEND );
2127 if( mbAlignUsed )
2128 maAlignment.SaveXml( rStrm );
2129 else if ( pStyleXF )
2130 pStyleXF->GetAlignmentData().SaveXml( rStrm );
2131 if( mbProtUsed )
2132 maProtection.SaveXml( rStrm );
2133 else if ( pStyleXF )
2134 pStyleXF->GetProtectionData().SaveXml( rStrm );
2136 // OOXTODO: XML_extLst
2137 rStyleSheet->endElement( XML_xf );
2140 // ----------------------------------------------------------------------------
2142 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2143 XclExpXF( rRoot, bCellXF )
2147 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2149 mnXclFont = nXclFont;
2150 mbFontUsed = true;
2153 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2155 mnXclNumFmt = nXclNumFmt;
2156 mbFmtUsed = true;
2159 // ----------------------------------------------------------------------------
2161 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, const String& rStyleName ) :
2162 XclExpRecord( EXC_ID_STYLE, 4 ),
2163 maName( rStyleName ),
2164 maXFId( nXFId ),
2165 mnStyleId( EXC_STYLE_USERDEF ),
2166 mnLevel( EXC_STYLE_NOLEVEL )
2168 OSL_ENSURE( maName.Len(), "XclExpStyle::XclExpStyle - empty style name" );
2169 #if OSL_DEBUG_LEVEL > 0
2170 sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
2171 OSL_ENSURE( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
2172 "XclExpStyle::XclExpStyle - this is a built-in style" );
2173 #endif
2176 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
2177 XclExpRecord( EXC_ID_STYLE, 4 ),
2178 maXFId( nXFId ),
2179 mnStyleId( nStyleId ),
2180 mnLevel( nLevel )
2184 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2186 maXFId.ConvertXFIndex( rStrm.GetRoot() );
2187 ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2188 rStrm << maXFId.mnXFIndex;
2190 if( IsBuiltIn() )
2192 rStrm << mnStyleId << mnLevel;
2194 else
2196 XclExpString aNameEx;
2197 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
2198 aNameEx.Assign( maName );
2199 else
2200 aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), EXC_STR_8BITLENGTH );
2201 rStrm << aNameEx;
2205 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2207 switch( nStyleId )
2209 case 0: return "Normal";
2210 case 3: return "Comma";
2211 case 4: return "Currency";
2212 case 5: return "Percent";
2213 case 6: return "Comma [0]";
2214 case 7: return "Currency [0]";
2216 return "*unknown*";
2219 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2221 OString sName;
2222 if( IsBuiltIn() )
2224 sName = OString( lcl_StyleNameFromId( mnStyleId ) );
2226 else
2227 sName = XclXmlUtils::ToOString( maName );
2228 // get the index in sortedlist associated with the mnXId
2229 sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXFIndex( maXFId.mnXFId );
2230 // get the style index associated with index into sortedlist
2231 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFId );
2232 rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
2233 XML_name, sName.getStr(),
2234 XML_xfId, OString::valueOf( nXFId ).getStr(),
2235 /* mso-excel 2007 complains when it finds builtinId >= 55, it is not
2236 * bothered by multiple 54 values. */
2237 #define CELL_STYLE_MAX_BUILTIN_ID 55
2238 XML_builtinId, OString::valueOf( std::min( static_cast<sal_Int32>( CELL_STYLE_MAX_BUILTIN_ID - 1 ), static_cast <sal_Int32>( mnStyleId ) ) ).getStr(),
2239 // OOXTODO: XML_iLevel,
2240 // OOXTODO: XML_hidden,
2241 XML_customBuiltin, XclXmlUtils::ToPsz( ! IsBuiltIn() ),
2242 FSEND );
2243 // OOXTODO: XML_extLst
2246 // ----------------------------------------------------------------------------
2248 namespace {
2250 const sal_uInt32 EXC_XFLIST_INDEXBASE = 0xFFFE0000;
2251 /** Maximum count of XF records to store in the XF list (performance). */
2252 const sal_uInt32 EXC_XFLIST_HARDLIMIT = 256 * 1024;
2254 bool lclIsBuiltInStyle( const String& rStyleName )
2256 return
2257 XclTools::IsBuiltInStyleName( rStyleName ) ||
2258 XclTools::IsCondFormatStyleName( rStyleName );
2261 } // namespace
2263 // ----------------------------------------------------------------------------
2265 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2266 mnStyleId( EXC_STYLE_USERDEF ),
2267 mnLevel( EXC_STYLE_NOLEVEL ),
2268 mbPredefined( true ),
2269 mbHasStyleRec( false )
2273 // ----------------------------------------------------------------------------
2275 /** Predicate for search algorithm. */
2276 struct XclExpBorderPred
2278 const XclExpCellBorder&
2279 mrBorder;
2280 inline explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2281 bool operator()( const XclExpCellBorder& rBorder ) const;
2284 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
2286 return
2287 mrBorder.mnLeftColor == rBorder.mnLeftColor &&
2288 mrBorder.mnRightColor == rBorder.mnRightColor &&
2289 mrBorder.mnTopColor == rBorder.mnTopColor &&
2290 mrBorder.mnBottomColor == rBorder.mnBottomColor &&
2291 mrBorder.mnDiagColor == rBorder.mnDiagColor &&
2292 mrBorder.mnLeftLine == rBorder.mnLeftLine &&
2293 mrBorder.mnRightLine == rBorder.mnRightLine &&
2294 mrBorder.mnTopLine == rBorder.mnTopLine &&
2295 mrBorder.mnBottomLine == rBorder.mnBottomLine &&
2296 mrBorder.mnDiagLine == rBorder.mnDiagLine &&
2297 mrBorder.mbDiagTLtoBR == rBorder.mbDiagTLtoBR &&
2298 mrBorder.mbDiagBLtoTR == rBorder.mbDiagBLtoTR &&
2299 mrBorder.mnLeftColorId == rBorder.mnLeftColorId &&
2300 mrBorder.mnRightColorId == rBorder.mnRightColorId &&
2301 mrBorder.mnTopColorId == rBorder.mnTopColorId &&
2302 mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
2303 mrBorder.mnDiagColorId == rBorder.mnDiagColorId;
2306 struct XclExpFillPred
2308 const XclExpCellArea&
2309 mrFill;
2310 inline explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2311 bool operator()( const XclExpCellArea& rFill ) const;
2314 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
2316 return
2317 mrFill.mnForeColor == rFill.mnForeColor &&
2318 mrFill.mnBackColor == rFill.mnBackColor &&
2319 mrFill.mnPattern == rFill.mnPattern &&
2320 mrFill.mnForeColorId == rFill.mnForeColorId &&
2321 mrFill.mnBackColorId == rFill.mnBackColorId;
2324 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
2325 XclExpRoot( rRoot )
2329 void XclExpXFBuffer::Initialize()
2331 InsertDefaultRecords();
2332 InsertUserStyles();
2335 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2337 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2340 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2341 sal_uInt16 nForceXclFont, bool bForceLineBreak )
2343 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2346 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uLong nForceScNumFmt, bool bForceLineBreak )
2348 return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2351 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2353 return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2356 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2358 return EXC_XFLIST_INDEXBASE | nXFIndex;
2361 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2363 return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2366 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2368 return maXFList.GetRecord( nXFId ).get();
2371 void XclExpXFBuffer::Finalize()
2373 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2374 maXFList.GetRecord( nPos )->SetFinalColors();
2376 sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
2377 sal_uInt32 nId;
2378 maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2379 maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2380 maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2382 XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
2383 /* nMaxBuiltInXFId used to decide faster whether an XF record is
2384 user-defined. If the current XF ID is greater than this value,
2385 maBuiltInMap doesn't need to be searched. */
2386 sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
2388 // *** map all built-in XF records (cell and style) *** -------------------
2390 // do not change XF order -> std::map<> iterates elements in ascending order
2391 for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(); aIt != aBuiltInEnd; ++aIt )
2392 AppendXFIndex( aIt->first );
2394 // *** insert all user-defined style XF records, without reduce *** -------
2396 sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
2398 for( nId = 0; nId < nTotalCount; ++nId )
2400 XclExpXFRef xXF = maXFList.GetRecord( nId );
2401 if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2403 if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2405 // maximum count of styles not reached
2406 AppendXFIndex( nId );
2407 ++nStyleXFCount;
2409 else
2411 /* Maximum count of styles reached - do not append more
2412 pointers to XFs; use default style XF instead; do not break
2413 the loop to initialize all maXFIndexVec elements. */
2414 maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
2419 // *** insert all cell XF records *** -------------------------------------
2421 // start position to search for equal inserted XF records
2422 size_t nSearchStart = maSortedXFList.GetSize();
2424 // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
2425 XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
2426 for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
2428 XclExpXFRef xXF = maXFList.GetRecord( nId );
2429 if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2431 // try to find an XF record equal to *xXF, which is already inserted
2432 sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2434 // first try if it is equal to the default cell XF
2435 if( xDefCellXF->Equals( *xXF ) )
2437 nFoundIndex = EXC_XF_DEFAULTCELL;
2439 else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2440 (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2442 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2443 nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
2446 if( nFoundIndex != EXC_XF_NOTFOUND )
2447 // equal XF already in the list, use its resulting XF index
2448 maXFIndexVec[ nId ] = nFoundIndex;
2449 else
2450 AppendXFIndex( nId );
2454 sal_uInt16 nXmlStyleIndex = 0;
2455 sal_uInt16 nXmlCellIndex = 0;
2457 size_t nXFCount = maSortedXFList.GetSize();
2458 for( size_t i = 0; i < nXFCount; ++i )
2460 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2461 if( xXF->IsStyleXF() )
2462 maStyleIndexes[ i ] = nXmlStyleIndex++;
2463 else
2464 maCellIndexes[ i ] = nXmlCellIndex++;
2468 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
2470 sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
2471 if( nXFId >= EXC_XFLIST_INDEXBASE )
2472 nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
2473 else if( nXFId < maXFIndexVec.size() )
2474 nXFIndex = maXFIndexVec[ nXFId ];
2475 return nXFIndex;
2478 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
2480 OSL_ENSURE( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2481 if( nXFIndex > maStyleIndexes.size() )
2482 return 0; // should be caught/debugged via above assert; return "valid" index.
2483 return maStyleIndexes[ nXFIndex ];
2486 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
2488 OSL_ENSURE( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2489 if( nXFIndex > maCellIndexes.size() )
2490 return 0; // should be caught/debugged via above assert; return "valid" index.
2491 return maCellIndexes[ nXFIndex ];
2494 void XclExpXFBuffer::Save( XclExpStream& rStrm )
2496 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2497 maSortedXFList.Save( rStrm );
2498 // save all STYLE records
2499 maStyleList.Save( rStrm );
2502 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2504 rCells = 0;
2505 rStyles = 0;
2506 size_t nXFCount = rXFList.GetSize();
2507 for( size_t i = 0; i < nXFCount; ++i )
2509 XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2510 if( xXF->IsCellXF() )
2511 ++rCells;
2512 else if( xXF->IsStyleXF() )
2513 ++rStyles;
2517 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2519 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2521 rStyleSheet->startElement( XML_fills,
2522 XML_count, OString::valueOf( (sal_Int32) maFills.size() ).getStr(),
2523 FSEND );
2524 for( XclExpFillList::iterator aIt = maFills.begin(), aEnd = maFills.end();
2525 aIt != aEnd; ++aIt )
2527 aIt->SaveXml( rStrm );
2529 rStyleSheet->endElement( XML_fills );
2531 rStyleSheet->startElement( XML_borders,
2532 XML_count, OString::valueOf( (sal_Int32) maBorders.size() ).getStr(),
2533 FSEND );
2534 for( XclExpBorderList::iterator aIt = maBorders.begin(), aEnd = maBorders.end();
2535 aIt != aEnd; ++aIt )
2537 aIt->SaveXml( rStrm );
2539 rStyleSheet->endElement( XML_borders );
2541 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2542 sal_Int32 nCells, nStyles;
2543 lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
2545 if( nStyles > 0 )
2547 rStyleSheet->startElement( XML_cellStyleXfs,
2548 XML_count, OString::valueOf( nStyles ).getStr(),
2549 FSEND );
2550 size_t nXFCount = maSortedXFList.GetSize();
2551 for( size_t i = 0; i < nXFCount; ++i )
2553 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2554 if( ! xXF->IsStyleXF() )
2555 continue;
2556 SaveXFXml( rStrm, *xXF );
2558 rStyleSheet->endElement( XML_cellStyleXfs );
2561 if( nCells > 0 )
2563 rStyleSheet->startElement( XML_cellXfs,
2564 XML_count, OString::valueOf( nCells ).getStr(),
2565 FSEND );
2566 size_t nXFCount = maSortedXFList.GetSize();
2567 for( size_t i = 0; i < nXFCount; ++i )
2569 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2570 if( ! xXF->IsCellXF() )
2571 continue;
2572 SaveXFXml( rStrm, *xXF );
2574 rStyleSheet->endElement( XML_cellXfs );
2577 // save all STYLE records
2578 rStyleSheet->startElement( XML_cellStyles,
2579 XML_count, OString::valueOf( (sal_Int32) maStyleList.GetSize() ).getStr(),
2580 FSEND );
2581 maStyleList.SaveXml( rStrm );
2582 rStyleSheet->endElement( XML_cellStyles );
2585 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
2587 XclExpBorderList::iterator aBorderPos =
2588 std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
2589 OSL_ENSURE( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
2590 XclExpFillList::iterator aFillPos =
2591 std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
2592 OSL_ENSURE( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
2594 sal_Int32 nBorderId = 0, nFillId = 0;
2595 if( aBorderPos != maBorders.end() )
2596 nBorderId = std::distance( maBorders.begin(), aBorderPos );
2597 if( aFillPos != maFills.end() )
2598 nFillId = std::distance( maFills.begin(), aFillPos );
2600 rXF.SetXmlIds( nBorderId, nFillId );
2601 rXF.SaveXml( rStrm );
2604 sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
2605 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2607 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2608 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2609 return static_cast< sal_uInt32 >( nPos );
2610 return EXC_XFID_NOTFOUND;
2613 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
2615 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2616 if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
2617 return static_cast< sal_uInt32 >( nPos );
2618 return EXC_XFID_NOTFOUND;
2621 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
2623 for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(), aEnd = maBuiltInMap.end(); aIt != aEnd; ++aIt )
2624 if( (aIt->second.mnStyleId == nStyleId) && (aIt->second.mnLevel == nLevel) )
2625 return aIt->first;
2626 return EXC_XFID_NOTFOUND;
2629 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2630 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2632 const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
2633 if( !pPattern )
2634 pPattern = pDefPattern;
2636 // special handling for default cell formatting
2637 if( (pPattern == pDefPattern) && !bForceLineBreak &&
2638 (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2639 (nForceXclFont == EXC_FONT_NOTFOUND) )
2641 // Is it the first try to insert the default cell format?
2642 bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2643 if( rbPredefined )
2645 // replace default cell pattern
2646 XclExpXFRef xNewXF( new XclExpXF( GetRoot(), *pPattern, nScript ) );
2647 maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
2648 rbPredefined = false;
2650 return GetDefCellXFId();
2653 sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2654 if( nXFId == EXC_XFID_NOTFOUND )
2656 // not found - insert new cell XF
2657 if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
2659 maXFList.AppendNewRecord( new XclExpXF(
2660 GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak ) );
2661 // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
2662 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
2664 else
2666 // list full - fall back to default cell XF
2667 nXFId = GetDefCellXFId();
2670 return nXFId;
2673 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2675 // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2677 sal_uInt8 nStyleId, nLevel;
2678 if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
2680 // try to find the built-in XF record (if already created in InsertDefaultRecords())
2681 sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
2682 if( nXFId == EXC_XFID_NOTFOUND )
2684 // built-in style XF not yet created - do it now
2685 XclExpXFRef xXF( new XclExpXF( GetRoot(), rStyleSheet ) );
2686 nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
2687 // this new XF record is not predefined
2688 maBuiltInMap[ nXFId ].mbPredefined = false;
2690 else
2692 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
2693 // XF record still predefined? -> Replace with real XF
2694 bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
2695 if( rbPredefined )
2697 // replace predefined built-in style (ReplaceRecord() deletes old record)
2698 maXFList.ReplaceRecord( XclExpXFRef( new XclExpXF( GetRoot(), rStyleSheet ) ), nXFId );
2699 rbPredefined = false;
2703 // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2704 bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2705 if( !rbHasStyleRec )
2707 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2708 rbHasStyleRec = true;
2711 return nXFId;
2714 // *** try to find the XF record of a user-defined style ***
2716 sal_uInt32 nXFId = FindXF( rStyleSheet );
2717 if( nXFId == EXC_XFID_NOTFOUND )
2719 // not found - insert new style XF and STYLE
2720 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2721 if( nXFId < EXC_XFLIST_HARDLIMIT )
2723 maXFList.AppendNewRecord( new XclExpXF( GetRoot(), rStyleSheet ) );
2724 // create the STYLE record
2725 if( rStyleSheet.GetName().Len() )
2726 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
2728 else
2729 // list full - fall back to default style XF
2730 nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2732 return nXFId;
2735 void XclExpXFBuffer::InsertUserStyles()
2737 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
2738 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
2739 if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
2740 InsertStyleXF( *pStyleSheet );
2743 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2745 sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2746 maXFList.AppendRecord( xXF );
2747 XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
2748 rInfo.mnStyleId = nStyleId;
2749 rInfo.mnLevel = nLevel;
2750 rInfo.mbPredefined = true;
2751 return nXFId;
2754 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2756 sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
2757 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2758 maBuiltInMap[ nXFId ].mbHasStyleRec = true; // mark existing STYLE record
2759 return nXFId;
2762 static XclExpCellArea lcl_GetPatternFill_None()
2764 XclExpCellArea aFill;
2765 aFill.mnPattern = EXC_PATT_NONE;
2766 return aFill;
2769 static XclExpCellArea lcl_GetPatternFill_Gray125()
2771 XclExpCellArea aFill;
2772 aFill.mnPattern = EXC_PATT_12_5_PERC;
2773 aFill.mnForeColor = 0;
2774 aFill.mnBackColor = 0;
2775 return aFill;
2778 void XclExpXFBuffer::InsertDefaultRecords()
2780 maFills.push_back( lcl_GetPatternFill_None() );
2781 maFills.push_back( lcl_GetPatternFill_Gray125() );
2783 // index 0: default style
2784 if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) )
2786 XclExpXFRef xDefStyle( new XclExpXF( GetRoot(), *pDefStyleSheet ) );
2787 sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2788 // mark this XF as not predefined, prevents overwriting
2789 maBuiltInMap[ nXFId ].mbPredefined = false;
2791 else
2793 OSL_FAIL( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
2794 XclExpXFRef xDefStyle( new XclExpDefaultXF( GetRoot(), false ) );
2795 xDefStyle->SetAllUsedFlags( true );
2796 AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2799 // index 1-14: RowLevel and ColLevel styles (without STYLE records)
2800 XclExpDefaultXF aLevelStyle( GetRoot(), false );
2801 // RowLevel_1, ColLevel_1
2802 aLevelStyle.SetFont( 1 );
2803 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 0 );
2804 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 0 );
2805 // RowLevel_2, ColLevel_2
2806 aLevelStyle.SetFont( 2 );
2807 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 1 );
2808 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 1 );
2809 // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
2810 aLevelStyle.SetFont( 0 );
2811 for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
2813 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, nLevel );
2814 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, nLevel );
2817 // index 15: default hard cell format, placeholder to be able to add more built-in styles
2818 maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
2819 maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
2821 // index 16-20: other built-in styles
2822 XclExpDefaultXF aFormatStyle( GetRoot(), false );
2823 aFormatStyle.SetFont( 1 );
2824 aFormatStyle.SetNumFmt( 43 );
2825 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA );
2826 aFormatStyle.SetNumFmt( 41 );
2827 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA_0 );
2828 aFormatStyle.SetNumFmt( 44 );
2829 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY );
2830 aFormatStyle.SetNumFmt( 42 );
2831 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY_0 );
2832 aFormatStyle.SetNumFmt( 9 );
2833 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_PERCENT );
2835 // other built-in style XF records (i.e. Hyperlink styles) are created on demand
2837 /* Insert the real default hard cell format -> 0 is document default pattern.
2838 Do it here (and not already above) to really have all built-in styles. */
2839 Insert( 0, GetDefApiScript() );
2842 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
2844 OSL_ENSURE( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
2845 maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
2846 XclExpXFRef xXF = maXFList.GetRecord( nXFId );
2847 AddBorderAndFill( *xXF );
2848 maSortedXFList.AppendRecord( xXF );
2849 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
2852 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
2854 if( std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) == maBorders.end() )
2856 maBorders.push_back( rXF.GetBorderData() );
2859 if( std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) == maFills.end() )
2861 maFills.push_back( rXF.GetAreaData() );
2866 XclExpDxfs::XclExpDxfs( const XclExpRoot& rRoot )
2867 : XclExpRoot( rRoot ),
2868 mxFormatter( new SvNumberFormatter( comphelper::getComponentContext(rRoot.GetDoc().GetServiceManager()), LANGUAGE_ENGLISH_US ) ),
2869 mpKeywordTable( new NfKeywordTable )
2871 mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
2872 // remap codes unknown to Excel
2873 (*mpKeywordTable)[ NF_KEY_NN ] = "DDD";
2874 (*mpKeywordTable)[ NF_KEY_NNN ] = "DDDD";
2875 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
2876 (*mpKeywordTable)[ NF_KEY_NNNN ] = "DDDD";
2877 // Export the Thai T NatNum modifier.
2878 (*mpKeywordTable)[ NF_KEY_THAI_T ] = "T";
2880 SCTAB nTables = rRoot.GetDoc().GetTableCount();
2881 for(SCTAB nTab = 0; nTab < nTables; ++nTab)
2883 ScConditionalFormatList* pList = rRoot.GetDoc().GetCondFormList(nTab);
2884 if (pList)
2886 sal_Int32 nIndex = 0;
2887 for (ScConditionalFormatList::const_iterator itr = pList->begin();
2888 itr != pList->end(); ++itr)
2890 size_t nEntryCount = itr->size();
2891 for (size_t nFormatEntry = 0; nFormatEntry < nEntryCount; ++nFormatEntry)
2893 const ScFormatEntry* pFormatEntry = itr->GetEntry(nFormatEntry);
2894 if (!pFormatEntry || (pFormatEntry->GetType() != condformat::CONDITION &&
2895 pFormatEntry->GetType() != condformat::DATE))
2896 continue;
2898 OUString aStyleName;
2899 if(pFormatEntry->GetType() == condformat::CONDITION)
2901 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
2902 aStyleName= pEntry->GetStyle();
2904 else
2906 const ScCondDateFormatEntry* pEntry = static_cast<const ScCondDateFormatEntry*>(pFormatEntry);
2907 aStyleName = pEntry->GetStyleName();
2910 if (maStyleNameToDxfId.find(aStyleName) == maStyleNameToDxfId.end())
2912 maStyleNameToDxfId.insert(std::pair<OUString, sal_Int32>(aStyleName, nIndex));
2914 SfxStyleSheetBase* pStyle = rRoot.GetDoc().GetStyleSheetPool()->Find(aStyleName);
2915 if(!pStyle)
2916 continue;
2918 SfxItemSet& rSet = pStyle->GetItemSet();
2920 XclExpCellBorder* pBorder = new XclExpCellBorder;
2921 if (!pBorder->FillFromItemSet( rSet, GetPalette(), GetBiff()) )
2923 delete pBorder;
2924 pBorder = NULL;
2927 XclExpCellAlign* pAlign = new XclExpCellAlign;
2928 if (!pAlign->FillFromItemSet( rSet, false, GetBiff()))
2930 delete pAlign;
2931 pAlign = NULL;
2934 XclExpCellProt* pCellProt = new XclExpCellProt;
2935 if (!pCellProt->FillFromItemSet( rSet ))
2937 delete pCellProt;
2938 pCellProt = NULL;
2941 XclExpColor* pColor = new XclExpColor();
2942 if(!pColor->FillFromItemSet( rSet ))
2944 delete pColor;
2945 pColor = NULL;
2948 XclExpFont* pFont = NULL;
2949 // check if non default font is set and only export then
2950 if (rSet.GetItemState(rSet.GetPool()->GetWhich( SID_ATTR_CHAR_FONT )) == SFX_ITEM_SET )
2952 Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rSet, com::sun::star::i18n::ScriptType::WEAK );
2953 pFont = new XclExpFont( GetRoot(), XclFontData( aFont ), EXC_COLOR_CELLTEXT );
2956 XclExpNumFmt* pNumFormat = NULL;
2957 const SfxPoolItem *pPoolItem = NULL;
2958 if( rSet.GetItemState( ATTR_VALUE_FORMAT, sal_True, &pPoolItem ) == SFX_ITEM_SET )
2960 sal_uLong nScNumFmt = static_cast< sal_uInt32 >( static_cast< const SfxInt32Item* >(pPoolItem)->GetValue());
2961 sal_Int32 nXclNumFmt = GetRoot().GetNumFmtBuffer().Insert(nScNumFmt);
2962 pNumFormat = new XclExpNumFmt( nScNumFmt, nXclNumFmt, GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() ));
2965 maDxf.push_back(new XclExpDxf( rRoot, pAlign, pBorder, pFont, pNumFormat, pCellProt, pColor ));
2966 ++nIndex;
2975 sal_Int32 XclExpDxfs::GetDxfId( const OUString& rStyleName )
2977 std::map<OUString, sal_Int32>::iterator itr = maStyleNameToDxfId.find(rStyleName);
2978 if(itr!= maStyleNameToDxfId.end())
2979 return itr->second;
2980 return -1;
2983 void XclExpDxfs::SaveXml( XclExpXmlStream& rStrm )
2985 if(maDxf.empty())
2986 return;
2988 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2989 rStyleSheet->startElement( XML_dxfs,
2990 XML_count, OString::number(maDxf.size()).getStr(),
2991 FSEND );
2993 for ( DxfContainer::iterator itr = maDxf.begin(); itr != maDxf.end(); ++itr )
2995 itr->SaveXml( rStrm );
2998 rStyleSheet->endElement( XML_dxfs );
3001 // ============================================================================
3003 XclExpDxf::XclExpDxf( const XclExpRoot& rRoot, XclExpCellAlign* pAlign, XclExpCellBorder* pBorder,
3004 XclExpFont* pFont, XclExpNumFmt* pNumberFmt, XclExpCellProt* pProt, XclExpColor* pColor)
3005 : XclExpRoot( rRoot ),
3006 mpAlign(pAlign),
3007 mpBorder(pBorder),
3008 mpFont(pFont),
3009 mpNumberFmt(pNumberFmt),
3010 mpProt(pProt),
3011 mpColor(pColor)
3015 XclExpDxf::~XclExpDxf()
3019 void XclExpDxf::SaveXml( XclExpXmlStream& rStrm )
3021 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3022 rStyleSheet->startElement( XML_dxf, FSEND );
3024 if (mpFont)
3025 mpFont->SaveXml(rStrm);
3026 if (mpNumberFmt)
3027 mpNumberFmt->SaveXml(rStrm);
3028 if (mpColor)
3029 mpColor->SaveXml(rStrm);
3030 if (mpAlign)
3031 mpAlign->SaveXml(rStrm);
3032 if (mpBorder)
3033 mpBorder->SaveXml(rStrm);
3034 if (mpProt)
3035 mpProt->SaveXml(rStrm);
3036 rStyleSheet->endElement( XML_dxf );
3039 // ============================================================================
3041 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3042 : XclExpRoot( rRoot )
3046 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
3048 sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
3049 OUString( "xl/styles.xml"),
3050 OUString( "styles.xml" ),
3051 rStrm.GetCurrentStream()->getOutputStream(),
3052 "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3053 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" );
3054 rStrm.PushStream( aStyleSheet );
3056 aStyleSheet->startElement( XML_styleSheet,
3057 XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
3058 FSEND );
3060 CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
3061 CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
3062 CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
3063 CreateRecord( EXC_ID_DXFS )->SaveXml( rStrm );
3064 CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
3066 aStyleSheet->endElement( XML_styleSheet );
3068 rStrm.PopStream();
3071 // ============================================================================
3073 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */