update dev300-m58
[ooovba.git] / sc / source / filter / excel / xechart.cxx
blobaebe639d29b02f24b98ceb5b421cb2f8601e944d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xechart.cxx,v $
10 * $Revision: 1.10.62.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "xechart.hxx"
36 #include <com/sun/star/i18n/XBreakIterator.hpp>
37 #include <com/sun/star/i18n/ScriptType.hpp>
38 #include <com/sun/star/drawing/FillStyle.hpp>
39 #include <com/sun/star/chart/XChartDocument.hpp>
40 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
41 #include <com/sun/star/chart/ChartAxisPosition.hpp>
42 #include <com/sun/star/chart/DataLabelPlacement.hpp>
43 #include <com/sun/star/chart/ErrorBarStyle.hpp>
44 #include <com/sun/star/chart/MissingValueTreatment.hpp>
45 #include <com/sun/star/chart2/XChartDocument.hpp>
46 #include <com/sun/star/chart2/XDiagram.hpp>
47 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
48 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
49 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
50 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
51 #include <com/sun/star/chart2/XTitled.hpp>
52 #include <com/sun/star/chart2/XColorScheme.hpp>
53 #include <com/sun/star/chart2/data/XDataSource.hpp>
54 #include <com/sun/star/chart2/AxisType.hpp>
55 #include <com/sun/star/chart2/CurveStyle.hpp>
56 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
57 #include <com/sun/star/chart2/DataPointLabel.hpp>
58 #include <com/sun/star/chart2/StackingDirection.hpp>
59 #include <com/sun/star/chart2/TickmarkStyle.hpp>
61 #include <vcl/outdev.hxx>
62 #include <svx/escherex.hxx>
64 #include "document.hxx"
65 #include "rangelst.hxx"
66 #include "rangeutl.hxx"
67 #include "compiler.hxx"
68 #include "tokenarray.hxx"
69 #include "token.hxx"
70 #include "xeformula.hxx"
71 #include "xehelper.hxx"
72 #include "xepage.hxx"
73 #include "xestyle.hxx"
75 using ::rtl::OUString;
76 using ::com::sun::star::uno::Any;
77 using ::com::sun::star::uno::Reference;
78 using ::com::sun::star::uno::Sequence;
79 using ::com::sun::star::uno::UNO_QUERY;
80 using ::com::sun::star::uno::Exception;
81 using ::com::sun::star::beans::XPropertySet;
82 using ::com::sun::star::i18n::XBreakIterator;
83 using ::com::sun::star::frame::XModel;
84 using ::com::sun::star::chart2::XChartDocument;
85 using ::com::sun::star::chart2::XDiagram;
86 using ::com::sun::star::chart2::XCoordinateSystemContainer;
87 using ::com::sun::star::chart2::XCoordinateSystem;
88 using ::com::sun::star::chart2::XChartTypeContainer;
89 using ::com::sun::star::chart2::XChartType;
90 using ::com::sun::star::chart2::XDataSeriesContainer;
91 using ::com::sun::star::chart2::XDataSeries;
92 using ::com::sun::star::chart2::XRegressionCurveContainer;
93 using ::com::sun::star::chart2::XRegressionCurve;
94 using ::com::sun::star::chart2::XAxis;
95 using ::com::sun::star::chart2::XScaling;
96 using ::com::sun::star::chart2::ScaleData;
97 using ::com::sun::star::chart2::IncrementData;
98 using ::com::sun::star::chart2::SubIncrement;
99 using ::com::sun::star::chart2::XLegend;
100 using ::com::sun::star::chart2::XTitled;
101 using ::com::sun::star::chart2::XTitle;
102 using ::com::sun::star::chart2::XFormattedString;
103 using ::com::sun::star::chart2::XColorScheme;
105 using ::com::sun::star::chart2::data::XDataSource;
106 using ::com::sun::star::chart2::data::XLabeledDataSequence;
107 using ::com::sun::star::chart2::data::XDataSequence;
109 using ::formula::FormulaGrammar;
110 using ::formula::FormulaToken;
112 // Helpers ====================================================================
114 namespace {
116 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
118 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
121 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
123 if( xRec.is() )
124 xRec->Save( rStrm );
127 /** Saves the passed record (group) together with a leading value record. */
128 template< typename Type >
129 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
131 if( xRec.is() )
133 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
134 xRec->Save( rStrm );
138 void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
140 sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
141 rStrm.StartRecord( nRecId, 12 );
142 rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
143 rStrm.EndRecord();
146 template< typename Type >
147 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
149 return !rAny.hasValue() || !(rAny >>= rValue);
152 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
154 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
155 if( !bIsAuto && bLogScale )
156 rfValue = log( rfValue ) / log( 10.0 );
157 return bIsAuto;
160 } // namespace
162 // Common =====================================================================
164 /** Stores global data needed in various classes of the Chart export filter. */
165 class XclExpChRootData : public XclChRootData
167 public:
168 explicit XclExpChRootData( XclExpChChart* pChartData );
170 /** Returns a reference to the parent chart data object. */
171 inline XclExpChChart& GetChartData() const { return *mpChartData; }
173 /** Registers a new future record level. */
174 void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
175 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
176 void InitializeFutureRecBlock( XclExpStream& rStrm );
177 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
178 void FinalizeFutureRecBlock( XclExpStream& rStrm );
180 private:
181 typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
183 XclExpChChart* mpChartData; /// Pointer to the chart data object.
184 XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
185 XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
188 // ----------------------------------------------------------------------------
190 XclExpChRootData::XclExpChRootData( XclExpChChart* pChartData ) :
191 mpChartData( pChartData )
195 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
197 maUnwrittenFrBlocks.push_back( rFrBlock );
200 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
202 // first call from a future record writes all missing CHFRBLOCKBEGIN records
203 if( !maUnwrittenFrBlocks.empty() )
205 // write the leading CHFRINFO record
206 if( maWrittenFrBlocks.empty() )
208 rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
209 rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
210 rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
211 rStrm.EndRecord();
213 // write all unwritten CHFRBLOCKBEGIN records
214 for( XclChFrBlockVector::const_iterator aIt = maUnwrittenFrBlocks.begin(), aEnd = maUnwrittenFrBlocks.end(); aIt != aEnd; ++aIt )
216 DBG_ASSERT( aIt->mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
217 lclWriteChFrBlockRecord( rStrm, *aIt, true );
219 // move all record infos to vector of written blocks
220 maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
221 maUnwrittenFrBlocks.clear();
225 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
227 DBG_ASSERT( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
228 if( !maUnwrittenFrBlocks.empty() )
230 // no future record has been written, just forget the topmost level
231 maUnwrittenFrBlocks.pop_back();
233 else if( !maWrittenFrBlocks.empty() )
235 // write the CHFRBLOCKEND record for the topmost block and delete it
236 lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
237 maWrittenFrBlocks.pop_back();
241 // ----------------------------------------------------------------------------
243 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart* pChartData ) :
244 XclExpRoot( rRoot ),
245 mxChData( new XclExpChRootData( pChartData ) )
249 XclExpChRoot::~XclExpChRoot()
253 XclExpChChart& XclExpChRoot::GetChartData() const
255 return mxChData->GetChartData();
258 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
260 return mxChData->GetTypeInfoProvider().GetTypeInfo( eType );
263 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
265 return mxChData->GetTypeInfoProvider().GetTypeInfoFromService( rServiceName );
268 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
270 return mxChData->GetFormatInfoProvider().GetFormatInfo( eObjType );
273 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc ) const
275 mxChData->InitConversion( xChartDoc );
278 void XclExpChRoot::FinishConversion() const
280 mxChData->FinishConversion();
283 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
285 XclExpPalette& rPal = GetPalette();
286 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
289 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
291 DBG_ASSERT( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
292 rColor = GetPalette().GetDefColor( nSysColorIdx );
293 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
296 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
297 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
299 GetChartPropSetHelper().ReadLineProperties(
300 rLineFmt, mxChData->GetLineDashTable(), rPropSet, ePropMode );
303 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
304 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
306 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
309 void XclExpChRoot::ConvertEscherFormat(
310 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
311 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
313 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
314 mxChData->GetGradientTable(), mxChData->GetHatchTable(), mxChData->GetBitmapTable(), rPropSet, ePropMode );
317 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
319 XclFontData aFontData;
320 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
321 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
324 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
326 sal_Int32 nApiRot = 0;
327 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
328 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
331 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
333 mxChData->RegisterFutureRecBlock( rFrBlock );
336 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
338 mxChData->InitializeFutureRecBlock( rStrm );
341 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
343 mxChData->FinalizeFutureRecBlock( rStrm );
346 // ----------------------------------------------------------------------------
348 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
349 sal_uInt16 nFrType, sal_uInt16 nRecId, sal_Size nRecSize ) :
350 XclExpRecord( nRecId, nRecSize ),
351 XclExpChRoot( rRoot ),
352 maFrBlock( nFrType )
356 XclExpChGroupBase::~XclExpChGroupBase()
360 void XclExpChGroupBase::Save( XclExpStream& rStrm )
362 // header record
363 XclExpRecord::Save( rStrm );
364 // group records
365 if( HasSubRecords() )
367 // register the future record context corresponding to this record group
368 RegisterFutureRecBlock( maFrBlock );
369 // CHBEGIN record
370 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
371 // embedded records
372 WriteSubRecords( rStrm );
373 // finalize the future records, must be done before the closing CHEND
374 FinalizeFutureRecBlock( rStrm );
375 // CHEND record
376 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
380 bool XclExpChGroupBase::HasSubRecords() const
382 return true;
385 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
387 maFrBlock.mnContext = nFrContext;
388 maFrBlock.mnValue1 = nFrValue1;
389 maFrBlock.mnValue2 = nFrValue2;
392 // ----------------------------------------------------------------------------
394 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
395 XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
396 XclExpFutureRecord( eRecType, nRecId, nRecSize ),
397 XclExpChRoot( rRoot )
401 void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
403 InitializeFutureRecBlock( rStrm );
404 XclExpFutureRecord::Save( rStrm );
407 // Frame formatting ===========================================================
409 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
410 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
411 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
415 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
417 switch( eDefFrameType )
419 case EXC_CHFRAMETYPE_AUTO:
420 SetAuto( true );
421 break;
422 case EXC_CHFRAMETYPE_INVISIBLE:
423 SetAuto( false );
424 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
425 break;
426 default:
427 DBG_ERRORFILE( "XclExpChLineFormat::SetDefault - unknown frame type" );
431 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
432 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
434 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
435 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
436 if( HasLine() )
438 // detect system color, set color identifier (TODO: detect automatic series line)
439 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
441 // store color index from automatic format data
442 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
443 // try to set automatic mode
444 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
445 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
447 else
449 // user defined color - register in palette
450 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
453 else
455 // no line - set default system color
456 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
460 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
462 return
463 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
464 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
467 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
469 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
470 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
471 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
474 namespace {
476 /** Creates a CHLINEFORMAT record from the passed property set. */
477 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
478 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
480 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
481 xLineFmt->Convert( rRoot, rPropSet, eObjType );
482 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
483 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
484 xLineFmt.reset();
485 return xLineFmt;
488 } // namespace
490 // ----------------------------------------------------------------------------
492 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
493 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
494 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
495 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
499 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
500 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
502 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
503 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
504 if( HasArea() )
506 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
507 // detect system color, set color identifier (TODO: detect automatic series area)
508 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
510 // store color index from automatic format data
511 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
512 // set automatic mode
513 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
515 else
517 // user defined color - register color in palette
518 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
520 // background color (default system color for solid fills)
521 if( bSolid )
522 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
523 else
524 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
526 else
528 // no area - set default system colors
529 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
530 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
532 return bComplexFill;
535 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
537 switch( eDefFrameType )
539 case EXC_CHFRAMETYPE_AUTO:
540 SetAuto( true );
541 break;
542 case EXC_CHFRAMETYPE_INVISIBLE:
543 SetAuto( false );
544 maData.mnPattern = EXC_PATT_NONE;
545 break;
546 default:
547 DBG_ERRORFILE( "XclExpChAreaFormat::SetDefault - unknown frame type" );
551 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
553 return
554 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
555 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
558 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
560 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
561 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
563 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
564 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
568 // ----------------------------------------------------------------------------
570 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
571 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
572 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
573 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
575 DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
578 void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
580 const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
581 ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
582 // register colors in palette
583 mnColor1Id = RegisterColor( ESCHER_Prop_fillColor );
584 mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor );
587 bool XclExpChEscherFormat::IsValid() const
589 return maData.mxEscherSet.is();
592 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
594 if( maData.mxEscherSet.is() )
596 // replace RGB colors with palette indexes in the Escher container
597 const XclExpPalette& rPal = GetPalette();
598 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
599 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
601 // save the record group
602 XclExpChGroupBase::Save( rStrm );
606 bool XclExpChEscherFormat::HasSubRecords() const
608 // no subrecords for gradients
609 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
612 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
614 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
615 rStrm << maPicFmt.mnBmpMode << maPicFmt.mnFormat << maPicFmt.mnFlags << maPicFmt.mfScale;
616 rStrm.EndRecord();
619 sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
621 sal_uInt32 nBGRValue;
622 if( maData.mxEscherSet.is() && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
624 // swap red and blue
625 Color aColor( RGB_COLORDATA(
626 COLORDATA_BLUE( nBGRValue ),
627 COLORDATA_GREEN( nBGRValue ),
628 COLORDATA_RED( nBGRValue ) ) );
629 return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
631 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
634 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
636 DBG_ASSERT( maData.mxEscherSet.is(), "XclExpChEscherFormat::WriteBody - missing property container" );
637 // write Escher property container via temporary memory stream
638 SvMemoryStream aMemStrm;
639 maData.mxEscherSet->Commit( aMemStrm );
640 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
641 rStrm.CopyFromStream( aMemStrm );
644 // ----------------------------------------------------------------------------
646 XclExpChFrameBase::XclExpChFrameBase()
650 XclExpChFrameBase::~XclExpChFrameBase()
654 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
655 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
657 // line format
658 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
659 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
660 // area format (only for frame objects)
661 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
663 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
664 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
665 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
667 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
668 mxEscherFmt->Convert( rPropSet, eObjType );
669 if( mxEscherFmt->IsValid() )
670 mxAreaFmt->SetAuto( false );
671 else
672 mxEscherFmt.reset();
677 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
678 XclChFrameType eDefFrameType, bool bIsFrame )
680 // line format
681 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
682 mxLineFmt->SetDefault( eDefFrameType );
683 // area format (only for frame objects)
684 if( bIsFrame )
686 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
687 mxAreaFmt->SetDefault( eDefFrameType );
688 mxEscherFmt.reset();
692 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
694 return
695 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
696 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
699 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
701 lclSaveRecord( rStrm, mxLineFmt );
702 lclSaveRecord( rStrm, mxAreaFmt );
703 lclSaveRecord( rStrm, mxEscherFmt );
706 // ----------------------------------------------------------------------------
708 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
709 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
710 meObjType( eObjType )
714 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
716 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
719 bool XclExpChFrame::IsDefault() const
721 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
724 bool XclExpChFrame::IsDeleteable() const
726 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
729 void XclExpChFrame::Save( XclExpStream& rStrm )
731 switch( meObjType )
733 // wall/floor frame without CHFRAME header record
734 case EXC_CHOBJTYPE_WALL3D:
735 case EXC_CHOBJTYPE_FLOOR3D:
736 WriteFrameRecords( rStrm );
737 break;
738 default:
739 XclExpChGroupBase::Save( rStrm );
743 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
745 WriteFrameRecords( rStrm );
748 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
750 rStrm << maData.mnFormat << maData.mnFlags;
753 namespace {
755 /** Creates a CHFRAME record from the passed property set. */
756 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
757 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
759 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
760 xFrame->Convert( rPropSet );
761 if( xFrame->IsDeleteable() )
762 xFrame.reset();
763 return xFrame;
766 } // namespace
768 // Source links ===============================================================
770 namespace {
772 void lclAddDoubleRefData(
773 ScTokenArray& orArray, const FormulaToken& rToken,
774 SCsTAB nScTab1, SCsCOL nScCol1, SCsROW nScRow1,
775 SCsTAB nScTab2, SCsCOL nScCol2, SCsROW nScRow2 )
777 ScComplexRefData aComplexRef;
778 aComplexRef.InitFlags();
779 aComplexRef.Ref1.SetFlag3D( true );
780 aComplexRef.Ref1.nTab = nScTab1;
781 aComplexRef.Ref1.nCol = nScCol1;
782 aComplexRef.Ref1.nRow = nScRow1;
783 aComplexRef.Ref2.nTab = nScTab2;
784 aComplexRef.Ref2.nCol = nScCol2;
785 aComplexRef.Ref2.nRow = nScRow2;
787 if( orArray.GetLen() > 0 )
788 orArray.AddOpCode( ocUnion );
790 DBG_ASSERT( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),
791 "lclAddDoubleRefData - double reference token expected");
792 if( rToken.GetType() == ::formula::svExternalDoubleRef )
793 orArray.AddExternalDoubleReference( rToken.GetIndex(), rToken.GetString(), aComplexRef );
794 else
795 orArray.AddDoubleReference( aComplexRef );
798 } // namespace
800 // ----------------------------------------------------------------------------
802 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
803 XclExpRecord( EXC_ID_CHSOURCELINK ),
804 XclExpChRoot( rRoot )
806 maData.mnDestType = nDestType;
807 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
810 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
812 mxLinkFmla.reset();
813 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
815 if( !xDataSeq.is() )
816 return nDefCount;
818 // Compile the range representation string into token array. Note that the
819 // source range text depends on the current grammar.
820 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
821 ScCompiler aComp( GetDocPtr(), ScAddress() );
822 aComp.SetGrammar( GetDocPtr()->GetGrammar() );
823 ScTokenArray* pArray = aComp.CompileString( aRangeRepr );
824 if( !pArray )
825 return nDefCount;
827 ScTokenArray aArray;
828 sal_uInt32 nValueCount = 0;
829 pArray->Reset();
830 for( const FormulaToken* pToken = pArray->First(); pToken; pToken = pArray->Next() )
832 switch( pToken->GetType() )
834 case ::formula::svSingleRef:
835 case ::formula::svExternalSingleRef:
836 // for a single ref token, just add it to the new token array as is
837 if( aArray.GetLen() > 0 )
838 aArray.AddOpCode( ocUnion );
839 aArray.AddToken( *pToken );
840 ++nValueCount;
841 break;
843 case ::formula::svDoubleRef:
844 case ::formula::svExternalDoubleRef:
846 // split 3-dimensional ranges into single sheets
847 const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
848 const ScSingleRefData& rRef1 = rComplexRef.Ref1;
849 const ScSingleRefData& rRef2 = rComplexRef.Ref2;
850 for( SCsTAB nScTab = rRef1.nTab; nScTab <= rRef2.nTab; ++nScTab )
852 // split 2-dimensional ranges into single columns
853 if( bSplitToColumns && (rRef1.nCol < rRef2.nCol) && (rRef1.nRow < rRef2.nRow) )
854 for( SCsCOL nScCol = rRef1.nCol; nScCol <= rRef2.nCol; ++nScCol )
855 lclAddDoubleRefData( aArray, *pToken, nScTab, nScCol, rRef1.nRow, nScTab, nScCol, rRef2.nRow );
856 else
857 lclAddDoubleRefData( aArray, *pToken, nScTab, rRef1.nCol, rRef1.nRow, nScTab, rRef2.nCol, rRef2.nRow );
859 sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
860 sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
861 sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
862 nValueCount += nCols * nRows * nTabs;
864 break;
866 default:;
870 const ScAddress aBaseCell;
871 mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
872 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
873 return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
876 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
878 mxString.reset();
879 sal_uInt16 nFontIdx = EXC_FONT_APP;
880 if( rStringSeq.hasElements() )
882 mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
883 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
884 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
886 // convert all formatted string entries from the sequence
887 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
888 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
889 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
891 if( pIt->is() )
893 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
894 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
895 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
896 OUString aText = (*pIt)->getString();
897 ScfPropertySet aStrProp( *pIt );
899 // #i63255# get script type for leading weak characters
900 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
902 // process all script portions
903 sal_Int32 nPortionPos = 0;
904 sal_Int32 nTextLen = aText.getLength();
905 while( nPortionPos < nTextLen )
907 // get script type and end position of next script portion
908 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
909 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
911 // reuse previous script for following weak portions
912 if( nScript == ApiScriptType::WEAK )
913 nScript = nLastScript;
915 // Excel start position of this portion
916 sal_uInt16 nXclPortionStart = mxString->Len();
917 // add portion text to Excel string
918 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
919 if( nXclPortionStart < mxString->Len() )
921 // find font index variable dependent on script type
922 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
923 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
925 // insert font into buffer (if not yet done)
926 if( rnFontIdx == EXC_FONT_NOTFOUND )
927 rnFontIdx = ConvertFont( aStrProp, nScript );
929 // insert font index into format run vector
930 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
933 // go to next script portion
934 nLastScript = nScript;
935 nPortionPos = nPortionEnd;
939 if( !mxString->IsEmpty() )
941 // get leading font index
942 const XclFormatRunVec& rFormats = mxString->GetFormats();
943 DBG_ASSERT( !rFormats.empty() && (rFormats.front().mnChar == 0),
944 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
945 // remove leading format run, if entire string is equally formatted
946 if( rFormats.size() == 1 )
947 nFontIdx = mxString->RemoveLeadingFont();
948 else if( !rFormats.empty() )
949 nFontIdx = rFormats.front().mnFontIdx;
950 // add trailing format run, if string is rich-formatted
951 if( mxString->IsRich() )
952 mxString->AppendTrailingFormat( EXC_FONT_APP );
955 return nFontIdx;
958 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
960 sal_Int32 nApiNumFmt = 0;
961 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
963 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
964 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
968 void XclExpChSourceLink::AppendString( const String& rStr )
970 if (!mxString.is())
971 return;
972 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
975 void XclExpChSourceLink::Save( XclExpStream& rStrm )
977 // CHFORMATRUNS record
978 if( mxString.is() && mxString->IsRich() )
980 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
981 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
982 mxString->WriteFormats( rStrm, true );
983 rStrm.EndRecord();
985 // CHSOURCELINK record
986 XclExpRecord::Save( rStrm );
987 // CHSTRING record
988 if( mxString.is() && !mxString->IsEmpty() )
990 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
991 rStrm << sal_uInt16( 0 ) << *mxString;
992 rStrm.EndRecord();
996 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
998 rStrm << maData.mnDestType
999 << maData.mnLinkType
1000 << maData.mnFlags
1001 << maData.mnNumFmtIdx
1002 << mxLinkFmla;
1005 // Text =======================================================================
1007 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
1008 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
1012 // ----------------------------------------------------------------------------
1014 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
1015 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
1017 maData.mnTarget = nLinkTarget;
1018 maData.maPointPos = rPointPos;
1021 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
1023 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
1026 // ----------------------------------------------------------------------------
1028 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
1029 XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
1033 void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, bool bShowSeries,
1034 bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
1036 // label value flags
1037 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, bShowSeries );
1038 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
1039 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
1040 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
1041 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
1043 // label value separator
1044 rPropSet.GetStringProperty( maData.maSeparator, EXC_CHPROP_LABELSEPARATOR );
1045 if( maData.maSeparator.Len() == 0 )
1046 maData.maSeparator = String( sal_Unicode( ' ' ) );
1049 void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
1051 XclExpString aXclSep( maData.maSeparator, EXC_STR_FORCEUNICODE | EXC_STR_SMARTFLAGS );
1052 rStrm << maData.mnFlags << aXclSep;
1055 // ----------------------------------------------------------------------------
1057 XclExpChFontBase::~XclExpChFontBase()
1061 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
1063 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
1065 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
1066 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
1070 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
1072 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
1075 void XclExpChFontBase::ConvertRotationBase(
1076 const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet, bool bSupportsStacked )
1078 sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet, bSupportsStacked );
1079 SetRotation( nRotation );
1082 // ----------------------------------------------------------------------------
1084 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
1085 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
1086 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
1090 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
1092 mxFont = xFont;
1093 maData.maTextColor = rColor;
1094 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
1095 mnTextColorId = nColorId;
1098 void XclExpChText::SetRotation( sal_uInt16 nRotation )
1100 maData.mnRotation = nRotation;
1101 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
1104 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const String* pSubTitle )
1106 switch( nTarget )
1108 case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
1109 case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
1110 case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 0 ); break;
1111 case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
1114 mxSrcLink.reset();
1115 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
1117 if( xTitle.is() )
1119 // title frame formatting
1120 ScfPropertySet aTitleProp( xTitle );
1121 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1123 // string sequence
1124 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1125 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1126 if (pSubTitle)
1128 // append subtitle as the 2nd line of the title.
1129 String aSubTitle = String::CreateFromAscii("\n");
1130 aSubTitle.Append(*pSubTitle);
1131 mxSrcLink->AppendString(aSubTitle);
1134 ConvertFontBase( GetChRoot(), nFontIdx );
1136 // rotation
1137 ConvertRotationBase( GetChRoot(), aTitleProp, true );
1139 else
1141 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1145 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1147 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1148 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1149 ConvertFontBase( GetChRoot(), rPropSet );
1152 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1153 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1155 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
1157 namespace cssc = ::com::sun::star::chart2;
1158 cssc::DataPointLabel aPointLabel;
1159 if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1160 return false;
1162 // percentage only allowed in pie and donut charts
1163 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1164 // bubble sizes only allowed in bubble charts
1165 bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
1166 DBG_ASSERT( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1168 // raw show flags
1169 bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1170 bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
1171 bool bShowCateg = aPointLabel.ShowCategoryName;
1172 bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1173 bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
1175 // create the CHFRLABELPROPS record for extended settings in BIFF8
1176 if( bShowAny && (GetBiff() == EXC_BIFF8) )
1178 mxLabelProps.reset( new XclExpChFrLabelProps( GetChRoot() ) );
1179 mxLabelProps->Convert( rPropSet, false, bShowCateg, bShowValue, bShowPercent, bShowBubble );
1182 // restrict to combinations allowed in CHTEXT
1183 if( bShowPercent ) bShowValue = false; // percent wins over value
1184 if( bShowValue ) bShowCateg = false; // value wins over category
1185 if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
1187 // set all flags
1188 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1189 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1190 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1191 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1192 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1193 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
1194 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
1195 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1197 if( bShowAny )
1199 // font settings
1200 ConvertFontBase( GetChRoot(), rPropSet );
1201 ConvertRotationBase( GetChRoot(), rPropSet, false );
1202 // label placement
1203 sal_Int32 nPlacement = 0;
1204 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1206 using namespace ::com::sun::star::chart::DataLabelPlacement;
1207 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1209 maData.mnPlacement = EXC_CHTEXT_POS_DEFAULT;
1211 else switch( nPlacement )
1213 case AVOID_OVERLAP: maData.mnPlacement = EXC_CHTEXT_POS_AUTO; break;
1214 case CENTER: maData.mnPlacement = EXC_CHTEXT_POS_CENTER; break;
1215 case TOP: maData.mnPlacement = EXC_CHTEXT_POS_ABOVE; break;
1216 case TOP_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1217 case LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1218 case BOTTOM_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1219 case BOTTOM: maData.mnPlacement = EXC_CHTEXT_POS_BELOW; break;
1220 case BOTTOM_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1221 case RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1222 case TOP_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1223 case INSIDE: maData.mnPlacement = EXC_CHTEXT_POS_INSIDE; break;
1224 case OUTSIDE: maData.mnPlacement = EXC_CHTEXT_POS_OUTSIDE; break;
1225 case NEAR_ORIGIN: maData.mnPlacement = EXC_CHTEXT_POS_AXIS; break;
1226 default: DBG_ERRORFILE( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1229 // source link (contains number format)
1230 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1231 if( bShowValue || bShowPercent )
1232 // percentage format wins over value format
1233 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1234 // object link
1235 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1238 /* Return true to indicate valid label settings:
1239 - for existing labels at entire series
1240 - for any settings at single data point (to be able to delete a point label) */
1241 return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
1244 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1246 // required flags
1247 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1248 if( GetBiff() == EXC_BIFF8 )
1249 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1250 // frame formatting
1251 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1252 // font settings
1253 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1254 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1255 ConvertFontBase( GetChRoot(), rPropSet );
1256 // source link (contains number format)
1257 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1258 mxSrcLink->ConvertNumFmt( rPropSet, false );
1259 // object link
1260 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1263 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1265 sal_uInt16 nFlags = 0;
1266 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1267 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1268 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1269 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1270 return nFlags;
1273 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1275 // CHFONT record
1276 lclSaveRecord( rStrm, mxFont );
1277 // CHSOURCELINK group
1278 lclSaveRecord( rStrm, mxSrcLink );
1279 // CHFRAME group
1280 lclSaveRecord( rStrm, mxFrame );
1281 // CHOBJECTLINK record
1282 lclSaveRecord( rStrm, mxObjLink );
1283 // CHFRLABELPROPS record
1284 lclSaveRecord( rStrm, mxLabelProps );
1287 void XclExpChText::WriteBody( XclExpStream& rStrm )
1289 rStrm << maData.mnHAlign
1290 << maData.mnVAlign
1291 << maData.mnBackMode
1292 << maData.maTextColor
1293 << maData.maRect
1294 << maData.mnFlags;
1296 if( GetBiff() == EXC_BIFF8 )
1298 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1299 << maData.mnPlacement
1300 << maData.mnRotation;
1304 // ----------------------------------------------------------------------------
1306 namespace {
1308 /** Creates and returns an Excel text object from the passed title. */
1309 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
1310 const String* pSubTitle = NULL )
1312 Reference< XTitle > xTitle;
1313 if( xTitled.is() )
1314 xTitle = xTitled->getTitleObject();
1316 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1317 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1318 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1319 will be interpreted as auto-generated title showing the series title in
1320 charts that contain exactly one data series. */
1321 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1322 xText.reset();
1324 return xText;
1329 // Data series ================================================================
1331 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1332 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1333 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1334 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1338 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1339 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1341 rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1342 /* Set marker line/fill color to series line color.
1343 TODO: remove this if OOChart supports own colors in markers. */
1344 Color aLineColor;
1345 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1346 maData.maLineColor = maData.maFillColor = aLineColor;
1347 // register colors in palette
1348 RegisterColors( rRoot );
1351 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1352 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1354 // clear the automatic flag
1355 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1356 // symbol type and color
1357 if( bCloseSymbol )
1359 // set symbol type for the 'close' data series
1360 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1361 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1362 // set symbol line/fill color to series line color
1363 Color aLineColor;
1364 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1366 maData.maLineColor = maData.maFillColor = aLineColor;
1367 RegisterColors( rRoot );
1370 else
1372 // set invisible symbol
1373 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1377 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1379 if( HasMarker() )
1381 if( HasLineColor() )
1382 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1383 if( HasFillColor() )
1384 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1388 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1390 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1391 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1393 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1394 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1398 // ----------------------------------------------------------------------------
1400 XclExpChPieFormat::XclExpChPieFormat() :
1401 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1405 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1407 double fApiDist(0.0);
1408 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1409 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1412 // ----------------------------------------------------------------------------
1414 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1415 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1419 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1421 sal_Int32 nApiType(0);
1422 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1424 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1425 switch( nApiType )
1427 case CUBOID:
1428 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1429 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1430 break;
1431 case PYRAMID:
1432 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1433 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1434 break;
1435 case CYLINDER:
1436 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1437 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1438 break;
1439 case CONE:
1440 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1441 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1442 break;
1443 default:
1444 DBG_ERRORFILE( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1449 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1451 rStrm << maData.mnBase << maData.mnTop;
1454 // ----------------------------------------------------------------------------
1456 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1457 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1461 // ----------------------------------------------------------------------------
1463 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1464 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1465 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
1467 maData.maPointPos = rPointPos;
1468 maData.mnFormatIdx = nFormatIdx;
1471 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1473 // line and area formatting
1474 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1476 // data point symbols
1477 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1478 if( !bIsFrame )
1480 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1481 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1484 // pie segments
1485 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1487 mxPieFmt.reset( new XclExpChPieFormat );
1488 mxPieFmt->Convert( rPropSet );
1491 // 3D bars (only allowed for entire series in BIFF8)
1492 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1494 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1495 mx3dDataFmt->Convert( rPropSet );
1498 // spline
1499 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1500 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1502 // data point labels
1503 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1504 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1506 // CHTEXT groups for data labels are stored in global CHCHART group
1507 GetChartData().SetDataLabel( xLabel );
1508 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1512 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1514 // set line format to invisible
1515 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1516 // set symbols to invisible or to 'close' series symbol
1517 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1518 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1521 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1523 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1526 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1528 lclSaveRecord( rStrm, mx3dDataFmt );
1529 WriteFrameRecords( rStrm );
1530 lclSaveRecord( rStrm, mxPieFmt );
1531 lclSaveRecord( rStrm, mxMarkerFmt );
1532 lclSaveRecord( rStrm, mxSeriesFmt );
1533 lclSaveRecord( rStrm, mxAttLabel );
1536 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1538 rStrm << maData.maPointPos.mnPointIdx
1539 << maData.maPointPos.mnSeriesIdx
1540 << maData.mnFormatIdx
1541 << maData.mnFlags;
1544 // ----------------------------------------------------------------------------
1546 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1547 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1548 XclExpChRoot( rRoot )
1552 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1554 if( !xRegCurve.is() )
1555 return false;
1557 // trend line type
1558 ScfPropertySet aCurveProp( xRegCurve );
1559 OUString aService = aCurveProp.GetServiceName();
1560 if( aService == SERVICE_CHART2_LINEARREGCURVE )
1562 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1563 maData.mnOrder = 1;
1565 else if( aService == SERVICE_CHART2_EXPREGCURVE )
1566 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1567 else if( aService == SERVICE_CHART2_LOGREGCURVE )
1568 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1569 else if( aService == SERVICE_CHART2_POTREGCURVE )
1570 maData.mnLineType = EXC_CHSERTREND_POWER;
1571 else
1572 return false;
1574 // line formatting
1575 XclChDataPointPos aPointPos( nSeriesIdx );
1576 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1577 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1579 // #i83100# show equation and correlation coefficient
1580 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1581 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1582 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1584 // #i83100# formatting of the equation text box
1585 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1587 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1588 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1591 // missing features
1592 // #i20819# polynomial trend lines
1593 // #i66819# moving average trend lines
1594 // #i5085# manual trend line size
1595 // #i34093# manual crossing point
1596 return true;
1599 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1601 rStrm << maData.mnLineType
1602 << maData.mnOrder
1603 << maData.mfIntercept
1604 << maData.mnShowEquation
1605 << maData.mnShowRSquared
1606 << maData.mfForecastFor
1607 << maData.mfForecastBack;
1610 // ----------------------------------------------------------------------------
1612 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1613 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1614 XclExpChRoot( rRoot )
1616 maData.mnBarType = nBarType;
1619 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1621 sal_Int32 nBarStyle = 0;
1622 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1623 if( bOk )
1625 namespace cssc = ::com::sun::star::chart;
1626 switch( nBarStyle )
1628 case cssc::ErrorBarStyle::ABSOLUTE:
1629 maData.mnSourceType = EXC_CHSERERR_FIXED;
1630 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1631 break;
1632 case cssc::ErrorBarStyle::RELATIVE:
1633 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1634 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1635 break;
1636 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1637 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1638 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1639 break;
1640 case cssc::ErrorBarStyle::STANDARD_ERROR:
1641 maData.mnSourceType = EXC_CHSERERR_STDERR;
1642 break;
1643 case cssc::ErrorBarStyle::FROM_DATA:
1645 bOk = false;
1646 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1647 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1648 if( xDataSource.is() )
1650 // find first sequence with current role
1651 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1652 Reference< XDataSequence > xValueSeq;
1654 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1655 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1656 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1657 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1659 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1660 ScfPropertySet aValueProp( xTmpValueSeq );
1661 OUString aCurrRole;
1662 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1663 xValueSeq = xTmpValueSeq;
1665 if( xValueSeq.is() )
1667 // #i86465# pass value count back to series
1668 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1669 bOk = maData.mnValueCount > 0;
1673 break;
1674 default:
1675 bOk = false;
1678 return bOk;
1681 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1683 rStrm << maData.mnBarType
1684 << maData.mnSourceType
1685 << maData.mnLineEnd
1686 << sal_uInt8( 1 ) // must be 1 to make line visible
1687 << maData.mfValue
1688 << maData.mnValueCount;
1691 // ----------------------------------------------------------------------------
1693 namespace {
1695 /** Returns the property set of the specified data point. */
1696 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1698 ScfPropertySet aPropSet;
1701 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1703 catch( Exception& )
1705 DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1707 return aPropSet;
1710 } // namespace
1712 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1713 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1714 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1715 mnSeriesIdx( nSeriesIdx ),
1716 mnParentIdx( EXC_CHSERIES_INVALID )
1718 // CHSOURCELINK records are always required, even if unused
1719 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1720 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1721 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1722 if( GetBiff() == EXC_BIFF8 )
1723 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1726 bool XclExpChSeries::ConvertDataSeries(
1727 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1728 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1730 bool bOk = false;
1731 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1732 if( xDataSource.is() )
1734 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
1736 // find first sequence with role 'values-y'
1737 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1738 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1739 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1740 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1742 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1743 ScfPropertySet aValueProp( xTmpValueSeq );
1744 OUString aRole;
1745 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1747 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1749 xYValueSeq = xTmpValueSeq;
1750 if( !xTitleSeq.is() )
1751 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1753 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1755 xXValueSeq = xTmpValueSeq;
1757 else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES) )
1759 xBubbleSeq = xTmpValueSeq;
1760 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1765 bOk = xYValueSeq.is();
1766 if( bOk )
1768 // chart type group index
1769 mnGroupIdx = nGroupIdx;
1771 // convert source links
1772 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1773 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1775 // X values of XY charts
1776 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1778 // size values of bubble charts
1779 if( mxBubbleLink.is() )
1780 mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
1782 // series formatting
1783 XclChDataPointPos aPointPos( mnSeriesIdx );
1784 ScfPropertySet aSeriesProp( xDataSeries );
1785 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1786 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1788 // trend lines
1789 CreateTrendLines( xDataSeries );
1791 // error bars
1792 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1793 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1795 if( maData.mnValueCount > 0 )
1797 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1799 /* #i91063# Create missing fill properties in pie/doughnut charts.
1800 If freshly created (never saved to ODF), these charts show
1801 varying point colors but do not return these points via API. */
1802 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1804 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1805 if( xColorScheme.is() )
1807 const OUString aFillStyleName = CREATE_OUSTRING( "FillStyle" );
1808 const OUString aColorName = CREATE_OUSTRING( "Color" );
1809 namespace cssd = ::com::sun::star::drawing;
1810 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1812 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1813 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1814 // test that the point fill style is solid, but no color is set
1815 cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
1816 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1817 (eFillStyle == cssd::FillStyle_SOLID) &&
1818 !aPointProp.HasProperty( aColorName ) )
1820 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1826 // data point formatting
1827 Sequence< sal_Int32 > aPointIndexes;
1828 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1830 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1831 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1832 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1834 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1835 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1836 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1837 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1838 maPointFmts.AppendRecord( xPointFmt );
1844 return bOk;
1847 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1848 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1850 bool bOk = false;
1851 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1852 if( xDataSource.is() )
1854 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1856 // find first sequence with passed role
1857 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1858 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1859 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1860 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1862 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1863 ScfPropertySet aValueProp( xTmpValueSeq );
1864 OUString aRole;
1865 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
1867 xYValueSeq = xTmpValueSeq;
1868 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1872 bOk = xYValueSeq.is();
1873 if( bOk )
1875 // chart type group index
1876 mnGroupIdx = nGroupIdx;
1877 // convert source links
1878 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1879 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1880 // series formatting
1881 ScfPropertySet aSeriesProp( xDataSeries );
1882 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
1883 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
1886 return bOk;
1889 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
1891 InitFromParent( rParent );
1892 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
1893 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
1894 if( bOk )
1896 mxSeriesFmt = mxTrendLine->GetDataFormat();
1897 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
1899 return bOk;
1902 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
1904 InitFromParent( rParent );
1905 // error bar settings
1906 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
1907 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
1908 if( bOk )
1910 // error bar formatting
1911 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
1912 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
1914 return bOk;
1917 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
1919 if( xCategSeq.is() )
1920 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
1923 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
1925 lclSaveRecord( rStrm, mxTitleLink );
1926 lclSaveRecord( rStrm, mxValueLink );
1927 lclSaveRecord( rStrm, mxCategLink );
1928 lclSaveRecord( rStrm, mxBubbleLink );
1929 lclSaveRecord( rStrm, mxSeriesFmt );
1930 maPointFmts.Save( rStrm );
1931 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
1932 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
1933 if( mnParentIdx != EXC_CHSERIES_INVALID )
1934 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
1935 lclSaveRecord( rStrm, mxTrendLine );
1936 lclSaveRecord( rStrm, mxErrorBar );
1939 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
1941 // index to parent series is stored 1-based
1942 mnParentIdx = rParent.mnSeriesIdx + 1;
1943 /* #i86465# MSO2007 SP1 expects correct point counts in child series
1944 (there was no problem in Excel2003 or Excel2007 without SP1...) */
1945 maData.mnCategCount = rParent.maData.mnCategCount;
1946 maData.mnValueCount = rParent.maData.mnValueCount;
1949 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
1951 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
1952 if( xRegCurveCont.is() )
1954 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
1955 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
1956 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
1957 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
1959 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1960 if( xSeries.is() && !xSeries->ConvertTrendLine( *this, *pIt ) )
1961 GetChartData().RemoveLastSeries();
1966 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
1967 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
1969 Reference< XPropertySet > xErrorBar;
1970 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
1972 ScfPropertySet aErrorProp( xErrorBar );
1973 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
1974 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
1978 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
1979 const OUString& rShowPropName, sal_uInt8 nBarId )
1981 if( rPropSet.GetBoolProperty( rShowPropName ) )
1983 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1984 if( xSeries.is() && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
1985 GetChartData().RemoveLastSeries();
1989 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
1991 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
1992 if( GetBiff() == EXC_BIFF8 )
1993 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
1996 // Chart type groups ==========================================================
1998 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
1999 XclExpRecord( EXC_ID_CHUNKNOWN ),
2000 XclExpChRoot( rRoot ),
2001 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2005 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2006 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
2008 if( xChartType.is() )
2010 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
2011 // special handling for some chart types
2012 switch( maTypeInfo.meTypeCateg )
2014 case EXC_CHTYPECATEG_BAR:
2016 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
2017 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
2018 ScfPropertySet aTypeProp( xChartType );
2019 Sequence< sal_Int32 > aInt32Seq;
2020 maData.mnOverlap = 0;
2021 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2022 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
2023 maData.mnGap = 150;
2024 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2025 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
2027 break;
2028 case EXC_CHTYPECATEG_RADAR:
2029 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
2030 break;
2031 case EXC_CHTYPECATEG_PIE:
2033 ScfPropertySet aTypeProp( xChartType );
2034 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
2035 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2036 maData.mnPieHole = bDonut ? 50 : 0;
2037 // #i85166# starting angle of first pie slice
2038 ScfPropertySet aDiaProp( xDiagram );
2039 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
2041 break;
2042 case EXC_CHTYPECATEG_SCATTER:
2043 if( GetBiff() == EXC_BIFF8 )
2044 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
2045 break;
2046 default:;
2048 SetRecId( maTypeInfo.mnRecId );
2052 void XclExpChType::SetStacked( bool bPercent )
2054 switch( maTypeInfo.meTypeCateg )
2056 case EXC_CHTYPECATEG_LINE:
2057 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
2058 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
2059 break;
2060 case EXC_CHTYPECATEG_BAR:
2061 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
2062 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
2063 maData.mnOverlap = -100;
2064 break;
2065 default:;
2069 void XclExpChType::WriteBody( XclExpStream& rStrm )
2071 switch( GetRecId() )
2073 case EXC_ID_CHBAR:
2074 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
2075 break;
2077 case EXC_ID_CHLINE:
2078 case EXC_ID_CHAREA:
2079 case EXC_ID_CHRADARLINE:
2080 case EXC_ID_CHRADARAREA:
2081 rStrm << maData.mnFlags;
2082 break;
2084 case EXC_ID_CHPIE:
2085 rStrm << maData.mnRotation << maData.mnPieHole;
2086 if( GetBiff() == EXC_BIFF8 )
2087 rStrm << maData.mnFlags;
2088 break;
2090 case EXC_ID_CHSCATTER:
2091 if( GetBiff() == EXC_BIFF8 )
2092 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
2093 break;
2095 default:
2096 DBG_ERRORFILE( "XclExpChType::WriteBody - unknown chart type" );
2100 // ----------------------------------------------------------------------------
2102 XclExpChChart3d::XclExpChChart3d() :
2103 XclExpRecord( EXC_ID_CHCHART3D, 14 )
2107 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
2109 sal_Int32 nRotationY = 0;
2110 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
2111 sal_Int32 nRotationX = 0;
2112 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
2113 sal_Int32 nPerspective = 15;
2114 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
2116 if( b3dWallChart )
2118 // Y rotation (Excel [0..359], Chart2 [-179,180])
2119 if( nRotationY < 0 ) nRotationY += 360;
2120 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
2121 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2122 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
2123 // perspective (Excel and Chart2 [0,100])
2124 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2125 // flags
2126 maData.mnFlags = 0;
2127 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
2128 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
2129 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
2131 else
2133 // Y rotation not used in pie charts, but 'first pie slice angle'
2134 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
2135 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2136 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
2137 // perspective (Excel and Chart2 [0,100])
2138 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2139 // flags
2140 maData.mnFlags = 0;
2144 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
2146 rStrm << maData.mnRotation
2147 << maData.mnElevation
2148 << maData.mnEyeDist
2149 << maData.mnRelHeight
2150 << maData.mnRelDepth
2151 << maData.mnDepthGap
2152 << maData.mnFlags;
2155 // ----------------------------------------------------------------------------
2157 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2158 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
2162 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2164 // frame properties
2165 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2166 // text properties
2167 mxText.reset( new XclExpChText( GetChRoot() ) );
2168 mxText->ConvertLegend( rPropSet );
2169 // special legend properties
2170 GetChartPropSetHelper().ReadLegendProperties( maData, rPropSet );
2173 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2175 lclSaveRecord( rStrm, mxText );
2176 lclSaveRecord( rStrm, mxFrame );
2179 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2181 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2184 // ----------------------------------------------------------------------------
2186 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
2187 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
2188 meObjType( eObjType ),
2189 mnBarDist( 100 )
2193 void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
2195 if( rPropSet.Is() )
2196 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
2197 else
2198 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
2201 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2203 WriteFrameRecords( rStrm );
2206 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2208 rStrm << mnBarDist;
2211 // ----------------------------------------------------------------------------
2213 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2214 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
2215 maType( rRoot ),
2216 maTypeInfo( maType.GetTypeInfo() )
2218 maData.mnGroupIdx = nGroupIdx;
2221 void XclExpChTypeGroup::ConvertType(
2222 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2223 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2225 // chart type settings
2226 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2228 // spline - TODO: get from single series (#i66858#)
2229 ScfPropertySet aTypeProp( xChartType );
2230 ::com::sun::star::chart2::CurveStyle eCurveStyle;
2231 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2232 (eCurveStyle != ::com::sun::star::chart2::CurveStyle_LINES);
2234 // extended type info
2235 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2237 // 3d chart settings
2238 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2240 mxChart3d.reset( new XclExpChChart3d );
2241 ScfPropertySet aDiaProp( xDiagram );
2242 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2246 void XclExpChTypeGroup::ConvertSeries(
2247 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2248 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2250 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2251 if( xSeriesCont.is() )
2253 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2254 XDataSeriesVec aSeriesVec;
2256 // copy data series attached to the current axes set to the vector
2257 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2258 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2259 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2260 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2262 ScfPropertySet aSeriesProp( *pIt );
2263 sal_Int32 nSeriesAxesSetIdx(0);
2264 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2265 aSeriesVec.push_back( *pIt );
2268 // Are there any series in the current axes set?
2269 if( !aSeriesVec.empty() )
2271 // stacking direction (stacked/percent/deep 3d) from first series
2272 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2273 namespace cssc = ::com::sun::star::chart2;
2274 cssc::StackingDirection eStacking;
2275 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2276 eStacking = cssc::StackingDirection_NO_STACKING;
2278 // stacked or percent chart
2279 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc::StackingDirection_Y_STACKING) )
2281 // percent overrides simple stacking
2282 maType.SetStacked( bPercent );
2284 // connected data points (only in stacked bar charts)
2285 if( bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
2286 maChartLines[ EXC_CHCHARTLINE_CONNECT ].reset( new XclExpChLineFormat( GetChRoot() ) );
2288 else
2290 // reverse series order for some unstacked 2D chart types
2291 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2292 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2295 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2296 if( (eStacking == cssc::StackingDirection_NO_STACKING) && Is3dWallChart() )
2297 mxChart3d->SetClustered();
2299 // varied point colors
2300 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2302 // process all series
2303 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2305 // create Excel series object, stock charts need special processing
2306 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2307 CreateAllStockSeries( xChartType, *aIt );
2308 else
2309 CreateDataSeries( xDiagram, *aIt );
2315 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2317 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2318 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2321 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2323 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2325 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2326 mxLegend->Convert( rPropSet );
2330 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2332 maType.Save( rStrm );
2333 lclSaveRecord( rStrm, mxChart3d );
2334 lclSaveRecord( rStrm, mxLegend );
2335 lclSaveRecord( rStrm, mxUpBar );
2336 lclSaveRecord( rStrm, mxDownBar );
2337 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2338 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2341 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2343 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2346 void XclExpChTypeGroup::CreateDataSeries(
2347 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2349 // let chart create series object with correct series index
2350 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2351 if( xSeries.is() )
2353 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2354 maSeries.AppendRecord( xSeries );
2355 else
2356 GetChartData().RemoveLastSeries();
2360 void XclExpChTypeGroup::CreateAllStockSeries(
2361 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2363 // create existing series objects
2364 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2365 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2366 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2367 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2369 // formatting of special stock chart elements
2370 ScfPropertySet aTypeProp( xChartType );
2371 // hi-lo lines
2372 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2374 ScfPropertySet aSeriesProp( xDataSeries );
2375 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2376 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2377 maChartLines[ EXC_CHCHARTLINE_HILO ] = xLineFmt;
2379 // dropbars
2380 if( bHasOpen && bHasClose )
2382 // dropbar type is dependent on position in the file - always create both
2383 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2384 // white dropbar format
2385 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2386 ScfPropertySet aWhiteProp( xWhitePropSet );
2387 mxUpBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ) );
2388 mxUpBar->Convert( aWhiteProp );
2389 // black dropbar format
2390 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2391 ScfPropertySet aBlackProp( xBlackPropSet );
2392 mxDownBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ) );
2393 mxDownBar->Convert( aBlackProp );
2397 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2398 const OUString& rValueRole, bool bCloseSymbol )
2400 bool bOk = false;
2401 // let chart create series object with correct series index
2402 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2403 if( xSeries.is() )
2405 bOk = xSeries->ConvertStockSeries( xDataSeries,
2406 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2407 if( bOk )
2408 maSeries.AppendRecord( xSeries );
2409 else
2410 GetChartData().RemoveLastSeries();
2412 return bOk;
2415 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2417 rStrm << maData.maRect << maData.mnFlags << maData.mnGroupIdx;
2420 // Axes =======================================================================
2422 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2423 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2424 XclExpChRoot( rRoot )
2428 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, bool bMirrorOrient )
2430 // origin
2431 double fOrigin = 0.0;
2432 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
2433 maData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
2435 // reverse order
2436 if( (rScaleData.Orientation == ::com::sun::star::chart2::AxisOrientation_REVERSE) != bMirrorOrient )
2437 ::set_flag( maData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2440 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2442 namespace cssc = ::com::sun::star::chart;
2443 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2444 rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION );
2445 double fCrossingPos = 1.0;
2446 rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE );
2447 switch( eAxisPos )
2449 case cssc::ChartAxisPosition_ZERO: maData.mnCross = 1; break;
2450 case cssc::ChartAxisPosition_START: maData.mnCross = 1; break;
2451 case cssc::ChartAxisPosition_END: ::set_flag( maData.mnFlags, EXC_CHLABELRANGE_MAXCROSS ); break;
2452 case cssc::ChartAxisPosition_VALUE: maData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 ); break;
2453 default: maData.mnCross = 1;
2457 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2459 rStrm << maData.mnCross << maData.mnLabelFreq << maData.mnTickFreq << maData.mnFlags;
2462 // ----------------------------------------------------------------------------
2464 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2465 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2466 XclExpChRoot( rRoot )
2470 void XclExpChValueRange::Convert( const ScaleData& rScaleData )
2472 // scaling algorithm
2473 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == SERVICE_CHART2_LOGSCALING;
2474 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2476 // min/max
2477 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
2478 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2479 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
2480 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2482 // origin
2483 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
2484 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2486 // major increment
2487 const IncrementData& rIncrementData = rScaleData.IncrementData;
2488 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
2489 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2490 // minor increment
2491 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2492 sal_Int32 nCount = 0;
2493 bool bAutoMinor = bLogScale || bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2494 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1);
2495 if( !bAutoMinor )
2496 maData.mfMinorStep = maData.mfMajorStep / nCount;
2497 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2499 // reverse order
2500 namespace cssc = ::com::sun::star::chart2;
2501 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc::AxisOrientation_REVERSE );
2504 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2506 namespace cssc = ::com::sun::star::chart;
2507 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2508 double fCrossingPos = 0.0;
2509 if( rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE ) )
2511 switch( eAxisPos )
2513 case cssc::ChartAxisPosition_ZERO:
2514 case cssc::ChartAxisPosition_START:
2515 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2516 break;
2517 case cssc::ChartAxisPosition_END:
2518 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2519 break;
2520 case cssc::ChartAxisPosition_VALUE:
2521 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
2522 maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
2523 break;
2524 default:
2525 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2530 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2532 rStrm << maData.mfMin
2533 << maData.mfMax
2534 << maData.mfMajorStep
2535 << maData.mfMinorStep
2536 << maData.mfCross
2537 << maData.mnFlags;
2540 // ----------------------------------------------------------------------------
2542 namespace {
2544 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2546 using namespace ::com::sun::star::chart2::TickmarkStyle;
2547 sal_uInt8 nXclTickPos = 0;
2548 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2549 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2550 return nXclTickPos;
2553 } // namespace
2555 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2556 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2557 XclExpChRoot( rRoot ),
2558 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2562 void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
2564 // tick mark style
2565 sal_Int32 nApiTickmarks = 0;
2566 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2567 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2568 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2569 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2571 // axis labels
2572 if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
2574 /* Radar charts disable their category labels via chart type, not via
2575 axis, and axis labels are always 'near axis'. */
2576 maData.mnLabelPos = EXC_CHTICK_NEXT;
2578 else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2580 // no labels
2581 maData.mnLabelPos = EXC_CHTICK_NOLABEL;
2583 else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
2585 // Excel expects 'near axis' at Y axes in 3D charts
2586 maData.mnLabelPos = EXC_CHTICK_NEXT;
2588 else
2590 namespace cssc = ::com::sun::star::chart;
2591 cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
2592 rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION );
2593 switch( eApiLabelPos )
2595 case cssc::ChartAxisLabelPosition_NEAR_AXIS:
2596 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
2597 case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
2598 case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
2599 default: maData.mnLabelPos = EXC_CHTICK_NEXT;
2604 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2606 maData.maTextColor = rColor;
2607 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2608 mnTextColorId = nColorId;
2611 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2613 maData.mnRotation = nRotation;
2614 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2615 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2618 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2620 rStrm << maData.mnMajor
2621 << maData.mnMinor
2622 << maData.mnLabelPos
2623 << maData.mnBackMode
2624 << maData.maRect
2625 << maData.maTextColor
2626 << maData.mnFlags;
2627 if( GetBiff() == EXC_BIFF8 )
2628 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2631 // ----------------------------------------------------------------------------
2633 namespace {
2635 /** Returns an API axis object from the passed coordinate system. */
2636 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2637 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2639 Reference< XAxis > xAxis;
2640 if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
2642 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2644 catch( Exception& )
2647 return xAxis;
2650 } // namespace
2652 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2653 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
2654 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2656 maData.mnType = nAxisType;
2659 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2661 mxFont = xFont;
2662 if( mxTick.is() )
2663 mxTick->SetFontColor( rColor, nColorId );
2666 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2668 if( mxTick.is() )
2669 mxTick->SetRotation( nRotation );
2672 void XclExpChAxis::Convert( Reference< XAxis > xAxis, Reference< XAxis > xCrossingAxis, const XclChExtTypeInfo& rTypeInfo )
2674 ScfPropertySet aAxisProp( xAxis );
2675 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2677 // axis line format -------------------------------------------------------
2679 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2680 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2681 // #i58688# axis enabled
2682 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2684 // axis scaling and increment ---------------------------------------------
2686 ScfPropertySet aCrossingProp( xCrossingAxis );
2687 if( bCategoryAxis )
2689 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2690 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2691 if( xAxis.is() )
2692 // #i71684# radar charts have reversed rotation direction
2693 mxLabelRange->Convert( xAxis->getScaleData(), (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2694 // get position of crossing axis on this axis from passed axis object
2695 if( aCrossingProp.Is() )
2696 mxLabelRange->ConvertAxisPosition( aCrossingProp );
2698 else
2700 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
2701 if( xAxis.is() )
2702 mxValueRange->Convert( xAxis->getScaleData() );
2703 // get position of crossing axis on this axis from passed axis object
2704 if( aCrossingProp.Is() )
2705 mxValueRange->ConvertAxisPosition( aCrossingProp );
2708 // axis caption text ------------------------------------------------------
2710 // axis ticks properties
2711 mxTick.reset( new XclExpChTick( GetChRoot() ) );
2712 mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
2714 // axis label formatting and rotation
2715 ConvertFontBase( GetChRoot(), aAxisProp );
2716 ConvertRotationBase( GetChRoot(), aAxisProp, true );
2718 // axis number format
2719 sal_Int32 nApiNumFmt = 0;
2720 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
2721 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
2723 // grid -------------------------------------------------------------------
2725 if( xAxis.is() )
2727 // main grid
2728 ScfPropertySet aGridProp( xAxis->getGridProperties() );
2729 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2730 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
2731 // sub grid
2732 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
2733 if( aSubGridPropSeq.hasElements() )
2735 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
2736 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2737 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
2742 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
2744 if( xDiagram.is() ) switch( GetAxisType() )
2746 case EXC_CHAXIS_X:
2748 ScfPropertySet aWallProp( xDiagram->getWall() );
2749 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
2751 break;
2752 case EXC_CHAXIS_Y:
2754 ScfPropertySet aFloorProp( xDiagram->getFloor() );
2755 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
2757 break;
2758 default:
2759 mxWallFrame.reset();
2763 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
2765 lclSaveRecord( rStrm, mxLabelRange );
2766 lclSaveRecord( rStrm, mxValueRange );
2767 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
2768 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
2769 lclSaveRecord( rStrm, mxTick );
2770 lclSaveRecord( rStrm, mxFont );
2771 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
2772 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
2773 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
2774 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
2777 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
2779 rStrm << maData.mnType << maData.maRect;
2782 // ----------------------------------------------------------------------------
2784 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
2785 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
2787 maData.mnAxesSetId = nAxesSetId;
2788 SetFutureRecordContext( 0, nAxesSetId );
2791 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
2793 /* First unused chart type group index is passed to be able to continue
2794 counting of chart type groups for secondary axes set. */
2795 sal_uInt16 nGroupIdx = nFirstGroupIdx;
2796 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
2797 if( xCoordSysCont.is() )
2799 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
2800 if( aCoordSysSeq.getLength() > 0 )
2802 /* Process first coordinate system only. Import filter puts all
2803 chart types into one coordinate system. */
2804 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
2805 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2807 // 3d mode
2808 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
2810 // percent charts
2811 namespace ApiAxisType = ::com::sun::star::chart2::AxisType;
2812 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
2813 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
2815 // connector lines in bar charts
2816 ScfPropertySet aDiaProp( xDiagram );
2817 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
2819 // swapped axes sets
2820 ScfPropertySet aCoordSysProp( xCoordSystem );
2821 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
2823 // X axis for later use
2824 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
2825 // X axis labels
2826 ScfPropertySet aXAxisProp( xApiXAxis );
2827 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
2829 // process chart types
2830 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
2831 if( xChartTypeCont.is() )
2833 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
2834 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
2835 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
2836 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
2838 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
2839 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
2840 /* If new chart type group cannot be inserted into a combination
2841 chart with existing type groups, insert all series into last
2842 contained chart type group instead of creating a new group. */
2843 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
2844 if( xLastGroup.is() && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
2846 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2848 else
2850 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2851 if( xTypeGroup->IsValidGroup() )
2853 maTypeGroups.AppendRecord( xTypeGroup );
2854 ++nGroupIdx;
2860 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
2862 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
2864 // create axes according to chart type (no axes for pie and donut charts)
2865 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
2867 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
2868 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
2869 if( pGroup->Is3dDeepChart() )
2870 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
2873 // X axis category ranges
2874 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
2876 const ScaleData aScaleData = xApiXAxis->getScaleData();
2877 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
2878 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
2881 // legend
2882 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2884 Reference< XLegend > xLegend = xDiagram->getLegend();
2885 if( xLegend.is() )
2887 ScfPropertySet aLegendProp( xLegend );
2888 pGroup->ConvertLegend( aLegendProp );
2895 // wall/floor/diagram frame formatting
2896 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2898 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2899 if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
2901 // wall/floor formatting (3D charts)
2902 if( mxXAxis.is() )
2903 mxXAxis->ConvertWall( xDiagram );
2904 if( mxYAxis.is() )
2905 mxYAxis->ConvertWall( xDiagram );
2907 else
2909 // diagram background formatting
2910 ScfPropertySet aWallProp( xDiagram->getWall() );
2911 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
2915 // return first unused chart type group index for next axes set
2916 return nGroupIdx;
2919 bool XclExpChAxesSet::Is3dChart() const
2921 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2922 return xTypeGroup.is() && xTypeGroup->Is3dChart();
2925 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
2927 lclSaveRecord( rStrm, mxXAxis );
2928 lclSaveRecord( rStrm, mxYAxis );
2929 lclSaveRecord( rStrm, mxZAxis );
2930 lclSaveRecord( rStrm, mxXAxisTitle );
2931 lclSaveRecord( rStrm, mxYAxisTitle );
2932 lclSaveRecord( rStrm, mxZAxisTitle );
2933 if( mxPlotFrame.is() )
2935 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
2936 mxPlotFrame->Save( rStrm );
2938 maTypeGroups.Save( rStrm );
2941 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
2943 return maTypeGroups.GetFirstRecord();
2946 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
2948 return maTypeGroups.GetLastRecord();
2951 void XclExpChAxesSet::ConvertAxis(
2952 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
2953 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
2954 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
2955 sal_Int32 nCrossingAxisDim )
2957 // create and convert axis object
2958 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
2959 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
2960 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2961 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
2962 Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
2963 rxChAxis->Convert( xAxis, xCrossingAxis, rTypeInfo );
2965 // create and convert axis title
2966 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
2967 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
2970 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
2972 rStrm << maData.mnAxesSetId << maData.maRect;
2975 // The chart object ===========================================================
2977 static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
2978 String& rSubTitle)
2980 Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
2981 if (!xChartDoc1.is())
2982 return;
2984 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
2985 if (!xProp.is())
2986 return;
2988 OUString aTitle;
2989 Any any = xProp->getPropertyValue( OUString::createFromAscii("String") );
2990 if (any >>= aTitle)
2991 rSubTitle = aTitle;
2994 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
2995 Reference< XChartDocument > xChartDoc, const Size& rSize ) :
2996 XclExpChGroupBase( XclExpChRoot( rRoot, this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
2998 Size aPtSize = OutputDevice::LogicToLogic( rSize, MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
2999 // rectangle is stored in 16.16 fixed-point format
3000 maRect.mnX = maRect.mnY = 0;
3001 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
3002 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
3004 // global chart properties (default values)
3005 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANSERIES );
3006 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
3007 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
3009 // always create both axes set objects
3010 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3011 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3013 if( xChartDoc.is() )
3015 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
3017 // global chart properties (only 'include hidden cells' attribute for now)
3018 ScfPropertySet aDiagramProp( xDiagram );
3019 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
3020 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
3022 // initialize API conversion (remembers xChartDoc internally)
3023 InitConversion( xChartDoc );
3025 // chart frame
3026 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3027 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
3029 // chart title
3030 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3031 String aSubTitle;
3032 lcl_getChartSubTitle(xChartDoc, aSubTitle);
3033 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
3034 aSubTitle.Len() ? &aSubTitle : NULL );
3036 // diagrams (axes sets)
3037 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
3038 if( !mxPrimAxesSet->Is3dChart() )
3039 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
3041 // treatment of missing values
3042 ScfPropertySet aDiaProp( xDiagram );
3043 sal_Int32 nMissingValues = 0;
3044 if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT ) )
3046 using namespace ::com::sun::star::chart::MissingValueTreatment;
3047 switch( nMissingValues )
3049 case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
3050 case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
3051 case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
3055 // finish API conversion
3056 FinishConversion();
3060 XclExpChSeriesRef XclExpChChart::CreateSeries()
3062 XclExpChSeriesRef xSeries;
3063 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
3064 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3066 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
3067 maSeries.AppendRecord( xSeries );
3069 return xSeries;
3072 void XclExpChChart::RemoveLastSeries()
3074 if( !maSeries.IsEmpty() )
3075 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
3078 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
3080 if( xText.is() )
3081 maLabels.AppendRecord( xText );
3084 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
3086 // background format
3087 lclSaveRecord( rStrm, mxFrame );
3089 // data series
3090 maSeries.Save( rStrm );
3092 // CHPROPERTIES record
3093 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
3094 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
3095 rStrm.EndRecord();
3097 // axes sets (always save primary axes set)
3098 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
3099 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
3100 mxPrimAxesSet->Save( rStrm );
3101 if( mxSecnAxesSet->IsValidAxesSet() )
3102 mxSecnAxesSet->Save( rStrm );
3104 // chart title and data labels
3105 lclSaveRecord( rStrm, mxTitle );
3106 maLabels.Save( rStrm );
3109 void XclExpChChart::WriteBody( XclExpStream& rStrm )
3111 rStrm << maRect;
3114 // ----------------------------------------------------------------------------
3116 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Size& rSize ) :
3117 XclExpSubStream( EXC_BOF_CHART ),
3118 XclExpRoot( rRoot )
3120 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
3121 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
3122 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
3124 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3125 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rSize ) );
3128 // ============================================================================