fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xestyle.cxx
blobdf5c75b2e82248981286ef1014170cf11d910c29
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/fontitem.hxx>
41 #include <editeng/eeitem.hxx>
42 #include <editeng/escapementitem.hxx>
43 #include <editeng/justifyitem.hxx>
44 #include "document.hxx"
45 #include "stlpool.hxx"
46 #include "stlsheet.hxx"
47 #include "patattr.hxx"
48 #include "attrib.hxx"
49 #include "globstr.hrc"
50 #include "xestring.hxx"
51 #include "conditio.hxx"
53 #include <oox/token/tokens.hxx>
54 #include <boost/ptr_container/ptr_vector.hpp>
56 using namespace ::com::sun::star;
57 using namespace oox;
59 // PALETTE record - color information =========================================
61 namespace {
63 sal_uInt32 lclGetWeighting( XclExpColorType eType )
65 switch( eType )
67 case EXC_COLOR_CHARTLINE: return 1;
68 case EXC_COLOR_CELLBORDER:
69 case EXC_COLOR_CHARTAREA: return 2;
70 case EXC_COLOR_CELLTEXT:
71 case EXC_COLOR_CHARTTEXT:
72 case EXC_COLOR_CTRLTEXT: return 10;
73 case EXC_COLOR_TABBG:
74 case EXC_COLOR_CELLAREA: return 20;
75 case EXC_COLOR_GRID: return 50;
76 default: OSL_FAIL( "lclGetWeighting - unknown color type" );
78 return 1;
81 sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
83 sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
84 nDist *= nDist * 77;
85 sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
86 nDist += nDummy * nDummy * 151;
87 nDummy = rColor1.GetBlue() - rColor2.GetBlue();
88 nDist += nDummy * nDummy * 28;
89 return nDist;
92 sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
94 sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
95 sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
96 if( nComp1Dist != nComp2Dist )
98 /* #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
99 Increase its weighting to prevent fading of the colors during reduction. */
100 const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
101 sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
102 rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
104 sal_uInt32 nWSum = nWeight1 + nWeight2;
105 return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
108 void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
110 rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
111 rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
112 rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
115 } // namespace
117 // additional classes for color reduction -------------------------------------
119 namespace {
121 /** Represents an entry in a color list.
123 The color stores a weighting value, which increases the more the color is
124 used in the document. Heavy-weighted colors will change less than others on
125 color reduction.
127 class XclListColor
129 DECL_FIXEDMEMPOOL_NEWDEL( XclListColor )
131 private:
132 Color maColor; /// The color value of this palette entry.
133 sal_uInt32 mnColorId; /// Unique color ID for color reduction.
134 sal_uInt32 mnWeight; /// Weighting for color reduction.
135 bool mbBaseColor; /// true = Handle as base color, (don't remove/merge).
137 public:
138 explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
140 /** Returns the RGB color value of the color. */
141 inline const Color& GetColor() const { return maColor; }
142 /** Returns the unique ID of the color. */
143 inline sal_uInt32 GetColorId() const { return mnColorId; }
144 /** Returns the current weighting of the color. */
145 inline sal_uInt32 GetWeighting() const { return mnWeight; }
146 /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
147 inline bool IsBaseColor() const { return mbBaseColor; }
149 /** Adds the passed weighting to this color. */
150 inline void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
151 /** Merges this color with rColor, regarding weighting settings. */
152 void Merge( const XclListColor& rColor );
155 IMPL_FIXEDMEMPOOL_NEWDEL( XclListColor )
157 XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
158 maColor( rColor ),
159 mnColorId( nColorId ),
160 mnWeight( 0 )
162 mbBaseColor =
163 ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
164 ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
165 ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
168 void XclListColor::Merge( const XclListColor& rColor )
170 sal_uInt32 nWeight2 = rColor.GetWeighting();
171 // do not change RGB value of base colors
172 if( !mbBaseColor )
174 maColor.SetRed( lclGetMergedColorComp( maColor.GetRed(), mnWeight, rColor.maColor.GetRed(), nWeight2 ) );
175 maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
176 maColor.SetBlue( lclGetMergedColorComp( maColor.GetBlue(), mnWeight, rColor.maColor.GetBlue(), nWeight2 ) );
178 AddWeighting( nWeight2 );
181 /** Data for each inserted original color, represented by a color ID. */
182 struct XclColorIdData
184 Color maColor; /// The original inserted color.
185 sal_uInt32 mnIndex; /// Maps current color ID to color list or export color vector.
186 /** Sets the contents of this struct. */
187 inline void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
190 /** A color that will be written to the Excel file. */
191 struct XclPaletteColor
193 Color maColor; /// Resulting color to export.
194 bool mbUsed; /// true = Entry is used in the document.
196 inline explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
197 inline void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
200 /** Maps a color list index to a palette index.
201 @descr Used to remap the color ID data vector from list indexes to palette indexes. */
202 struct XclRemap
204 sal_uInt32 mnPalIndex; /// Index to palette.
205 bool mbProcessed; /// true = List color already processed.
207 inline explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
208 inline void SetIndex( sal_uInt32 nPalIndex )
209 { mnPalIndex = nPalIndex; mbProcessed = true; }
212 /** Stores the nearest palette color index of a list color. */
213 struct XclNearest
215 sal_uInt32 mnPalIndex; /// Index to nearest palette color.
216 sal_Int32 mnDist; /// Distance to palette color.
218 inline explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
221 typedef ::std::vector< XclRemap > XclRemapVec;
222 typedef ::std::vector< XclNearest > XclNearestVec;
224 } // namespace
226 class XclExpPaletteImpl
228 public:
229 explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
231 /** Inserts the color into the list and updates weighting.
232 @param nAutoDefault The Excel palette index for automatic color.
233 @return A unique ID for this color. */
234 sal_uInt32 InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
235 /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
236 static sal_uInt32 GetColorIdFromIndex( sal_uInt16 nIndex );
238 /** Reduces the color list to the maximum count of the current BIFF version. */
239 void Finalize();
241 /** Returns the Excel palette index of the color with passed color ID. */
242 sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
244 /** Returns a foreground and background color for the two passed color IDs.
245 @descr If rnXclPattern contains a solid pattern, this function tries to find
246 the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
247 This will result in a better approximation to the passed foreground color. */
248 void GetMixedColors(
249 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
250 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
252 /** Returns the RGB color data for a (non-zero-based) Excel palette entry.
253 @return The color from current or default palette or COL_AUTO, if nothing else found. */
254 ColorData GetColorData( sal_uInt16 nXclIndex ) const;
256 /** Returns true, if all colors of the palette are equal to default palette colors. */
257 bool IsDefaultPalette() const;
258 /** Writes the color list (contents of the palette record) to the passed stream. */
259 void WriteBody( XclExpStream& rStrm );
260 void SaveXml( XclExpXmlStream& rStrm );
262 private:
263 /** Returns the Excel index of a 0-based color index. */
264 static inline sal_uInt16 GetXclIndex( sal_uInt32 nIndex )
265 { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
267 /** Returns the original inserted color represented by the color ID nColorId. */
268 const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
270 /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
271 XclListColor* SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
272 /** Creates and inserts a new color list entry at the specified list position. */
273 XclListColor* CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
275 /** Raw and fast reduction of the palette. */
276 void RawReducePalette( sal_uInt32 nPass );
277 /** Reduction of one color using advanced color merging based on color weighting. */
278 void ReduceLeastUsedColor();
280 /** Finds the least used color and returns its current list index. */
281 sal_uInt32 GetLeastUsedListColor() const;
282 /** Returns the list index of the color nearest to rColor.
283 @param nIgnore List index of a color which will be ignored.
284 @return The list index of the found color. */
285 sal_uInt32 GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
286 /** Returns the list index of the color nearest to the color with list index nIndex. */
287 sal_uInt32 GetNearestListColor( sal_uInt32 nIndex ) const;
289 /** Returns in rnIndex the palette index of the color nearest to rColor.
290 @param bDefaultOnly true = Searches for default colors only (colors never replaced).
291 @return The distance from passed color to found color. */
292 sal_Int32 GetNearestPaletteColor(
293 sal_uInt32& rnIndex,
294 const Color& rColor, bool bDefaultOnly ) const;
295 /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
296 @return The minimum distance from passed color to found colors. */
297 sal_Int32 GetNearPaletteColors(
298 sal_uInt32& rnFirst, sal_uInt32& rnSecond,
299 const Color& rColor ) const;
301 private:
302 typedef boost::ptr_vector< XclListColor > XclListColorList;
303 typedef boost::shared_ptr< XclListColorList > XclListColorListRef;
304 typedef ::std::vector< XclColorIdData > XclColorIdDataVec;
305 typedef ::std::vector< XclPaletteColor > XclPaletteColorVec;
307 const XclDefaultPalette& mrDefPal; /// The default palette for the current BIFF version.
308 XclListColorListRef mxColorList; /// Working color list.
309 XclColorIdDataVec maColorIdDataVec; /// Data of all CIDs.
310 XclPaletteColorVec maPalette; /// Contains resulting colors to export.
311 sal_uInt32 mnLastIdx; /// Last insertion index for search opt.
314 const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
315 const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
317 XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
318 mrDefPal( rDefPal ),
319 mxColorList( new XclListColorList ),
320 mnLastIdx( 0 )
322 // initialize maPalette with default colors
323 sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
324 maPalette.reserve( nCount );
325 for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
326 maPalette.push_back( XclPaletteColor( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) ) );
328 InsertColor( Color( COL_BLACK ), EXC_COLOR_CELLTEXT );
331 sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
333 if( rColor.GetColor() == COL_AUTO )
334 return GetColorIdFromIndex( nAutoDefault );
336 sal_uInt32 nFoundIdx = 0;
337 XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
338 if( !pEntry || (pEntry->GetColor() != rColor) )
339 pEntry = CreateListEntry( rColor, nFoundIdx );
340 pEntry->AddWeighting( lclGetWeighting( eType ) );
342 return pEntry->GetColorId();
345 sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
347 return EXC_PAL_INDEXBASE | nIndex;
350 void XclExpPaletteImpl::Finalize()
352 // --- build initial color ID data vector (maColorIdDataVec) ---
354 sal_uInt32 nCount = mxColorList->size();
355 maColorIdDataVec.resize( nCount );
356 for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
358 const XclListColor& listColor = mxColorList->at( nIdx );
359 maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
362 // --- loop as long as current color count does not fit into palette of current BIFF ---
364 // phase 1: raw reduction (performance reasons, #i36945#)
365 sal_uInt32 nPass = 0;
366 while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
367 RawReducePalette( nPass++ );
369 // phase 2: precise reduction using advanced color merging based on color weighting
370 while( mxColorList->size() > mrDefPal.GetColorCount() )
371 ReduceLeastUsedColor();
373 // --- use default palette and replace colors with nearest used colors ---
375 nCount = mxColorList->size();
376 XclRemapVec aRemapVec( nCount );
377 XclNearestVec aNearestVec( nCount );
379 // in each run: search the best fitting color and replace a default color with it
380 for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
382 sal_uInt32 nIndex;
383 // find nearest unused default color for each unprocessed list color
384 for( nIndex = 0; nIndex < nCount; ++nIndex )
385 aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
386 GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->at( nIndex ).GetColor(), true );
387 // find the list color which is nearest to a default color
388 sal_uInt32 nFound = 0;
389 for( nIndex = 1; nIndex < nCount; ++nIndex )
390 if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
391 nFound = nIndex;
392 // replace default color with list color
393 sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
394 OSL_ENSURE( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
395 maPalette[ nNearest ].SetColor( mxColorList->at( nFound ).GetColor() );
396 aRemapVec[ nFound ].SetIndex( nNearest );
399 // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
400 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
401 aIt->mnIndex = aRemapVec[ aIt->mnIndex ].mnPalIndex;
404 sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
406 sal_uInt16 nRet = 0;
407 if( nColorId >= EXC_PAL_INDEXBASE )
408 nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
409 else if( nColorId < maColorIdDataVec.size() )
410 nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
411 return nRet;
414 void XclExpPaletteImpl::GetMixedColors(
415 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
416 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
418 rnXclForeIx = GetColorIndex( nForeColorId );
419 rnXclBackIx = GetColorIndex( nBackColorId );
420 if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
421 return;
423 // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
425 sal_uInt32 nIndex1, nIndex2;
426 Color aForeColor( GetOriginalColor( nForeColorId ) );
427 sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
428 if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
429 return;
431 Color aColorArr[ 5 ];
432 aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
433 aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
434 lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
435 lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
436 lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
438 sal_Int32 nMinDist = nFirstDist;
439 sal_uInt32 nMinIndex = 0;
440 for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
442 sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
443 if( nDist < nMinDist )
445 nMinDist = nDist;
446 nMinIndex = nCnt;
449 rnXclForeIx = GetXclIndex( nIndex1 );
450 rnXclBackIx = GetXclIndex( nIndex2 );
451 if( nMinDist < nFirstDist )
453 switch( nMinIndex )
455 case 1: rnXclPattern = EXC_PATT_75_PERC; break;
456 case 2: rnXclPattern = EXC_PATT_50_PERC; break;
457 case 3: rnXclPattern = EXC_PATT_25_PERC; break;
462 ColorData XclExpPaletteImpl::GetColorData( sal_uInt16 nXclIndex ) const
464 if( nXclIndex >= EXC_COLOR_USEROFFSET )
466 sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
467 if( nIdx < maPalette.size() )
468 return maPalette[ nIdx ].maColor.GetColor();
470 return mrDefPal.GetDefColorData( nXclIndex );
473 bool XclExpPaletteImpl::IsDefaultPalette() const
475 bool bDefault = true;
476 for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
477 bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
478 return bDefault;
481 void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
483 rStrm << static_cast< sal_uInt16 >( maPalette.size() );
484 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
485 rStrm << aIt->maColor;
488 void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
490 if( !maPalette.size() )
491 return;
493 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
494 rStyleSheet->startElement( XML_colors, FSEND );
495 rStyleSheet->startElement( XML_indexedColors, FSEND );
496 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
497 rStyleSheet->singleElement( XML_rgbColor,
498 XML_rgb, XclXmlUtils::ToOString( aIt->maColor ).getStr(),
499 FSEND );
500 rStyleSheet->endElement( XML_indexedColors );
501 rStyleSheet->endElement( XML_colors );
504 const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
506 if( nColorId < maColorIdDataVec.size() )
507 return maColorIdDataVec[ nColorId ].maColor;
508 return maPalette[ 0 ].maColor;
511 XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
513 rnIndex = 0;
515 if (mxColorList->empty())
516 return NULL;
518 XclListColor* pEntry = NULL;
520 // search optimization for equal-colored objects occurring repeatedly
521 if (mnLastIdx < mxColorList->size())
523 pEntry = &(*mxColorList)[mnLastIdx];
524 if( pEntry->GetColor() == rColor )
526 rnIndex = mnLastIdx;
527 return pEntry;
531 // binary search for color
532 sal_uInt32 nBegIdx = 0;
533 sal_uInt32 nEndIdx = mxColorList->size();
534 bool bFound = false;
535 while( !bFound && (nBegIdx < nEndIdx) )
537 rnIndex = (nBegIdx + nEndIdx) / 2;
538 pEntry = &(*mxColorList)[rnIndex];
539 bFound = pEntry->GetColor() == rColor;
540 if( !bFound )
542 if( pEntry->GetColor().GetColor() < rColor.GetColor() )
543 nBegIdx = rnIndex + 1;
544 else
545 nEndIdx = rnIndex;
549 // not found - use end of range as new insertion position
550 if( !bFound )
551 rnIndex = nEndIdx;
553 mnLastIdx = rnIndex;
554 return pEntry;
557 XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
559 XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
560 XclListColorList::iterator itr = mxColorList->begin();
561 ::std::advance(itr, nIndex);
562 mxColorList->insert(itr, pEntry);
563 return pEntry;
566 void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
568 /* Fast palette reduction - in each call of this function one RGB component
569 of each color is reduced to a lower number of distinct values.
570 Pass 0: Blue is reduced to 128 distinct values.
571 Pass 1: Red is reduced to 128 distinct values.
572 Pass 2: Green is reduced to 128 distinct values.
573 Pass 3: Blue is reduced to 64 distinct values.
574 Pass 4: Red is reduced to 64 distinct values.
575 Pass 5: Green is reduced to 64 distinct values.
576 And so on...
579 XclListColorListRef xOldList = mxColorList;
580 mxColorList.reset( new XclListColorList );
582 // maps old list indexes to new list indexes, used to update maColorIdDataVec
583 ScfUInt32Vec aListIndexMap;
584 aListIndexMap.reserve( xOldList->size() );
586 // preparations
587 sal_uInt8 nR, nG, nB;
588 sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
589 nPass /= 3;
590 OSL_ENSURE( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
592 static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
593 sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
594 sal_uInt8 nFactor2 = spnFactor2[ nPass ];
595 sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
597 // process each color in the old color list
598 for( sal_uInt32 nIdx = 0, nCount = xOldList->size(); nIdx < nCount; ++nIdx )
600 // get the old list entry
601 const XclListColor* pOldEntry = &(xOldList->at( nIdx ));
602 nR = pOldEntry->GetColor().GetRed();
603 nG = pOldEntry->GetColor().GetGreen();
604 nB = pOldEntry->GetColor().GetBlue();
606 /* Calculate the new RGB component (rnComp points to one of nR, nG, nB).
607 Using integer arithmetic with its rounding errors, the results of
608 this calculation are always exactly in the range 0x00 to 0xFF
609 (simply cutting the lower bits would darken the colors slightly). */
610 sal_uInt32 nNewComp = rnComp;
611 nNewComp /= nFactor1;
612 nNewComp *= nFactor2;
613 nNewComp /= nFactor3;
614 rnComp = static_cast< sal_uInt8 >( nNewComp );
615 Color aNewColor( nR, nG, nB );
617 // find or insert the new color
618 sal_uInt32 nFoundIdx = 0;
619 XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
620 if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
621 pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
622 pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
623 aListIndexMap.push_back( nFoundIdx );
626 // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
627 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
628 aIt->mnIndex = aListIndexMap[ aIt->mnIndex ];
631 void XclExpPaletteImpl::ReduceLeastUsedColor()
633 // find a list color to remove
634 sal_uInt32 nRemove = GetLeastUsedListColor();
635 // find its nearest neighbor
636 sal_uInt32 nKeep = GetNearestListColor( nRemove );
638 // merge both colors to one color, remove one color from list
639 XclListColor* pKeepEntry = &mxColorList->at(nKeep);
640 XclListColor* pRemoveEntry = &mxColorList->at(nRemove);
641 if( pKeepEntry && pRemoveEntry )
643 // merge both colors (if pKeepEntry is a base color, it will not change)
644 pKeepEntry->Merge( *pRemoveEntry );
645 // remove the less used color, adjust nKeep index if kept color follows removed color
646 XclListColorList::iterator itr = mxColorList->begin();
647 ::std::advance(itr, nRemove);
648 mxColorList->erase(itr);
649 if( nKeep > nRemove ) --nKeep;
651 // recalculate color ID data map (maps color IDs to color list indexes)
652 for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
654 if( aIt->mnIndex > nRemove )
655 --aIt->mnIndex;
656 else if( aIt->mnIndex == nRemove )
657 aIt->mnIndex = nKeep;
662 sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
664 sal_uInt32 nFound = 0;
665 sal_uInt32 nMinW = SAL_MAX_UINT32;
667 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
669 XclListColor& pEntry = mxColorList->at( nIdx );
670 // ignore the base colors
671 if( !pEntry.IsBaseColor() && (pEntry.GetWeighting() < nMinW) )
673 nFound = nIdx;
674 nMinW = pEntry.GetWeighting();
677 return nFound;
680 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
682 sal_uInt32 nFound = 0;
683 sal_Int32 nMinD = SAL_MAX_INT32;
685 for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
687 if( nIdx != nIgnore )
689 if( XclListColor* pEntry = &mxColorList->at(nIdx) )
691 sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
692 if( nDist < nMinD )
694 nFound = nIdx;
695 nMinD = nDist;
700 return nFound;
703 sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
705 if (nIndex >= mxColorList->size())
706 return 0;
707 XclListColor* pEntry = &mxColorList->at(nIndex);
708 return GetNearestListColor( pEntry->GetColor(), nIndex );
711 sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
712 sal_uInt32& rnIndex, const Color& rColor, bool bDefaultOnly ) const
714 rnIndex = 0;
715 sal_Int32 nDist = SAL_MAX_INT32;
717 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
718 aIt != aEnd; ++aIt )
720 if( !bDefaultOnly || !aIt->mbUsed )
722 sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
723 if( nCurrDist < nDist )
725 rnIndex = aIt - maPalette.begin();
726 nDist = nCurrDist;
730 return nDist;
733 sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
734 sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
736 rnFirst = rnSecond = 0;
737 sal_Int32 nDist1 = SAL_MAX_INT32;
738 sal_Int32 nDist2 = SAL_MAX_INT32;
740 for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
741 aIt != aEnd; ++aIt )
743 sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
744 if( nCurrDist < nDist1 )
746 rnSecond = rnFirst;
747 nDist2 = nDist1;
748 rnFirst = aIt - maPalette.begin();
749 nDist1 = nCurrDist;
751 else if( nCurrDist < nDist2 )
753 rnSecond = aIt - maPalette.begin();
754 nDist2 = nCurrDist;
757 return nDist1;
760 XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
761 XclDefaultPalette( rRoot ),
762 XclExpRecord( EXC_ID_PALETTE )
764 mxImpl.reset( new XclExpPaletteImpl( *this ) );
765 SetRecSize( GetColorCount() * 4 + 2 );
768 XclExpPalette::~XclExpPalette()
772 sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
774 return mxImpl->InsertColor( rColor, eType, nAutoDefault );
777 sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
779 return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
782 void XclExpPalette::Finalize()
784 mxImpl->Finalize();
787 sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
789 return mxImpl->GetColorIndex( nColorId );
792 void XclExpPalette::GetMixedColors(
793 sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
794 sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
796 return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
799 ColorData XclExpPalette::GetColorData( sal_uInt16 nXclIndex ) const
801 return mxImpl->GetColorData( nXclIndex );
804 void XclExpPalette::Save( XclExpStream& rStrm )
806 if( !mxImpl->IsDefaultPalette() )
807 XclExpRecord::Save( rStrm );
810 void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
812 if( !mxImpl->IsDefaultPalette() )
813 mxImpl->SaveXml( rStrm );
816 void XclExpPalette::WriteBody( XclExpStream& rStrm )
818 mxImpl->WriteBody( rStrm );
821 // FONT record - font information =============================================
823 namespace {
825 typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
827 sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
828 const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
830 if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
831 if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
832 if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
833 return 0;
836 } // namespace
838 sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
840 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
842 /* #i17050# #i107170# We need to determine which font items are set in the
843 item set, and which script type we should prefer according to the
844 current language settings. */
846 static const WhichAndScript WAS_LATIN( ATTR_FONT, ::com::sun::star::i18n::ScriptType::LATIN );
847 static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, ::com::sun::star::i18n::ScriptType::ASIAN );
848 static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, ::com::sun::star::i18n::ScriptType::COMPLEX );
850 /* do not let a font from a parent style override an explicit
851 cell font. */
853 sal_Int16 nDefScript = rRoot.GetDefApiScript();
854 sal_Int16 nScript = 0;
855 const SfxItemSet* pCurrSet = &rItemSet;
857 while( (nScript == 0) && pCurrSet )
859 switch( nDefScript )
861 case ApiScriptType::LATIN:
862 nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
863 break;
864 case ApiScriptType::ASIAN:
865 nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
866 break;
867 case ApiScriptType::COMPLEX:
868 nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
869 break;
870 default:
871 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
872 nScript = ApiScriptType::LATIN;
874 pCurrSet = pCurrSet->GetParent();
877 if (nScript == 0)
878 nScript = nDefScript;
880 if (nScript == 0)
882 OSL_FAIL( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
883 nScript = ApiScriptType::LATIN;
886 return nScript;
889 vcl::Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
891 // if WEAK is passed, guess script type from existing items in the item set
892 if( nScript == css::i18n::ScriptType::WEAK )
893 nScript = GetFirstUsedScript( rRoot, rItemSet );
895 // convert to core script type constants
896 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
898 // fill the font object
899 vcl::Font aFont;
900 ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, 0, 0, 0, nScScript );
901 return aFont;
904 ScDxfFont XclExpFontHelper::GetDxfFontFromItemSet(const XclExpRoot& rRoot, const SfxItemSet& rItemSet)
906 sal_Int16 nScript = GetFirstUsedScript(rRoot, rItemSet);
908 // convert to core script type constants
909 SvtScriptType nScScript = SvtLanguageOptions::FromI18NToSvtScriptType(nScript);
910 return ScPatternAttr::GetDxfFont(rItemSet, nScScript);
913 bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
915 static const sal_uInt16 pnCommonIds[] = {
916 ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
917 ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
918 static const sal_uInt16 pnLatinIds[] = {
919 ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
920 static const sal_uInt16 pnAsianIds[] = {
921 ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
922 static const sal_uInt16 pnComplexIds[] = {
923 ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
925 bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
926 if( !bUsed )
928 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
929 // if WEAK is passed, guess script type from existing items in the item set
930 if( nScript == ApiScriptType::WEAK )
931 nScript = GetFirstUsedScript( rRoot, rItemSet );
932 // check the correct items
933 switch( nScript )
935 case ApiScriptType::LATIN: bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep ); break;
936 case ApiScriptType::ASIAN: bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep ); break;
937 case ApiScriptType::COMPLEX: bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep ); break;
938 default: OSL_FAIL( "XclExpFontHelper::CheckItems - unknown script type" );
941 return bUsed;
944 namespace {
946 sal_uInt32 lclCalcHash( const XclFontData& rFontData )
948 sal_uInt32 nHash = rFontData.maName.getLength();
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 XclExpFont::XclExpFont( const XclExpRoot& rRoot,
966 const XclFontData& rFontData, XclExpColorType eColorType ) :
967 XclExpRecord( EXC_ID2_FONT, 14 ),
968 XclExpRoot( rRoot ),
969 maData( rFontData )
971 // insert font color into palette
972 mnColorId = rRoot.GetPalette().InsertColor( rFontData.maColor, eColorType, EXC_COLOR_FONTAUTO );
973 // hash value for faster comparison
974 mnHash = lclCalcHash( maData );
975 // record size
976 sal_Int32 nStrLen = maData.maName.getLength();
977 SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
980 bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
982 return (mnHash == nHash) && (maData == rFontData);
985 void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
987 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
988 rStyleSheet->startElement( XML_font, FSEND );
989 XclXmlUtils::WriteFontData( rStyleSheet, maData, XML_name );
990 // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
991 rStyleSheet->endElement( XML_font );
994 // private --------------------------------------------------------------------
996 void XclExpFont::WriteBody( XclExpStream& rStrm )
998 sal_uInt16 nAttr = EXC_FONTATTR_NONE;
999 ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
1000 ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
1001 ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
1002 ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
1004 OSL_ENSURE( maData.maName.getLength() < 256, "XclExpFont::WriteBody - font name too long" );
1005 XclExpString aFontName;
1006 if( GetBiff() <= EXC_BIFF5 )
1007 aFontName.AssignByte( maData.maName, GetTextEncoding(), EXC_STR_8BITLENGTH );
1008 else
1009 aFontName.Assign( maData.maName, EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH );
1011 rStrm << maData.mnHeight
1012 << nAttr
1013 << GetPalette().GetColorIndex( mnColorId )
1014 << maData.mnWeight
1015 << maData.mnEscapem
1016 << maData.mnUnderline
1017 << maData.mnFamily
1018 << maData.mnCharSet
1019 << sal_uInt8( 0 )
1020 << aFontName;
1023 XclExpDxfFont::XclExpDxfFont(const XclExpRoot& rRoot,
1024 const SfxItemSet& rItemSet):
1025 XclExpRoot(rRoot)
1027 maDxfData = XclExpFontHelper::GetDxfFontFromItemSet(rRoot, rItemSet);
1030 namespace {
1032 const char* getUnderlineOOXValue(FontUnderline eUnderline)
1034 switch (eUnderline)
1036 case UNDERLINE_NONE:
1037 case UNDERLINE_DONTKNOW:
1038 return "none";
1039 case UNDERLINE_DOUBLE:
1040 case UNDERLINE_DOUBLEWAVE:
1041 return "double";
1042 default:
1043 return "single";
1047 const char* getFontFamilyOOXValue(FontFamily eValue)
1049 switch (eValue)
1051 case FAMILY_DONTKNOW:
1052 return "0";
1053 break;
1054 case FAMILY_SWISS:
1055 case FAMILY_SYSTEM:
1056 return "2";
1057 case FAMILY_ROMAN:
1058 return "1";
1059 case FAMILY_SCRIPT:
1060 return "4";
1061 case FAMILY_MODERN:
1062 return "3";
1063 case FAMILY_DECORATIVE:
1064 return "5";
1065 default:
1066 return "0";
1072 void XclExpDxfFont::SaveXml(XclExpXmlStream& rStrm)
1074 if (maDxfData.isEmpty())
1075 return;
1077 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1078 rStyleSheet->startElement(XML_font, FSEND);
1080 if (maDxfData.pFontAttr)
1082 OUString aFontName = (*maDxfData.pFontAttr)->GetFamilyName();
1084 aFontName = XclTools::GetXclFontName(aFontName);
1085 if (!aFontName.isEmpty())
1087 rStyleSheet->singleElement(XML_name,
1088 XML_val, XclXmlUtils::ToOString(aFontName).getStr(),
1089 FSEND);
1092 rtl_TextEncoding eTextEnc = (*maDxfData.pFontAttr)->GetCharSet();
1093 sal_uInt8 nExcelCharSet = rtl_getBestWindowsCharsetFromTextEncoding(eTextEnc);
1094 if (nExcelCharSet)
1096 rStyleSheet->singleElement(XML_charset,
1097 XML_val, OString::number(nExcelCharSet).getStr(),
1098 FSEND);
1101 FontFamily eFamily = (*maDxfData.pFontAttr)->GetFamily();
1102 const char* pVal = getFontFamilyOOXValue(eFamily);
1103 if (pVal)
1105 rStyleSheet->singleElement(XML_family,
1106 XML_val, pVal,
1107 FSEND);
1111 if (maDxfData.eWeight)
1113 rStyleSheet->singleElement(XML_b,
1114 XML_val, XclXmlUtils::ToPsz10(maDxfData.eWeight.get() != WEIGHT_NORMAL),
1115 FSEND);
1118 if (maDxfData.eItalic)
1120 bool bItalic = (maDxfData.eItalic.get() == ITALIC_OBLIQUE) || (maDxfData.eItalic.get() == ITALIC_NORMAL);
1121 rStyleSheet->singleElement(XML_i,
1122 XML_val, XclXmlUtils::ToPsz10(bItalic),
1123 FSEND);
1126 if (maDxfData.eStrike)
1128 bool bStrikeout =
1129 (maDxfData.eStrike.get() == STRIKEOUT_SINGLE) || (maDxfData.eStrike.get() == STRIKEOUT_DOUBLE) ||
1130 (maDxfData.eStrike.get() == STRIKEOUT_BOLD) || (maDxfData.eStrike.get() == STRIKEOUT_SLASH) ||
1131 (maDxfData.eStrike.get() == STRIKEOUT_X);
1133 rStyleSheet->singleElement(XML_strike,
1134 XML_val, XclXmlUtils::ToPsz10(bStrikeout),
1135 FSEND);
1138 if (maDxfData.bOutline)
1140 rStyleSheet->singleElement(XML_outline,
1141 XML_val, XclXmlUtils::ToPsz10(maDxfData.bOutline.get()),
1142 FSEND);
1145 if (maDxfData.bShadow)
1147 rStyleSheet->singleElement(XML_shadow,
1148 XML_val, XclXmlUtils::ToPsz10(maDxfData.bShadow.get()),
1149 FSEND);
1152 if (maDxfData.aColor)
1154 rStyleSheet->singleElement(XML_color,
1155 XML_rgb, XclXmlUtils::ToOString(maDxfData.aColor.get()).getStr(),
1156 FSEND);
1159 if (maDxfData.eUnder)
1161 const char* pVal = getUnderlineOOXValue(maDxfData.eUnder.get());
1162 rStyleSheet->singleElement(XML_u,
1163 XML_val, pVal,
1164 FSEND);
1167 rStyleSheet->endElement(XML_font);
1170 XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
1171 XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
1175 bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
1177 return false;
1180 void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
1182 // do nothing
1185 XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
1186 XclExpRoot( rRoot ),
1187 mnXclMaxSize( 0 )
1189 switch( GetBiff() )
1191 case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4; break;
1192 case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5; break;
1193 case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8; break;
1194 default: DBG_ERROR_BIFF();
1196 InitDefaultFonts();
1199 const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
1201 return maFontList.GetRecord( nXclFont ).get();
1204 const XclFontData& XclExpFontBuffer::GetAppFontData() const
1206 return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
1209 sal_uInt16 XclExpFontBuffer::Insert(
1210 const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
1212 if( bAppFont )
1214 XclExpFontRef xFont( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1215 maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
1216 // set width of '0' character for column width export
1217 SetCharWidth( xFont->GetFontData() );
1218 return EXC_FONT_APP;
1221 size_t nPos = Find( rFontData );
1222 if( nPos == EXC_FONTLIST_NOTFOUND )
1224 // not found in buffer - create new font
1225 size_t nSize = maFontList.GetSize();
1226 if( nSize < mnXclMaxSize )
1228 // possible to insert
1229 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
1230 nPos = nSize; // old size is last position now
1232 else
1234 // buffer is full - ignore new font, use default font
1235 nPos = EXC_FONT_APP;
1238 return static_cast< sal_uInt16 >( nPos );
1241 sal_uInt16 XclExpFontBuffer::Insert(
1242 const vcl::Font& rFont, XclExpColorType eColorType, bool bAppFont )
1244 return Insert( XclFontData( rFont ), eColorType, bAppFont );
1247 sal_uInt16 XclExpFontBuffer::Insert(
1248 const SvxFont& rFont, XclExpColorType eColorType, bool bAppFont )
1250 return Insert( XclFontData( rFont ), eColorType, bAppFont );
1253 sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
1254 sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
1256 // #i17050# script type now provided by caller
1257 vcl::Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
1258 return Insert( aFont, eColorType, bAppFont );
1261 void XclExpFontBuffer::Save( XclExpStream& rStrm )
1263 maFontList.Save( rStrm );
1266 void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
1268 if( maFontList.IsEmpty() )
1269 return;
1271 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1272 rStyleSheet->startElement( XML_fonts,
1273 XML_count, OString::number( maFontList.GetSize() ).getStr(),
1274 FSEND );
1276 maFontList.SaveXml( rStrm );
1278 rStyleSheet->endElement( XML_fonts );
1281 // private --------------------------------------------------------------------
1283 void XclExpFontBuffer::InitDefaultFonts()
1285 XclFontData aFontData;
1286 aFontData.maName = "Arial";
1287 aFontData.SetScFamily( FAMILY_DONTKNOW );
1288 aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
1289 aFontData.SetScHeight( 200 ); // 200 twips = 10 pt
1290 aFontData.SetScWeight( WEIGHT_NORMAL );
1292 switch( GetBiff() )
1294 case EXC_BIFF5:
1296 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1297 aFontData.SetScWeight( WEIGHT_BOLD );
1298 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1299 aFontData.SetScWeight( WEIGHT_NORMAL );
1300 aFontData.SetScPosture( ITALIC_NORMAL );
1301 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1302 aFontData.SetScWeight( WEIGHT_BOLD );
1303 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1304 // the blind font with index 4
1305 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1306 // already add the first user defined font (Excel does it too)
1307 aFontData.SetScWeight( WEIGHT_NORMAL );
1308 aFontData.SetScPosture( ITALIC_NONE );
1309 maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1311 break;
1312 case EXC_BIFF8:
1314 XclExpFontRef xFont( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
1315 maFontList.AppendRecord( xFont );
1316 maFontList.AppendRecord( xFont );
1317 maFontList.AppendRecord( xFont );
1318 maFontList.AppendRecord( xFont );
1319 if( GetOutput() == EXC_OUTPUT_BINARY )
1320 // the blind font with index 4
1321 maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
1323 break;
1324 default:
1325 DBG_ERROR_BIFF();
1329 size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
1331 sal_uInt32 nHash = lclCalcHash( rFontData );
1332 for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
1333 if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
1334 return nPos;
1335 return EXC_FONTLIST_NOTFOUND;
1338 // FORMAT record - number formats =============================================
1340 /** Predicate for search algorithm. */
1341 struct XclExpNumFmtPred
1343 sal_uLong mnScNumFmt;
1344 inline explicit XclExpNumFmtPred( sal_uLong nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
1345 inline bool operator()( const XclExpNumFmt& rFormat ) const
1346 { return rFormat.mnScNumFmt == mnScNumFmt; }
1349 void XclExpNumFmt::SaveXml( XclExpXmlStream& rStrm )
1351 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1352 rStyleSheet->singleElement( XML_numFmt,
1353 XML_numFmtId, OString::number( mnXclNumFmt ).getStr(),
1354 XML_formatCode, OUStringToOString(maNumFmtString, RTL_TEXTENCODING_UTF8).getStr(),
1355 FSEND );
1358 XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
1359 XclExpRoot( rRoot ),
1360 /* Compiler needs a hint, this doesn't work: new NfKeywordTable;
1361 cannot convert from 'class String *' to 'class String (*)[54]'
1362 The effective result here is class String (*)[54*1] */
1363 mxFormatter( new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ) ),
1364 mpKeywordTable( new NfKeywordTable ),
1365 mnStdFmt( GetFormatter().GetStandardFormat( ScGlobal::eLnge ) )
1367 switch( GetBiff() )
1369 case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5; break;
1370 case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8; break;
1371 default: mnXclOffset = 0; DBG_ERROR_BIFF();
1374 mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
1375 // remap codes unknown to Excel
1376 (*mpKeywordTable)[ NF_KEY_NN ] = "DDD";
1377 (*mpKeywordTable)[ NF_KEY_NNN ] = "DDDD";
1378 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
1379 (*mpKeywordTable)[ NF_KEY_NNNN ] = "DDDD";
1380 // Export the Thai T NatNum modifier.
1381 (*mpKeywordTable)[ NF_KEY_THAI_T ] = "T";
1384 XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
1388 sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uLong nScNumFmt )
1390 XclExpNumFmtVec::const_iterator aIt =
1391 ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
1392 if( aIt != maFormatMap.end() )
1393 return aIt->mnXclNumFmt;
1395 size_t nSize = maFormatMap.size();
1396 if( nSize < static_cast< size_t >( 0xFFFF - mnXclOffset ) )
1398 sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
1399 maFormatMap.push_back( XclExpNumFmt( nScNumFmt, nXclNumFmt, GetFormatCode( nScNumFmt ) ) );
1400 return nXclNumFmt;
1403 return 0;
1406 void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
1408 for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1409 WriteFormatRecord( rStrm, *aIt );
1412 void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
1414 if( !maFormatMap.size() )
1415 return;
1417 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1418 rStyleSheet->startElement( XML_numFmts,
1419 XML_count, OString::number( maFormatMap.size() ).getStr(),
1420 FSEND );
1421 for( XclExpNumFmtVec::iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
1423 aIt->SaveXml( rStrm );
1425 rStyleSheet->endElement( XML_numFmts );
1428 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const OUString& rFormatStr )
1430 XclExpString aExpStr;
1431 if( GetBiff() <= EXC_BIFF5 )
1432 aExpStr.AssignByte( rFormatStr, GetTextEncoding(), EXC_STR_8BITLENGTH );
1433 else
1434 aExpStr.Assign( rFormatStr );
1436 rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
1437 rStrm << nXclNumFmt << aExpStr;
1438 rStrm.EndRecord();
1441 void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
1443 WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat.mnScNumFmt ) );
1446 namespace {
1448 OUString GetNumberFormatCode(XclRoot& rRoot, const sal_uInt16 nScNumFmt, SvNumberFormatter* xFormatter, NfKeywordTable* pKeywordTable)
1450 OUString aFormatStr;
1452 if( const SvNumberformat* pEntry = rRoot.GetFormatter().GetEntry( nScNumFmt ) )
1454 if( pEntry->GetType() == css::util::NumberFormat::LOGICAL )
1456 // build Boolean number format
1457 Color* pColor = 0;
1458 OUString aTemp;
1459 const_cast< SvNumberformat* >( pEntry )->GetOutputString( 1.0, aTemp, &pColor );
1460 aFormatStr += "\"" + aTemp + "\";\"" + aTemp + "\";\"";
1461 const_cast< SvNumberformat* >( pEntry )->GetOutputString( 0.0, aTemp, &pColor );
1462 aFormatStr += aTemp + "\"";
1464 else
1466 LanguageType eLang = pEntry->GetLanguage();
1467 if( eLang != LANGUAGE_ENGLISH_US )
1469 sal_Int32 nCheckPos;
1470 short nType = css::util::NumberFormat::DEFINED;
1471 sal_uInt32 nKey;
1472 OUString aTemp( pEntry->GetFormatstring() );
1473 xFormatter->PutandConvertEntry( aTemp, nCheckPos, nType, nKey, eLang, LANGUAGE_ENGLISH_US );
1474 OSL_ENSURE( nCheckPos == 0, "XclExpNumFmtBuffer::WriteFormatRecord - format code not convertible" );
1475 pEntry = xFormatter->GetEntry( nKey );
1478 aFormatStr = pEntry->GetMappedFormatstring( *pKeywordTable, *xFormatter->GetLocaleData() );
1479 if( aFormatStr == "Standard" )
1480 aFormatStr = "General";
1483 else
1485 OSL_FAIL( "XclExpNumFmtBuffer::WriteFormatRecord - format not found" );
1486 aFormatStr = "General";
1489 return aFormatStr;
1494 OUString XclExpNumFmtBuffer::GetFormatCode( sal_uInt16 nScNumFmt )
1496 return GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() );
1499 // XF, STYLE record - Cell formatting =========================================
1501 bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
1503 const ScProtectionAttr& rProtItem = GETITEM( rItemSet, ScProtectionAttr, ATTR_PROTECTION );
1504 mbLocked = rProtItem.GetProtection();
1505 mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
1506 return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
1509 void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
1511 ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
1512 ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
1515 void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
1517 rStrm.GetCurrentStream()->singleElement( XML_protection,
1518 XML_locked, XclXmlUtils::ToPsz( mbLocked ),
1519 XML_hidden, XclXmlUtils::ToPsz( mbHidden ),
1520 FSEND );
1523 bool XclExpCellAlign::FillFromItemSet(
1524 const SfxItemSet& rItemSet, bool bForceLineBreak, XclBiff eBiff, bool bStyle )
1526 bool bUsed = false;
1527 SvxCellHorJustify eHorAlign = GETITEMVALUE( rItemSet, SvxHorJustifyItem, ATTR_HOR_JUSTIFY, SvxCellHorJustify );
1528 SvxCellVerJustify eVerAlign = GETITEMVALUE( rItemSet, SvxVerJustifyItem, ATTR_VER_JUSTIFY, SvxCellVerJustify );
1530 switch( eBiff )
1532 // ALL 'case's - run through!
1534 case EXC_BIFF8: // attributes new in BIFF8
1536 // text indent
1537 long nTmpIndent = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_INDENT, sal_Int32 );
1538 (nTmpIndent += 100) /= 200; // 1 Excel unit == 10 pt == 200 twips
1539 mnIndent = limit_cast< sal_uInt8 >( nTmpIndent, 0, 15 );
1540 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
1542 // shrink to fit
1543 mbShrink = GETITEM( rItemSet, SfxBoolItem, ATTR_SHRINKTOFIT ).GetValue();
1544 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
1546 // CTL text direction
1547 SetScFrameDir( GETITEMVALUE( rItemSet, SvxFrameDirectionItem, ATTR_WRITINGDIR, SvxFrameDirection ) );
1548 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
1551 case EXC_BIFF5: // attributes new in BIFF5
1552 case EXC_BIFF4: // attributes new in BIFF4
1554 // vertical alignment
1555 SetScVerAlign( eVerAlign );
1556 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
1558 // stacked/rotation
1559 bool bStacked = GETITEM( rItemSet, SfxBoolItem, ATTR_STACKED ).GetValue();
1560 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
1561 if( bStacked )
1563 mnRotation = EXC_ROT_STACKED;
1565 else
1567 // rotation
1568 sal_Int32 nScRot = GETITEMVALUE( rItemSet, SfxInt32Item, ATTR_ROTATE_VALUE, sal_Int32 );
1569 mnRotation = XclTools::GetXclRotation( nScRot );
1570 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
1572 mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
1575 case EXC_BIFF3: // attributes new in BIFF3
1577 // text wrap
1578 mbLineBreak = bForceLineBreak || GETITEMBOOL( rItemSet, ATTR_LINEBREAK );
1579 bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
1582 case EXC_BIFF2: // attributes new in BIFF2
1584 // horizontal alignment
1585 SetScHorAlign( eHorAlign );
1586 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
1589 break;
1590 default: DBG_ERROR_BIFF();
1593 if (eBiff == EXC_BIFF8)
1595 // Adjust for distributed alignments.
1596 if (eHorAlign == SVX_HOR_JUSTIFY_BLOCK)
1598 SvxCellJustifyMethod eHorJustMethod = GETITEMVALUE(
1599 rItemSet, SvxJustifyMethodItem, ATTR_HOR_JUSTIFY_METHOD, SvxCellJustifyMethod);
1600 if (eHorJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
1601 mnHorAlign = EXC_XF_HOR_DISTRIB;
1604 if (eVerAlign == SVX_VER_JUSTIFY_BLOCK)
1606 SvxCellJustifyMethod eVerJustMethod = GETITEMVALUE(
1607 rItemSet, SvxJustifyMethodItem, ATTR_VER_JUSTIFY_METHOD, SvxCellJustifyMethod);
1608 if (eVerJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
1609 mnVerAlign = EXC_XF_VER_DISTRIB;
1613 return bUsed;
1616 void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
1618 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1619 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1620 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1621 ::insert_value( rnAlign, mnOrient, 8, 2 );
1624 void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
1626 ::insert_value( rnAlign, mnHorAlign, 0, 3 );
1627 ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
1628 ::insert_value( rnAlign, mnVerAlign, 4, 3 );
1629 ::insert_value( rnAlign, mnRotation, 8, 8 );
1630 ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
1631 ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
1632 ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
1635 static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
1637 switch( nHorAlign )
1639 case EXC_XF_HOR_GENERAL: return "general";
1640 case EXC_XF_HOR_LEFT: return "left";
1641 case EXC_XF_HOR_CENTER: return "center";
1642 case EXC_XF_HOR_RIGHT: return "right";
1643 case EXC_XF_HOR_FILL: return "fill";
1644 case EXC_XF_HOR_JUSTIFY: return "justify";
1645 case EXC_XF_HOR_CENTER_AS: return "centerContinuous";
1646 case EXC_XF_HOR_DISTRIB: return "distributed";
1648 return "*unknown*";
1651 static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
1653 switch( nVerAlign )
1655 case EXC_XF_VER_TOP: return "top";
1656 case EXC_XF_VER_CENTER: return "center";
1657 case EXC_XF_VER_BOTTOM: return "bottom";
1658 case EXC_XF_VER_JUSTIFY: return "justify";
1659 case EXC_XF_VER_DISTRIB: return "distributed";
1661 return "*unknown*";
1664 void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
1666 rStrm.GetCurrentStream()->singleElement( XML_alignment,
1667 XML_horizontal, ToHorizontalAlignment( mnHorAlign ),
1668 XML_vertical, ToVerticalAlignment( mnVerAlign ),
1669 XML_textRotation, OString::number( mnRotation ).getStr(),
1670 XML_wrapText, XclXmlUtils::ToPsz( mbLineBreak ),
1671 XML_indent, OString::number( mnIndent ).getStr(),
1672 // OOXTODO: XML_relativeIndent, mnIndent?
1673 // OOXTODO: XML_justifyLastLine,
1674 XML_shrinkToFit, XclXmlUtils::ToPsz( mbShrink ),
1675 // OOXTODO: XML_readingOrder,
1676 FSEND );
1679 namespace {
1681 void lclGetBorderLine(
1682 sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
1683 const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
1685 rnXclLine = EXC_LINE_NONE;
1686 if( pLine )
1688 sal_uInt16 nOuterWidth = pLine->GetOutWidth();
1689 sal_uInt16 nDistance = pLine->GetDistance();
1690 if( nDistance > 0 )
1691 rnXclLine = EXC_LINE_DOUBLE;
1692 else if( nOuterWidth >= EXC_BORDER_THICK )
1693 rnXclLine = EXC_LINE_THICK;
1694 else if( nOuterWidth >= EXC_BORDER_MEDIUM )
1696 rnXclLine = EXC_LINE_MEDIUM;
1697 switch (pLine->GetBorderLineStyle())
1699 case table::BorderLineStyle::DASHED:
1700 rnXclLine = EXC_LINE_MEDIUM_DASHED;
1701 break;
1702 case table::BorderLineStyle::DASH_DOT:
1703 rnXclLine = EXC_LINE_MEDIUM_DASHDOT;
1704 break;
1705 case table::BorderLineStyle::DASH_DOT_DOT:
1706 rnXclLine = EXC_LINE_MEDIUM_DASHDOTDOT;
1707 break;
1708 default:
1712 else if( nOuterWidth >= EXC_BORDER_THIN )
1714 rnXclLine = EXC_LINE_THIN;
1715 switch (pLine->GetBorderLineStyle())
1717 case table::BorderLineStyle::DASHED:
1718 case table::BorderLineStyle::FINE_DASHED:
1719 rnXclLine = EXC_LINE_DASHED;
1720 break;
1721 case table::BorderLineStyle::DASH_DOT:
1722 rnXclLine = EXC_LINE_THIN_DASHDOT;
1723 break;
1724 case table::BorderLineStyle::DASH_DOT_DOT:
1725 rnXclLine = EXC_LINE_THIN_DASHDOTDOT;
1726 break;
1727 case table::BorderLineStyle::DOTTED:
1728 rnXclLine = EXC_LINE_DOTTED;
1729 break;
1730 default:
1731 break;
1734 else if (nOuterWidth >= EXC_BORDER_HAIR)
1735 rnXclLine = EXC_LINE_HAIR;
1736 else
1737 rnXclLine = EXC_LINE_NONE;
1739 if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
1740 rnXclLine = EXC_LINE_THIN;
1742 rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
1743 rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
1744 XclExpPalette::GetColorIdFromIndex( 0 );
1747 } // namespace
1749 XclExpCellBorder::XclExpCellBorder() :
1750 mnLeftColorId( XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
1751 mnRightColorId( XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
1752 mnTopColorId( XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
1753 mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
1754 mnDiagColorId( XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
1758 bool XclExpCellBorder::FillFromItemSet(
1759 const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
1761 bool bUsed = false;
1763 switch( eBiff )
1765 // ALL 'case's - run through!
1767 case EXC_BIFF8: // attributes new in BIFF8
1769 const SvxLineItem& rTLBRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_TLBR );
1770 sal_uInt8 nTLBRLine;
1771 sal_uInt32 nTLBRColorId;
1772 lclGetBorderLine( nTLBRLine, nTLBRColorId, rTLBRItem.GetLine(), rPalette, eBiff );
1773 mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
1775 const SvxLineItem& rBLTRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_BLTR );
1776 sal_uInt8 nBLTRLine;
1777 sal_uInt32 nBLTRColorId;
1778 lclGetBorderLine( nBLTRLine, nBLTRColorId, rBLTRItem.GetLine(), rPalette, eBiff );
1779 mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
1781 if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
1783 mnDiagLine = nTLBRLine;
1784 mnDiagColorId = nTLBRColorId;
1786 else
1788 mnDiagLine = nBLTRLine;
1789 mnDiagColorId = nBLTRColorId;
1792 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
1793 ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
1796 case EXC_BIFF5:
1797 case EXC_BIFF4:
1798 case EXC_BIFF3:
1799 case EXC_BIFF2:
1801 const SvxBoxItem& rBoxItem = GETITEM( rItemSet, SvxBoxItem, ATTR_BORDER );
1802 lclGetBorderLine( mnLeftLine, mnLeftColorId, rBoxItem.GetLeft(), rPalette, eBiff );
1803 lclGetBorderLine( mnRightLine, mnRightColorId, rBoxItem.GetRight(), rPalette, eBiff );
1804 lclGetBorderLine( mnTopLine, mnTopColorId, rBoxItem.GetTop(), rPalette, eBiff );
1805 lclGetBorderLine( mnBottomLine, mnBottomColorId, rBoxItem.GetBottom(), rPalette, eBiff );
1806 bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
1809 break;
1810 default: DBG_ERROR_BIFF();
1813 return bUsed;
1816 void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
1818 mnLeftColor = rPalette.GetColorIndex( mnLeftColorId );
1819 mnRightColor = rPalette.GetColorIndex( mnRightColorId );
1820 mnTopColor = rPalette.GetColorIndex( mnTopColorId );
1821 mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
1822 mnDiagColor = rPalette.GetColorIndex( mnDiagColorId );
1825 void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
1827 ::insert_value( rnBorder, mnTopLine, 0, 3 );
1828 ::insert_value( rnBorder, mnLeftLine, 3, 3 );
1829 ::insert_value( rnArea, mnBottomLine, 22, 3 );
1830 ::insert_value( rnBorder, mnRightLine, 6, 3 );
1831 ::insert_value( rnBorder, mnTopColor, 9, 7 );
1832 ::insert_value( rnBorder, mnLeftColor, 16, 7 );
1833 ::insert_value( rnArea, mnBottomColor, 25, 7 );
1834 ::insert_value( rnBorder, mnRightColor, 23, 7 );
1837 void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
1839 ::insert_value( rnBorder1, mnLeftLine, 0, 4 );
1840 ::insert_value( rnBorder1, mnRightLine, 4, 4 );
1841 ::insert_value( rnBorder1, mnTopLine, 8, 4 );
1842 ::insert_value( rnBorder1, mnBottomLine, 12, 4 );
1843 ::insert_value( rnBorder1, mnLeftColor, 16, 7 );
1844 ::insert_value( rnBorder1, mnRightColor, 23, 7 );
1845 ::insert_value( rnBorder2, mnTopColor, 0, 7 );
1846 ::insert_value( rnBorder2, mnBottomColor, 7, 7 );
1847 ::insert_value( rnBorder2, mnDiagColor, 14, 7 );
1848 ::insert_value( rnBorder2, mnDiagLine, 21, 4 );
1849 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
1850 ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
1853 void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
1855 ::insert_value( rnLine, mnLeftLine, 0, 4 );
1856 ::insert_value( rnLine, mnRightLine, 4, 4 );
1857 ::insert_value( rnLine, mnTopLine, 8, 4 );
1858 ::insert_value( rnLine, mnBottomLine, 12, 4 );
1859 ::insert_value( rnColor, mnLeftColor, 0, 7 );
1860 ::insert_value( rnColor, mnRightColor, 7, 7 );
1861 ::insert_value( rnColor, mnTopColor, 16, 7 );
1862 ::insert_value( rnColor, mnBottomColor, 23, 7 );
1865 static const char* ToLineStyle( sal_uInt8 nLineStyle )
1867 switch( nLineStyle )
1869 case EXC_LINE_NONE: return "none";
1870 case EXC_LINE_THIN: return "thin";
1871 case EXC_LINE_MEDIUM: return "medium";
1872 case EXC_LINE_THICK: return "thick";
1873 case EXC_LINE_DOUBLE: return "double";
1874 case EXC_LINE_HAIR: return "hair";
1875 case EXC_LINE_DOTTED: return "dotted";
1876 case EXC_LINE_DASHED: return "dashed";
1877 case EXC_LINE_MEDIUM_DASHED: return "mediumDashed";
1878 case EXC_LINE_THIN_DASHDOT: return "dashDot";
1879 case EXC_LINE_THIN_DASHDOTDOT: return "dashDotDot";
1880 case EXC_LINE_MEDIUM_DASHDOT: return "mediumDashDot";
1881 case EXC_LINE_MEDIUM_DASHDOTDOT: return "mediumDashDotDot";
1883 return "*unknown*";
1886 static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
1888 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1889 if( nLineStyle == EXC_LINE_NONE )
1890 rStyleSheet->singleElement( nElement, FSEND );
1891 else if( rColor == Color( 0, 0, 0, 0 ) )
1892 rStyleSheet->singleElement( nElement,
1893 XML_style, ToLineStyle( nLineStyle ),
1894 FSEND );
1895 else
1897 rStyleSheet->startElement( nElement,
1898 XML_style, ToLineStyle( nLineStyle ),
1899 FSEND );
1900 rStyleSheet->singleElement( XML_color,
1901 XML_rgb, XclXmlUtils::ToOString( rColor ).getStr(),
1902 FSEND );
1903 rStyleSheet->endElement( nElement );
1907 void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
1909 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
1911 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
1913 rStyleSheet->startElement( XML_border,
1914 XML_diagonalUp, XclXmlUtils::ToPsz( mbDiagBLtoTR ),
1915 XML_diagonalDown, XclXmlUtils::ToPsz( mbDiagTLtoBR ),
1916 // OOXTODO: XML_outline,
1917 FSEND );
1918 lcl_WriteBorder( rStrm, XML_left, mnLeftLine, rPalette.GetColor( mnLeftColor ) );
1919 lcl_WriteBorder( rStrm, XML_right, mnRightLine, rPalette.GetColor( mnRightColor ) );
1920 lcl_WriteBorder( rStrm, XML_top, mnTopLine, rPalette.GetColor( mnTopColor ) );
1921 lcl_WriteBorder( rStrm, XML_bottom, mnBottomLine, rPalette.GetColor( mnBottomColor ) );
1922 lcl_WriteBorder( rStrm, XML_diagonal, mnDiagLine, rPalette.GetColor( mnDiagColor ) );
1923 // OOXTODO: XML_vertical, XML_horizontal
1924 rStyleSheet->endElement( XML_border );
1927 XclExpCellArea::XclExpCellArea() :
1928 mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
1929 mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) )
1933 bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
1935 const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
1936 if( rBrushItem.GetColor().GetTransparency() )
1938 mnPattern = EXC_PATT_NONE;
1939 mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1940 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
1942 else
1944 mnPattern = EXC_PATT_SOLID;
1945 mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
1946 mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
1948 return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
1951 void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
1953 rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
1956 void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
1958 ::insert_value( rnArea, mnPattern, 16, 6 );
1959 ::insert_value( rnArea, mnForeColor, 0, 7 );
1960 ::insert_value( rnArea, mnBackColor, 7, 7 );
1963 void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
1965 ::insert_value( rnBorder2, mnPattern, 26, 6 );
1966 ::insert_value( rnArea, mnForeColor, 0, 7 );
1967 ::insert_value( rnArea, mnBackColor, 7, 7 );
1970 void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
1972 XclCellArea aTmp( *this );
1973 if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
1974 aTmp.mnBackColor = 0;
1975 if( aTmp.mnPattern == EXC_PATT_SOLID )
1976 ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
1977 ::insert_value( rnColor, aTmp.mnForeColor, 0, 7 );
1978 ::insert_value( rnColor, aTmp.mnBackColor, 7, 7 );
1979 ::insert_value( rnPattern, aTmp.mnPattern, 10, 6 );
1982 static const char* ToPatternType( sal_uInt8 nPattern )
1984 switch( nPattern )
1986 case EXC_PATT_NONE: return "none";
1987 case EXC_PATT_SOLID: return "solid";
1988 case EXC_PATT_50_PERC: return "mediumGray";
1989 case EXC_PATT_75_PERC: return "darkGray";
1990 case EXC_PATT_25_PERC: return "lightGray";
1991 case EXC_PATT_12_5_PERC: return "gray125";
1992 case EXC_PATT_6_25_PERC: return "gray0625";
1994 return "*unknown*";
1997 void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
1999 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2000 rStyleSheet->startElement( XML_fill,
2001 FSEND );
2003 // OOXTODO: XML_gradientFill
2005 XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
2007 if( mnPattern == EXC_PATT_NONE || ( mnForeColor == 0 && mnBackColor == 0 ) )
2008 rStyleSheet->singleElement( XML_patternFill,
2009 XML_patternType, ToPatternType( mnPattern ),
2010 FSEND );
2011 else
2013 rStyleSheet->startElement( XML_patternFill,
2014 XML_patternType, ToPatternType( mnPattern ),
2015 FSEND );
2016 rStyleSheet->singleElement( XML_fgColor,
2017 XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnForeColor ) ).getStr(),
2018 FSEND );
2019 rStyleSheet->singleElement( XML_bgColor,
2020 XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnBackColor ) ).getStr(),
2021 FSEND );
2022 rStyleSheet->endElement( XML_patternFill );
2025 rStyleSheet->endElement( XML_fill );
2028 bool XclExpColor::FillFromItemSet( const SfxItemSet& rItemSet )
2030 if( !ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true ) )
2031 return false;
2033 const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
2034 maColor = rBrushItem.GetColor();
2036 return true;
2039 void XclExpColor::SaveXml( XclExpXmlStream& rStrm ) const
2041 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2042 rStyleSheet->startElement( XML_fill,
2043 FSEND );
2044 rStyleSheet->startElement( XML_patternFill,
2045 FSEND );
2046 rStyleSheet->singleElement( XML_bgColor,
2047 XML_rgb, XclXmlUtils::ToOString(maColor).getStr(),
2048 FSEND );
2050 rStyleSheet->endElement( XML_patternFill );
2051 rStyleSheet->endElement( XML_fill );
2054 XclExpXFId::XclExpXFId() :
2055 mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
2056 mnXFIndex( EXC_XF_DEFAULTCELL )
2060 XclExpXFId::XclExpXFId( sal_uInt32 nXFId ) :
2061 mnXFId( nXFId ),
2062 mnXFIndex( EXC_XF_DEFAULTCELL )
2066 void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
2068 mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
2071 XclExpXF::XclExpXF(
2072 const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
2073 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) :
2074 XclXFBase( true ),
2075 XclExpRoot( rRoot )
2077 mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
2078 Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
2081 XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
2082 XclXFBase( false ),
2083 XclExpRoot( rRoot ),
2084 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2086 bool bDefStyle = (rStyleSheet.GetName() == ScGlobal::GetRscString( STR_STYLENAME_STANDARD ));
2087 sal_Int16 nScript = bDefStyle ? GetDefApiScript() : ::com::sun::star::i18n::ScriptType::WEAK;
2088 Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
2089 NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
2092 XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
2093 XclXFBase( bCellXF ),
2094 XclExpRoot( rRoot ),
2095 mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
2097 InitDefault();
2100 bool XclExpXF::Equals( const ScPatternAttr& rPattern,
2101 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2103 return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
2104 (!bForceLineBreak || maAlignment.mbLineBreak) &&
2105 ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
2106 ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
2109 bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
2111 return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
2114 void XclExpXF::SetFinalColors()
2116 maBorder.SetFinalColors( GetPalette() );
2117 maArea.SetFinalColors( GetPalette() );
2120 bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
2122 return XclXFBase::Equals( rCmpXF ) &&
2123 (maProtection == rCmpXF.maProtection) && (maAlignment == rCmpXF.maAlignment) &&
2124 (maBorder == rCmpXF.maBorder) && (maArea == rCmpXF.maArea) &&
2125 (mnXclFont == rCmpXF.mnXclFont) && (mnXclNumFmt == rCmpXF.mnXclNumFmt) &&
2126 (mnParentXFId == rCmpXF.mnParentXFId);
2129 void XclExpXF::InitDefault()
2131 SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
2132 mpItemSet = 0;
2133 mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
2134 mnXclFont = mnXclNumFmt = 0;
2135 SetXmlIds(0, 0);
2138 void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
2139 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
2141 InitDefault();
2142 mpItemSet = &rItemSet;
2144 // cell protection
2145 mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
2147 // font
2148 if( nForceXclFont == EXC_FONT_NOTFOUND )
2150 mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
2151 mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
2153 else
2155 mnXclFont = nForceXclFont;
2156 mbFontUsed = true;
2159 // number format
2160 mnScNumFmt = (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) ?
2161 GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) : nForceScNumFmt;
2162 mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
2163 mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
2164 // alignment
2165 mbAlignUsed = maAlignment.FillFromItemSet( rItemSet, bForceLineBreak, GetBiff(), IsStyleXF() );
2167 // cell border
2168 mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
2170 // background area
2171 mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
2173 // set all b***Used flags to true in "Default"/"Normal" style
2174 if( bDefStyle )
2175 SetAllUsedFlags( true );
2178 sal_uInt8 XclExpXF::GetUsedFlags() const
2180 sal_uInt8 nUsedFlags = 0;
2181 /* In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
2182 "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
2183 ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT, mbCellXF == mbProtUsed );
2184 ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT, mbCellXF == mbFontUsed );
2185 ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
2186 ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN, mbCellXF == mbAlignUsed );
2187 ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
2188 ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA, mbCellXF == mbAreaUsed );
2189 return nUsedFlags;
2192 void XclExpXF::WriteBody5( XclExpStream& rStrm )
2194 sal_uInt16 nTypeProt = 0, nAlign = 0;
2195 sal_uInt32 nArea = 0, nBorder = 0;
2197 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2198 ::insert_value( nTypeProt, mnParent, 4, 12 );
2199 ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
2201 maProtection.FillToXF3( nTypeProt );
2202 maAlignment.FillToXF5( nAlign );
2203 maBorder.FillToXF5( nBorder, nArea );
2204 maArea.FillToXF5( nArea );
2206 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
2209 void XclExpXF::WriteBody8( XclExpStream& rStrm )
2211 sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
2212 sal_uInt32 nBorder1 = 0, nBorder2 = 0;
2214 ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
2215 ::insert_value( nTypeProt, mnParent, 4, 12 );
2216 ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
2218 maProtection.FillToXF3( nTypeProt );
2219 maAlignment.FillToXF8( nAlign, nMiscAttrib );
2220 maBorder.FillToXF8( nBorder1, nBorder2 );
2221 maArea.FillToXF8( nBorder2, nArea );
2223 rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
2226 void XclExpXF::WriteBody( XclExpStream& rStrm )
2228 XclExpXFId aParentId( mnParentXFId );
2229 aParentId.ConvertXFIndex( GetRoot() );
2230 mnParent = aParentId.mnXFIndex;
2231 switch( GetBiff() )
2233 case EXC_BIFF5: WriteBody5( rStrm ); break;
2234 case EXC_BIFF8: WriteBody8( rStrm ); break;
2235 default: DBG_ERROR_BIFF();
2239 void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
2241 mnBorderId = nBorderId;
2242 mnFillId = nFillId;
2245 void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
2247 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2249 sal_Int32 nXfId = 0;
2250 const XclExpXF* pStyleXF = NULL;
2251 if( IsCellXF() )
2253 sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
2254 nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
2255 pStyleXF = rStrm.GetRoot().GetXFBuffer().GetXFById( mnParentXFId );
2258 rStyleSheet->startElement( XML_xf,
2259 XML_numFmtId, OString::number( mnXclNumFmt ).getStr(),
2260 XML_fontId, OString::number( mnXclFont ).getStr(),
2261 XML_fillId, OString::number( mnFillId ).getStr(),
2262 XML_borderId, OString::number( mnBorderId ).getStr(),
2263 XML_xfId, IsStyleXF() ? NULL : OString::number( nXfId ).getStr(),
2264 // OOXTODO: XML_quotePrefix,
2265 // OOXTODO: XML_pivotButton,
2266 // OOXTODO: XML_applyNumberFormat, ;
2267 XML_applyFont, XclXmlUtils::ToPsz( mbFontUsed ),
2268 // OOXTODO: XML_applyFill,
2269 XML_applyBorder, XclXmlUtils::ToPsz( mbBorderUsed ),
2270 XML_applyAlignment, XclXmlUtils::ToPsz( mbAlignUsed ),
2271 XML_applyProtection, XclXmlUtils::ToPsz( mbProtUsed ),
2272 FSEND );
2273 if( mbAlignUsed )
2274 maAlignment.SaveXml( rStrm );
2275 else if ( pStyleXF )
2276 pStyleXF->GetAlignmentData().SaveXml( rStrm );
2277 if( mbProtUsed )
2278 maProtection.SaveXml( rStrm );
2279 else if ( pStyleXF )
2280 pStyleXF->GetProtectionData().SaveXml( rStrm );
2282 // OOXTODO: XML_extLst
2283 rStyleSheet->endElement( XML_xf );
2286 XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
2287 XclExpXF( rRoot, bCellXF )
2291 void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
2293 mnXclFont = nXclFont;
2294 mbFontUsed = true;
2297 void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
2299 mnXclNumFmt = nXclNumFmt;
2300 mbFmtUsed = true;
2303 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, const OUString& rStyleName ) :
2304 XclExpRecord( EXC_ID_STYLE, 4 ),
2305 maName( rStyleName ),
2306 maXFId( nXFId ),
2307 mnStyleId( EXC_STYLE_USERDEF ),
2308 mnLevel( EXC_STYLE_NOLEVEL )
2310 OSL_ENSURE( !maName.isEmpty(), "XclExpStyle::XclExpStyle - empty style name" );
2311 #if OSL_DEBUG_LEVEL > 0
2312 sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
2313 OSL_ENSURE( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
2314 "XclExpStyle::XclExpStyle - this is a built-in style" );
2315 #endif
2318 XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
2319 XclExpRecord( EXC_ID_STYLE, 4 ),
2320 maXFId( nXFId ),
2321 mnStyleId( nStyleId ),
2322 mnLevel( nLevel )
2326 void XclExpStyle::WriteBody( XclExpStream& rStrm )
2328 maXFId.ConvertXFIndex( rStrm.GetRoot() );
2329 ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
2330 rStrm << maXFId.mnXFIndex;
2332 if( IsBuiltIn() )
2334 rStrm << mnStyleId << mnLevel;
2336 else
2338 XclExpString aNameEx;
2339 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
2340 aNameEx.Assign( maName );
2341 else
2342 aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), EXC_STR_8BITLENGTH );
2343 rStrm << aNameEx;
2347 static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
2349 switch( nStyleId )
2351 case 0: return "Normal";
2352 case 3: return "Comma";
2353 case 4: return "Currency";
2354 case 5: return "Percent";
2355 case 6: return "Comma [0]";
2356 case 7: return "Currency [0]";
2358 return "*unknown*";
2361 void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
2363 OString sName;
2364 if( IsBuiltIn() )
2366 sName = OString( lcl_StyleNameFromId( mnStyleId ) );
2368 else
2369 sName = XclXmlUtils::ToOString( maName );
2370 // get the index in sortedlist associated with the mnXId
2371 sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXFIndex( maXFId.mnXFId );
2372 // get the style index associated with index into sortedlist
2373 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFId );
2374 rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
2375 XML_name, sName.getStr(),
2376 XML_xfId, OString::number( nXFId ).getStr(),
2377 // builtinId of 54 or above is invalid according to OpenXML SDK validator.
2378 #define CELL_STYLE_MAX_BUILTIN_ID 54
2379 XML_builtinId, OString::number( std::min( static_cast<sal_Int32>( CELL_STYLE_MAX_BUILTIN_ID - 1 ), static_cast <sal_Int32>( mnStyleId ) ) ).getStr(),
2380 // OOXTODO: XML_iLevel,
2381 // OOXTODO: XML_hidden,
2382 XML_customBuiltin, XclXmlUtils::ToPsz( ! IsBuiltIn() ),
2383 FSEND );
2384 // OOXTODO: XML_extLst
2387 namespace {
2389 const sal_uInt32 EXC_XFLIST_INDEXBASE = 0xFFFE0000;
2390 /** Maximum count of XF records to store in the XF list (performance). */
2391 const sal_uInt32 EXC_XFLIST_HARDLIMIT = 256 * 1024;
2393 bool lclIsBuiltInStyle( const OUString& rStyleName )
2395 return
2396 XclTools::IsBuiltInStyleName( rStyleName ) ||
2397 XclTools::IsCondFormatStyleName( rStyleName );
2400 } // namespace
2402 XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
2403 mnStyleId( EXC_STYLE_USERDEF ),
2404 mnLevel( EXC_STYLE_NOLEVEL ),
2405 mbPredefined( true ),
2406 mbHasStyleRec( false )
2410 /** Predicate for search algorithm. */
2411 struct XclExpBorderPred
2413 const XclExpCellBorder&
2414 mrBorder;
2415 inline explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
2416 bool operator()( const XclExpCellBorder& rBorder ) const;
2419 bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
2421 return
2422 mrBorder.mnLeftColor == rBorder.mnLeftColor &&
2423 mrBorder.mnRightColor == rBorder.mnRightColor &&
2424 mrBorder.mnTopColor == rBorder.mnTopColor &&
2425 mrBorder.mnBottomColor == rBorder.mnBottomColor &&
2426 mrBorder.mnDiagColor == rBorder.mnDiagColor &&
2427 mrBorder.mnLeftLine == rBorder.mnLeftLine &&
2428 mrBorder.mnRightLine == rBorder.mnRightLine &&
2429 mrBorder.mnTopLine == rBorder.mnTopLine &&
2430 mrBorder.mnBottomLine == rBorder.mnBottomLine &&
2431 mrBorder.mnDiagLine == rBorder.mnDiagLine &&
2432 mrBorder.mbDiagTLtoBR == rBorder.mbDiagTLtoBR &&
2433 mrBorder.mbDiagBLtoTR == rBorder.mbDiagBLtoTR &&
2434 mrBorder.mnLeftColorId == rBorder.mnLeftColorId &&
2435 mrBorder.mnRightColorId == rBorder.mnRightColorId &&
2436 mrBorder.mnTopColorId == rBorder.mnTopColorId &&
2437 mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
2438 mrBorder.mnDiagColorId == rBorder.mnDiagColorId;
2441 struct XclExpFillPred
2443 const XclExpCellArea&
2444 mrFill;
2445 inline explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
2446 bool operator()( const XclExpCellArea& rFill ) const;
2449 bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
2451 return
2452 mrFill.mnForeColor == rFill.mnForeColor &&
2453 mrFill.mnBackColor == rFill.mnBackColor &&
2454 mrFill.mnPattern == rFill.mnPattern &&
2455 mrFill.mnForeColorId == rFill.mnForeColorId &&
2456 mrFill.mnBackColorId == rFill.mnBackColorId;
2459 XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
2460 XclExpRoot( rRoot )
2464 void XclExpXFBuffer::Initialize()
2466 InsertDefaultRecords();
2467 InsertUserStyles();
2470 sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
2472 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
2475 sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
2476 sal_uInt16 nForceXclFont, bool bForceLineBreak )
2478 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
2481 sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uLong nForceScNumFmt, bool bForceLineBreak )
2483 return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
2486 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
2488 return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2491 sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
2493 return EXC_XFLIST_INDEXBASE | nXFIndex;
2496 sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
2498 return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
2501 const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
2503 return maXFList.GetRecord( nXFId ).get();
2506 void XclExpXFBuffer::Finalize()
2508 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2509 maXFList.GetRecord( nPos )->SetFinalColors();
2511 sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
2512 sal_uInt32 nId;
2513 maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2514 maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2515 maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
2517 XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
2518 /* nMaxBuiltInXFId used to decide faster whether an XF record is
2519 user-defined. If the current XF ID is greater than this value,
2520 maBuiltInMap doesn't need to be searched. */
2521 sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
2523 // *** map all built-in XF records (cell and style) *** -------------------
2525 // do not change XF order -> std::map<> iterates elements in ascending order
2526 for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(); aIt != aBuiltInEnd; ++aIt )
2527 AppendXFIndex( aIt->first );
2529 // *** insert all user-defined style XF records, without reduce *** -------
2531 sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
2533 for( nId = 0; nId < nTotalCount; ++nId )
2535 XclExpXFRef xXF = maXFList.GetRecord( nId );
2536 if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2538 if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
2540 // maximum count of styles not reached
2541 AppendXFIndex( nId );
2542 ++nStyleXFCount;
2544 else
2546 /* Maximum count of styles reached - do not append more
2547 pointers to XFs; use default style XF instead; do not break
2548 the loop to initialize all maXFIndexVec elements. */
2549 maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
2554 // *** insert all cell XF records *** -------------------------------------
2556 // start position to search for equal inserted XF records
2557 size_t nSearchStart = maSortedXFList.GetSize();
2559 // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
2560 XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
2561 for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
2563 XclExpXFRef xXF = maXFList.GetRecord( nId );
2564 if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
2566 // try to find an XF record equal to *xXF, which is already inserted
2567 sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
2569 // first try if it is equal to the default cell XF
2570 if( xDefCellXF->Equals( *xXF ) )
2572 nFoundIndex = EXC_XF_DEFAULTCELL;
2574 else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
2575 (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
2577 if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
2578 nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
2581 if( nFoundIndex != EXC_XF_NOTFOUND )
2582 // equal XF already in the list, use its resulting XF index
2583 maXFIndexVec[ nId ] = nFoundIndex;
2584 else
2585 AppendXFIndex( nId );
2589 sal_uInt16 nXmlStyleIndex = 0;
2590 sal_uInt16 nXmlCellIndex = 0;
2592 size_t nXFCount = maSortedXFList.GetSize();
2593 for( size_t i = 0; i < nXFCount; ++i )
2595 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2596 if( xXF->IsStyleXF() )
2597 maStyleIndexes[ i ] = nXmlStyleIndex++;
2598 else
2599 maCellIndexes[ i ] = nXmlCellIndex++;
2603 sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
2605 sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
2606 if( nXFId >= EXC_XFLIST_INDEXBASE )
2607 nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
2608 else if( nXFId < maXFIndexVec.size() )
2609 nXFIndex = maXFIndexVec[ nXFId ];
2610 return nXFIndex;
2613 sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
2615 OSL_ENSURE( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2616 if( nXFIndex > maStyleIndexes.size() )
2617 return 0; // should be caught/debugged via above assert; return "valid" index.
2618 return maStyleIndexes[ nXFIndex ];
2621 sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
2623 OSL_ENSURE( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
2624 if( nXFIndex > maCellIndexes.size() )
2625 return 0; // should be caught/debugged via above assert; return "valid" index.
2626 return maCellIndexes[ nXFIndex ];
2629 void XclExpXFBuffer::Save( XclExpStream& rStrm )
2631 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2632 maSortedXFList.Save( rStrm );
2633 // save all STYLE records
2634 maStyleList.Save( rStrm );
2637 static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
2639 rCells = 0;
2640 rStyles = 0;
2641 size_t nXFCount = rXFList.GetSize();
2642 for( size_t i = 0; i < nXFCount; ++i )
2644 XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
2645 if( xXF->IsCellXF() )
2646 ++rCells;
2647 else if( xXF->IsStyleXF() )
2648 ++rStyles;
2652 void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
2654 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
2656 rStyleSheet->startElement( XML_fills,
2657 XML_count, OString::number( maFills.size() ).getStr(),
2658 FSEND );
2659 for( XclExpFillList::iterator aIt = maFills.begin(), aEnd = maFills.end();
2660 aIt != aEnd; ++aIt )
2662 aIt->SaveXml( rStrm );
2664 rStyleSheet->endElement( XML_fills );
2666 rStyleSheet->startElement( XML_borders,
2667 XML_count, OString::number( maBorders.size() ).getStr(),
2668 FSEND );
2669 for( XclExpBorderList::iterator aIt = maBorders.begin(), aEnd = maBorders.end();
2670 aIt != aEnd; ++aIt )
2672 aIt->SaveXml( rStrm );
2674 rStyleSheet->endElement( XML_borders );
2676 // save all XF records contained in the maSortedXFList vector (sorted by XF index)
2677 sal_Int32 nCells, nStyles;
2678 lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
2680 if( nStyles > 0 )
2682 rStyleSheet->startElement( XML_cellStyleXfs,
2683 XML_count, OString::number( nStyles ).getStr(),
2684 FSEND );
2685 size_t nXFCount = maSortedXFList.GetSize();
2686 for( size_t i = 0; i < nXFCount; ++i )
2688 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2689 if( ! xXF->IsStyleXF() )
2690 continue;
2691 SaveXFXml( rStrm, *xXF );
2693 rStyleSheet->endElement( XML_cellStyleXfs );
2696 if( nCells > 0 )
2698 rStyleSheet->startElement( XML_cellXfs,
2699 XML_count, OString::number( nCells ).getStr(),
2700 FSEND );
2701 size_t nXFCount = maSortedXFList.GetSize();
2702 for( size_t i = 0; i < nXFCount; ++i )
2704 XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
2705 if( ! xXF->IsCellXF() )
2706 continue;
2707 SaveXFXml( rStrm, *xXF );
2709 rStyleSheet->endElement( XML_cellXfs );
2712 // save all STYLE records
2713 rStyleSheet->startElement( XML_cellStyles,
2714 XML_count, OString::number( maStyleList.GetSize() ).getStr(),
2715 FSEND );
2716 maStyleList.SaveXml( rStrm );
2717 rStyleSheet->endElement( XML_cellStyles );
2720 void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
2722 XclExpBorderList::iterator aBorderPos =
2723 std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
2724 OSL_ENSURE( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
2725 XclExpFillList::iterator aFillPos =
2726 std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
2727 OSL_ENSURE( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
2729 sal_Int32 nBorderId = 0, nFillId = 0;
2730 if( aBorderPos != maBorders.end() )
2731 nBorderId = std::distance( maBorders.begin(), aBorderPos );
2732 if( aFillPos != maFills.end() )
2733 nFillId = std::distance( maFills.begin(), aFillPos );
2735 rXF.SetXmlIds( nBorderId, nFillId );
2736 rXF.SaveXml( rStrm );
2739 sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
2740 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
2742 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2743 if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
2744 return static_cast< sal_uInt32 >( nPos );
2745 return EXC_XFID_NOTFOUND;
2748 sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
2750 for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
2751 if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
2752 return static_cast< sal_uInt32 >( nPos );
2753 return EXC_XFID_NOTFOUND;
2756 sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
2758 for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(), aEnd = maBuiltInMap.end(); aIt != aEnd; ++aIt )
2759 if( (aIt->second.mnStyleId == nStyleId) && (aIt->second.mnLevel == nLevel) )
2760 return aIt->first;
2761 return EXC_XFID_NOTFOUND;
2764 sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
2765 sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
2767 const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
2768 if( !pPattern )
2769 pPattern = pDefPattern;
2771 // special handling for default cell formatting
2772 if( (pPattern == pDefPattern) && !bForceLineBreak &&
2773 (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
2774 (nForceXclFont == EXC_FONT_NOTFOUND) )
2776 // Is it the first try to insert the default cell format?
2777 bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
2778 if( rbPredefined )
2780 // replace default cell pattern
2781 XclExpXFRef xNewXF( new XclExpXF( GetRoot(), *pPattern, nScript ) );
2782 maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
2783 rbPredefined = false;
2785 return GetDefCellXFId();
2788 sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
2789 if( nXFId == EXC_XFID_NOTFOUND )
2791 // not found - insert new cell XF
2792 if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
2794 maXFList.AppendNewRecord( new XclExpXF(
2795 GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak ) );
2796 // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
2797 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
2799 else
2801 // list full - fall back to default cell XF
2802 nXFId = GetDefCellXFId();
2805 return nXFId;
2808 sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
2810 // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
2812 sal_uInt8 nStyleId, nLevel;
2813 if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
2815 // try to find the built-in XF record (if already created in InsertDefaultRecords())
2816 sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
2817 if( nXFId == EXC_XFID_NOTFOUND )
2819 // built-in style XF not yet created - do it now
2820 XclExpXFRef xXF( new XclExpXF( GetRoot(), rStyleSheet ) );
2821 nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
2822 // this new XF record is not predefined
2823 maBuiltInMap[ nXFId ].mbPredefined = false;
2825 else
2827 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
2828 // XF record still predefined? -> Replace with real XF
2829 bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
2830 if( rbPredefined )
2832 // replace predefined built-in style (ReplaceRecord() deletes old record)
2833 maXFList.ReplaceRecord( XclExpXFRef( new XclExpXF( GetRoot(), rStyleSheet ) ), nXFId );
2834 rbPredefined = false;
2838 // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
2839 bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
2840 if( !rbHasStyleRec )
2842 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2843 rbHasStyleRec = true;
2846 return nXFId;
2849 // *** try to find the XF record of a user-defined style ***
2851 sal_uInt32 nXFId = FindXF( rStyleSheet );
2852 if( nXFId == EXC_XFID_NOTFOUND )
2854 // not found - insert new style XF and STYLE
2855 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2856 if( nXFId < EXC_XFLIST_HARDLIMIT )
2858 maXFList.AppendNewRecord( new XclExpXF( GetRoot(), rStyleSheet ) );
2859 // create the STYLE record
2860 if( !rStyleSheet.GetName().isEmpty() )
2861 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
2863 else
2864 // list full - fall back to default style XF
2865 nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
2867 return nXFId;
2870 void XclExpXFBuffer::InsertUserStyles()
2872 SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
2873 for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
2874 if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
2875 InsertStyleXF( *pStyleSheet );
2878 sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2880 sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
2881 maXFList.AppendRecord( xXF );
2882 XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
2883 rInfo.mnStyleId = nStyleId;
2884 rInfo.mnLevel = nLevel;
2885 rInfo.mbPredefined = true;
2886 return nXFId;
2889 sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
2891 sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
2892 maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
2893 maBuiltInMap[ nXFId ].mbHasStyleRec = true; // mark existing STYLE record
2894 return nXFId;
2897 static XclExpCellArea lcl_GetPatternFill_None()
2899 XclExpCellArea aFill;
2900 aFill.mnPattern = EXC_PATT_NONE;
2901 return aFill;
2904 static XclExpCellArea lcl_GetPatternFill_Gray125()
2906 XclExpCellArea aFill;
2907 aFill.mnPattern = EXC_PATT_12_5_PERC;
2908 aFill.mnForeColor = 0;
2909 aFill.mnBackColor = 0;
2910 return aFill;
2913 void XclExpXFBuffer::InsertDefaultRecords()
2915 maFills.push_back( lcl_GetPatternFill_None() );
2916 maFills.push_back( lcl_GetPatternFill_Gray125() );
2918 // index 0: default style
2919 if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) )
2921 XclExpXFRef xDefStyle( new XclExpXF( GetRoot(), *pDefStyleSheet ) );
2922 sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2923 // mark this XF as not predefined, prevents overwriting
2924 maBuiltInMap[ nXFId ].mbPredefined = false;
2926 else
2928 OSL_FAIL( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
2929 XclExpXFRef xDefStyle( new XclExpDefaultXF( GetRoot(), false ) );
2930 xDefStyle->SetAllUsedFlags( true );
2931 AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
2934 // index 1-14: RowLevel and ColLevel styles (without STYLE records)
2935 XclExpDefaultXF aLevelStyle( GetRoot(), false );
2936 // RowLevel_1, ColLevel_1
2937 aLevelStyle.SetFont( 1 );
2938 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 0 );
2939 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 0 );
2940 // RowLevel_2, ColLevel_2
2941 aLevelStyle.SetFont( 2 );
2942 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 1 );
2943 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 1 );
2944 // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
2945 aLevelStyle.SetFont( 0 );
2946 for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
2948 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, nLevel );
2949 AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, nLevel );
2952 // index 15: default hard cell format, placeholder to be able to add more built-in styles
2953 maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
2954 maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
2956 // index 16-20: other built-in styles
2957 XclExpDefaultXF aFormatStyle( GetRoot(), false );
2958 aFormatStyle.SetFont( 1 );
2959 aFormatStyle.SetNumFmt( 43 );
2960 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA );
2961 aFormatStyle.SetNumFmt( 41 );
2962 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA_0 );
2963 aFormatStyle.SetNumFmt( 44 );
2964 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY );
2965 aFormatStyle.SetNumFmt( 42 );
2966 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY_0 );
2967 aFormatStyle.SetNumFmt( 9 );
2968 AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_PERCENT );
2970 // other built-in style XF records (i.e. Hyperlink styles) are created on demand
2972 /* Insert the real default hard cell format -> 0 is document default pattern.
2973 Do it here (and not already above) to really have all built-in styles. */
2974 Insert( 0, GetDefApiScript() );
2977 void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
2979 OSL_ENSURE( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
2980 maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
2981 XclExpXFRef xXF = maXFList.GetRecord( nXFId );
2982 AddBorderAndFill( *xXF );
2983 maSortedXFList.AppendRecord( xXF );
2984 OSL_ENSURE( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
2987 void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
2989 if( std::none_of( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) )
2991 maBorders.push_back( rXF.GetBorderData() );
2994 if( std::none_of( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) )
2996 maFills.push_back( rXF.GetAreaData() );
3000 XclExpDxfs::XclExpDxfs( const XclExpRoot& rRoot )
3001 : XclExpRoot( rRoot ),
3002 mxFormatter( new SvNumberFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ) ),
3003 mpKeywordTable( new NfKeywordTable )
3005 mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
3006 // remap codes unknown to Excel
3007 (*mpKeywordTable)[ NF_KEY_NN ] = "DDD";
3008 (*mpKeywordTable)[ NF_KEY_NNN ] = "DDDD";
3009 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
3010 (*mpKeywordTable)[ NF_KEY_NNNN ] = "DDDD";
3011 // Export the Thai T NatNum modifier.
3012 (*mpKeywordTable)[ NF_KEY_THAI_T ] = "T";
3014 SCTAB nTables = rRoot.GetDoc().GetTableCount();
3015 for(SCTAB nTab = 0; nTab < nTables; ++nTab)
3017 ScConditionalFormatList* pList = rRoot.GetDoc().GetCondFormList(nTab);
3018 if (pList)
3020 sal_Int32 nIndex = 0;
3021 for (ScConditionalFormatList::const_iterator itr = pList->begin();
3022 itr != pList->end(); ++itr)
3024 size_t nEntryCount = itr->size();
3025 for (size_t nFormatEntry = 0; nFormatEntry < nEntryCount; ++nFormatEntry)
3027 const ScFormatEntry* pFormatEntry = itr->GetEntry(nFormatEntry);
3028 if (!pFormatEntry || (pFormatEntry->GetType() != condformat::CONDITION &&
3029 pFormatEntry->GetType() != condformat::DATE))
3030 continue;
3032 OUString aStyleName;
3033 if(pFormatEntry->GetType() == condformat::CONDITION)
3035 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
3036 aStyleName= pEntry->GetStyle();
3038 else
3040 const ScCondDateFormatEntry* pEntry = static_cast<const ScCondDateFormatEntry*>(pFormatEntry);
3041 aStyleName = pEntry->GetStyleName();
3044 if (maStyleNameToDxfId.find(aStyleName) == maStyleNameToDxfId.end())
3046 maStyleNameToDxfId.insert(std::pair<OUString, sal_Int32>(aStyleName, nIndex));
3048 SfxStyleSheetBase* pStyle = rRoot.GetDoc().GetStyleSheetPool()->Find(aStyleName);
3049 if(!pStyle)
3050 continue;
3052 SfxItemSet& rSet = pStyle->GetItemSet();
3054 XclExpCellBorder* pBorder = new XclExpCellBorder;
3055 if (!pBorder->FillFromItemSet( rSet, GetPalette(), GetBiff()) )
3057 delete pBorder;
3058 pBorder = NULL;
3061 XclExpCellAlign* pAlign = new XclExpCellAlign;
3062 if (!pAlign->FillFromItemSet( rSet, false, GetBiff()))
3064 delete pAlign;
3065 pAlign = NULL;
3068 XclExpCellProt* pCellProt = new XclExpCellProt;
3069 if (!pCellProt->FillFromItemSet( rSet ))
3071 delete pCellProt;
3072 pCellProt = NULL;
3075 XclExpColor* pColor = new XclExpColor();
3076 if(!pColor->FillFromItemSet( rSet ))
3078 delete pColor;
3079 pColor = NULL;
3082 XclExpDxfFont* pFont = new XclExpDxfFont(rRoot, rSet);
3084 XclExpNumFmt* pNumFormat = NULL;
3085 const SfxPoolItem *pPoolItem = NULL;
3086 if( rSet.GetItemState( ATTR_VALUE_FORMAT, true, &pPoolItem ) == SfxItemState::SET )
3088 sal_uLong nScNumFmt = static_cast< const SfxUInt32Item* >(pPoolItem)->GetValue();
3089 sal_Int32 nXclNumFmt = GetRoot().GetNumFmtBuffer().Insert(nScNumFmt);
3090 pNumFormat = new XclExpNumFmt( nScNumFmt, nXclNumFmt, GetNumberFormatCode( *this, nScNumFmt, mxFormatter.get(), mpKeywordTable.get() ));
3093 maDxf.push_back(new XclExpDxf( rRoot, pAlign, pBorder, pFont, pNumFormat, pCellProt, pColor ));
3094 ++nIndex;
3103 sal_Int32 XclExpDxfs::GetDxfId( const OUString& rStyleName )
3105 std::map<OUString, sal_Int32>::iterator itr = maStyleNameToDxfId.find(rStyleName);
3106 if(itr!= maStyleNameToDxfId.end())
3107 return itr->second;
3108 return -1;
3111 void XclExpDxfs::SaveXml( XclExpXmlStream& rStrm )
3113 if(maDxf.empty())
3114 return;
3116 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3117 rStyleSheet->startElement( XML_dxfs,
3118 XML_count, OString::number(maDxf.size()).getStr(),
3119 FSEND );
3121 for ( DxfContainer::iterator itr = maDxf.begin(); itr != maDxf.end(); ++itr )
3123 itr->SaveXml( rStrm );
3126 rStyleSheet->endElement( XML_dxfs );
3129 XclExpDxf::XclExpDxf( const XclExpRoot& rRoot, XclExpCellAlign* pAlign, XclExpCellBorder* pBorder,
3130 XclExpDxfFont* pFont, XclExpNumFmt* pNumberFmt, XclExpCellProt* pProt, XclExpColor* pColor)
3131 : XclExpRoot( rRoot ),
3132 mpAlign(pAlign),
3133 mpBorder(pBorder),
3134 mpFont(pFont),
3135 mpNumberFmt(pNumberFmt),
3136 mpProt(pProt),
3137 mpColor(pColor)
3141 XclExpDxf::~XclExpDxf()
3145 void XclExpDxf::SaveXml( XclExpXmlStream& rStrm )
3147 sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
3148 rStyleSheet->startElement( XML_dxf, FSEND );
3150 if (mpFont)
3151 mpFont->SaveXml(rStrm);
3152 if (mpNumberFmt)
3153 mpNumberFmt->SaveXml(rStrm);
3154 if (mpColor)
3155 mpColor->SaveXml(rStrm);
3156 if (mpAlign)
3157 mpAlign->SaveXml(rStrm);
3158 if (mpBorder)
3159 mpBorder->SaveXml(rStrm);
3160 if (mpProt)
3161 mpProt->SaveXml(rStrm);
3162 rStyleSheet->endElement( XML_dxf );
3165 XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
3166 : XclExpRoot( rRoot )
3170 void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
3172 sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
3173 OUString( "xl/styles.xml"),
3174 OUString( "styles.xml" ),
3175 rStrm.GetCurrentStream()->getOutputStream(),
3176 "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3177 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" );
3178 rStrm.PushStream( aStyleSheet );
3180 aStyleSheet->startElement( XML_styleSheet,
3181 XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
3182 FSEND );
3184 CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
3185 CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
3186 CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
3187 CreateRecord( EXC_ID_DXFS )->SaveXml( rStrm );
3188 CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
3190 aStyleSheet->endElement( XML_styleSheet );
3192 rStrm.PopStream();
3195 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */