update dev300-m58
[ooovba.git] / sc / source / filter / excel / xichart.cxx
blob41ec8012a5acb1408f5750cecc5898e8f4de6fa6
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: xichart.cxx,v $
10 * $Revision: 1.20.62.14 $
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 "xichart.hxx"
36 #include <algorithm>
37 #include <memory>
39 #include <com/sun/star/frame/XModel.hpp>
40 #include <com/sun/star/drawing/Direction3D.hpp>
41 #include <com/sun/star/drawing/ProjectionMode.hpp>
42 #include <com/sun/star/drawing/ShadeMode.hpp>
43 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
44 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
45 #include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
46 #include <com/sun/star/chart/ChartAxisPosition.hpp>
47 #include <com/sun/star/chart/XChartDocument.hpp>
48 #include <com/sun/star/chart2/XChartDocument.hpp>
49 #include <com/sun/star/chart2/XDiagram.hpp>
50 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
51 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
52 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
53 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
54 #include <com/sun/star/chart2/XTitled.hpp>
55 #include <com/sun/star/chart2/data/XDataProvider.hpp>
56 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
57 #include <com/sun/star/chart2/data/XDataSink.hpp>
58 #include <com/sun/star/chart2/AxisType.hpp>
59 #include <com/sun/star/chart2/CurveStyle.hpp>
60 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
61 #include <com/sun/star/chart2/DataPointLabel.hpp>
62 #include <com/sun/star/chart2/StackingDirection.hpp>
63 #include <com/sun/star/chart2/TickmarkStyle.hpp>
64 #include <com/sun/star/chart/DataLabelPlacement.hpp>
65 #include <com/sun/star/chart/ErrorBarStyle.hpp>
66 #include <com/sun/star/chart/MissingValueTreatment.hpp>
68 #include <sfx2/objsh.hxx>
70 #include "document.hxx"
71 #include "drwlayer.hxx"
72 #include "rangeutl.hxx"
73 #include "tokenarray.hxx"
74 #include "token.hxx"
75 #include "compiler.hxx"
76 #include "reftokenhelper.hxx"
77 #include "chartlis.hxx"
78 #include "fprogressbar.hxx"
79 #include "xltracer.hxx"
80 #include "xistream.hxx"
81 #include "xiformula.hxx"
82 #include "xistyle.hxx"
83 #include "xipage.hxx"
84 #include "xiview.hxx"
85 #include "xiescher.hxx"
87 using ::rtl::OUString;
88 using ::rtl::OUStringBuffer;
89 using ::com::sun::star::uno::Any;
90 using ::com::sun::star::uno::Reference;
91 using ::com::sun::star::uno::Sequence;
92 using ::com::sun::star::uno::UNO_QUERY;
93 using ::com::sun::star::uno::UNO_QUERY_THROW;
94 using ::com::sun::star::uno::Exception;
95 using ::com::sun::star::beans::XPropertySet;
96 using ::com::sun::star::lang::XMultiServiceFactory;
97 using ::com::sun::star::frame::XModel;
98 using ::com::sun::star::util::XNumberFormatsSupplier;
100 using ::com::sun::star::chart2::XChartDocument;
101 using ::com::sun::star::chart2::XDiagram;
102 using ::com::sun::star::chart2::XCoordinateSystemContainer;
103 using ::com::sun::star::chart2::XCoordinateSystem;
104 using ::com::sun::star::chart2::XChartTypeContainer;
105 using ::com::sun::star::chart2::XChartType;
106 using ::com::sun::star::chart2::XDataSeriesContainer;
107 using ::com::sun::star::chart2::XDataSeries;
108 using ::com::sun::star::chart2::XRegressionCurve;
109 using ::com::sun::star::chart2::XRegressionCurveContainer;
110 using ::com::sun::star::chart2::XAxis;
111 using ::com::sun::star::chart2::XScaling;
112 using ::com::sun::star::chart2::ScaleData;
113 using ::com::sun::star::chart2::IncrementData;
114 using ::com::sun::star::chart2::SubIncrement;
115 using ::com::sun::star::chart2::XLegend;
116 using ::com::sun::star::chart2::XTitled;
117 using ::com::sun::star::chart2::XTitle;
118 using ::com::sun::star::chart2::XFormattedString;
120 using ::com::sun::star::chart2::data::XDataProvider;
121 using ::com::sun::star::chart2::data::XDataReceiver;
122 using ::com::sun::star::chart2::data::XDataSink;
123 using ::com::sun::star::chart2::data::XLabeledDataSequence;
124 using ::com::sun::star::chart2::data::XDataSequence;
126 using ::formula::FormulaToken;
127 using ::formula::StackVar;
129 using ::std::vector;
131 // Helpers ====================================================================
133 namespace {
135 XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect )
137 return rStrm >> rRect.mnX >> rRect.mnY >> rRect.mnWidth >> rRect.mnHeight;
140 template< typename Type >
141 void lclSetValueOrClearAny( Any& rAny, const Type& rValue, bool bClear )
143 if( bClear )
144 rAny.clear();
145 else
146 rAny <<= rValue;
149 void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear )
151 if( !bClear && bLogScale )
152 fValue = pow( 10.0, fValue );
153 lclSetValueOrClearAny( rAny, fValue, bClear );
156 } // namespace
158 // Common =====================================================================
160 /** Stores global data needed in various classes of the Chart import filter. */
161 class XclImpChRootData : public XclChRootData
163 public:
164 explicit XclImpChRootData( XclImpChChart* pChartData );
166 /** Returns a reference to the parent chart data object. */
167 inline XclImpChChart& GetChartData() const { return *mpChartData; }
169 private:
170 XclImpChChart* mpChartData; /// Pointer to the chart data object.
173 XclImpChRootData::XclImpChRootData( XclImpChChart* pChartData ) :
174 mpChartData( pChartData )
178 // ----------------------------------------------------------------------------
180 XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart* pChartData ) :
181 XclImpRoot( rRoot ),
182 mxChData( new XclImpChRootData( pChartData ) )
186 XclImpChRoot::~XclImpChRoot()
190 XclImpChChart& XclImpChRoot::GetChartData() const
192 return mxChData->GetChartData();
195 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
197 return mxChData->GetTypeInfoProvider().GetTypeInfo( eType );
200 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const
202 return mxChData->GetTypeInfoProvider().GetTypeInfoFromRecId( nRecId );
205 const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
207 return mxChData->GetFormatInfoProvider().GetFormatInfo( eObjType );
210 Color XclImpChRoot::GetFontAutoColor() const
212 return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT );
215 Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const
217 return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) );
220 Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const
222 const XclImpPalette& rPal = GetPalette();
223 Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) );
224 sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx );
225 return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans );
228 void XclImpChRoot::InitConversion( Reference< XChartDocument > xChartDoc ) const
230 // create formatting object tables
231 mxChData->InitConversion( xChartDoc );
233 // lock the model to suppress any internal updates
234 Reference< XModel > xModel( xChartDoc, UNO_QUERY );
235 if( xModel.is() )
236 xModel->lockControllers();
238 SfxObjectShell* pDocShell = GetDocShell();
239 Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
240 if( pDocShell && xDataRec.is() )
242 // create and register a data provider
243 Reference< XDataProvider > xDataProv(
244 ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY );
245 if( xDataProv.is() )
246 xDataRec->attachDataProvider( xDataProv );
247 // attach the number formatter
248 Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY );
249 if( xNumFmtSupp.is() )
250 xDataRec->attachNumberFormatsSupplier( xNumFmtSupp );
254 void XclImpChRoot::FinishConversion( ScfProgressBar& rProgress ) const
256 rProgress.Progress( EXC_CHART_PROGRESS_SIZE );
257 // unlock the model
258 Reference< XModel > xModel( mxChData->GetChartDoc(), UNO_QUERY );
259 if( xModel.is() )
260 xModel->unlockControllers();
261 rProgress.Progress( EXC_CHART_PROGRESS_SIZE );
263 mxChData->FinishConversion();
266 Reference< XDataProvider > XclImpChRoot::GetDataProvider() const
268 return mxChData->GetChartDoc()->getDataProvider();
271 void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet,
272 const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const
274 GetChartPropSetHelper().WriteLineProperties(
275 rPropSet, mxChData->GetLineDashTable(), rLineFmt, ePropMode );
278 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet,
279 const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const
281 GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode );
284 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet,
285 const XclChEscherFormat& rEscherFmt, const XclChPicFormat& rPicFmt,
286 XclChPropertyMode ePropMode ) const
288 GetChartPropSetHelper().WriteEscherProperties( rPropSet,
289 mxChData->GetGradientTable(), mxChData->GetHatchTable(), mxChData->GetBitmapTable(),
290 rEscherFmt, rPicFmt, ePropMode );
293 void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet,
294 sal_uInt16 nFontIdx, const Color* pFontColor ) const
296 GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor );
299 void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle )
301 sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360;
302 rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot );
305 // ----------------------------------------------------------------------------
307 XclImpChGroupBase::~XclImpChGroupBase()
311 void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm )
313 // read contents of the header record
314 ReadHeaderRecord( rStrm );
316 // only read sub records, if the next record is a CHBEGIN
317 if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN )
319 // read the CHBEGIN record, may be used for special initial processing
320 rStrm.StartNextRecord();
321 ReadSubRecord( rStrm );
323 // read the nested records
324 bool bLoop = true;
325 while( bLoop && rStrm.StartNextRecord() )
327 sal_uInt16 nRecId = rStrm.GetRecId();
328 bLoop = nRecId != EXC_ID_CHEND;
329 // skip unsupported nested blocks
330 if( nRecId == EXC_ID_CHBEGIN )
331 SkipBlock( rStrm );
332 else
333 ReadSubRecord( rStrm );
336 /* Returns with current CHEND record or unchanged stream, if no record
337 group present. In every case another call to StartNextRecord() will go
338 to next record of interest. */
341 void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm )
343 DBG_ASSERT( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
344 // do nothing if current record is not CHBEGIN
345 bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN;
346 while( bLoop && rStrm.StartNextRecord() )
348 sal_uInt16 nRecId = rStrm.GetRecId();
349 bLoop = nRecId != EXC_ID_CHEND;
350 // skip nested record groups
351 if( nRecId == EXC_ID_CHBEGIN )
352 SkipBlock( rStrm );
356 // Frame formatting ===========================================================
358 void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm )
360 rStrm >> maData.mnObjType >> maData.mnSizeMode >> maData.maRect;
363 // ----------------------------------------------------------------------------
365 void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm )
367 rStrm >> maData.maColor >> maData.mnPattern >> maData.mnWeight >> maData.mnFlags;
369 const XclImpRoot& rRoot = rStrm.GetRoot();
370 if( rRoot.GetBiff() == EXC_BIFF8 )
371 // #116397# BIFF8: index into palette used instead of RGB data
372 maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() );
375 void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot,
376 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
378 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
379 if( IsAuto() )
381 XclChLineFormat aLineFmt;
382 aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ?
383 rRoot.GetSeriesLineAutoColor( nFormatIdx ) :
384 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx );
385 aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
386 aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight;
387 rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode );
389 else
391 rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode );
395 // ----------------------------------------------------------------------------
397 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm )
399 rStrm >> maData.maPattColor >> maData.maBackColor >> maData.mnPattern >> maData.mnFlags;
401 const XclImpRoot& rRoot = rStrm.GetRoot();
402 if( rRoot.GetBiff() == EXC_BIFF8 )
404 // #116397# BIFF8: index into palette used instead of RGB data
405 const XclImpPalette& rPal = rRoot.GetPalette();
406 maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() );
407 maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16());
411 void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot,
412 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
414 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
415 if( IsAuto() )
417 XclChAreaFormat aAreaFmt;
418 aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ?
419 rRoot.GetSeriesFillAutoColor( nFormatIdx ) :
420 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx );
421 aAreaFmt.mnPattern = EXC_PATT_SOLID;
422 rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode );
424 else
426 rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode );
430 // ----------------------------------------------------------------------------
432 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot )
434 maData.mxItemSet.reset(
435 new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) );
438 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm )
440 // read from stream - CHESCHERFORMAT uses own ID for record continuation
441 XclImpDffPropSet aPropSet( rStrm.GetRoot() );
442 rStrm.ResetRecord( true, rStrm.GetRecId() );
443 rStrm >> aPropSet;
444 // get the data
445 aPropSet.FillToItemSet( *maData.mxItemSet );
446 // get bitmap mode from DFF item set
447 sal_uInt32 nType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid );
448 maPicFmt.mnBmpMode = (nType == mso_fillPicture) ? EXC_CHPICFORMAT_STRETCH : EXC_CHPICFORMAT_STACK;
451 void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm )
453 switch( rStrm.GetRecId() )
455 case EXC_ID_CHPICFORMAT:
456 rStrm >> maPicFmt.mnBmpMode >> maPicFmt.mnFormat >> maPicFmt.mnFlags >> maPicFmt.mfScale;
457 break;
461 void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot,
462 ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
464 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
465 rRoot.ConvertEscherFormat( rPropSet, maData, maPicFmt, rFmtInfo.mePropMode );
468 // ----------------------------------------------------------------------------
470 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo )
472 if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType )
474 case EXC_CHFRAMETYPE_AUTO:
475 mxLineFmt.reset( new XclImpChLineFormat );
476 if( rFmtInfo.mbIsFrame )
477 mxAreaFmt.reset( new XclImpChAreaFormat );
478 break;
479 case EXC_CHFRAMETYPE_INVISIBLE:
481 XclChLineFormat aLineFmt;
482 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
483 aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
484 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
485 if( rFmtInfo.mbIsFrame )
487 XclChAreaFormat aAreaFmt;
488 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
489 aAreaFmt.mnPattern = EXC_PATT_NONE;
490 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
493 break;
494 default:
495 DBG_ERRORFILE( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
499 void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm )
501 switch( rStrm.GetRecId() )
503 case EXC_ID_CHLINEFORMAT:
504 mxLineFmt.reset( new XclImpChLineFormat );
505 mxLineFmt->ReadChLineFormat( rStrm );
506 break;
507 case EXC_ID_CHAREAFORMAT:
508 mxAreaFmt.reset( new XclImpChAreaFormat );
509 mxAreaFmt->ReadChAreaFormat( rStrm );
510 break;
511 case EXC_ID_CHESCHERFORMAT:
512 mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) );
513 mxEscherFmt->ReadRecordGroup( rStrm );
514 break;
518 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot,
519 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
521 if( mxLineFmt.is() )
522 mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
525 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot,
526 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
528 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
530 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
531 if( mxEscherFmt.is() )
532 mxEscherFmt->Convert( rRoot, rPropSet, eObjType );
533 else if( mxAreaFmt.is() )
534 mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
538 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot,
539 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
541 ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx );
542 ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx );
545 // ----------------------------------------------------------------------------
547 XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) :
548 XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ),
549 XclImpChRoot( rRoot ),
550 meObjType( eObjType )
554 void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm )
556 rStrm >> maData.mnFormat >> maData.mnFlags;
559 void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
561 const XclImpPalette& rPal = GetPalette();
563 if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) )
565 // line formatting
566 XclChLineFormat aLineFmt;
567 aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx );
568 switch( rLineData.mnStyle )
570 case EXC_OBJ_LINE_SOLID: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; break;
571 case EXC_OBJ_LINE_DASH: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH; break;
572 case EXC_OBJ_LINE_DOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT; break;
573 case EXC_OBJ_LINE_DASHDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT; break;
574 case EXC_OBJ_LINE_DASHDOTDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT; break;
575 case EXC_OBJ_LINE_MEDTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS; break;
576 case EXC_OBJ_LINE_DARKTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS; break;
577 case EXC_OBJ_LINE_LIGHTTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS; break;
578 case EXC_OBJ_LINE_NONE: aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; break;
579 default: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
581 switch( rLineData.mnWidth )
583 case EXC_OBJ_LINE_HAIR: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; break;
584 case EXC_OBJ_LINE_THIN: aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE; break;
585 case EXC_OBJ_LINE_MEDIUM: aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE; break;
586 case EXC_OBJ_LINE_THICK: aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE; break;
587 default: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
589 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() );
590 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
593 if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt )
595 // area formatting
596 XclChAreaFormat aAreaFmt;
597 aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx );
598 aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx );
599 aAreaFmt.mnPattern = rFillData.mnPattern;
600 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() );
601 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
605 void XclImpChFrame::Convert( ScfPropertySet& rPropSet ) const
607 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
610 // Source links ===============================================================
612 namespace {
614 /** Creates a labeled data sequence object, adds link for series title if present. */
615 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
616 XclImpChSourceLinkRef xValueLink, const OUString& rValueRole,
617 const XclImpChSourceLink* pTitleLink = 0 )
619 // create data sequence for values and title
620 Reference< XDataSequence > xValueSeq;
621 if( xValueLink.is() )
622 xValueSeq = xValueLink->CreateDataSequence( rValueRole );
623 Reference< XDataSequence > xTitleSeq;
624 if( pTitleLink )
625 xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL );
627 // create the labeled data sequence, if values or title are present
628 Reference< XLabeledDataSequence > xLabeledSeq;
629 if( xValueSeq.is() || xTitleSeq.is() )
630 xLabeledSeq.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LABELEDDATASEQ ), UNO_QUERY );
631 if( xLabeledSeq.is() )
633 if( xValueSeq.is() )
634 xLabeledSeq->setValues( xValueSeq );
635 if( xTitleSeq.is() )
636 xLabeledSeq->setLabel( xTitleSeq );
638 return xLabeledSeq;
641 } // namespace
643 // ----------------------------------------------------------------------------
645 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
646 XclImpChRoot( rRoot )
650 XclImpChSourceLink::~XclImpChSourceLink()
654 void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
656 rStrm >> maData.mnDestType
657 >> maData.mnLinkType
658 >> maData.mnFlags
659 >> maData.mnNumFmtIdx;
661 mxTokenArray.reset();
662 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
664 // read token array
665 XclTokenArray aXclTokArr;
666 rStrm >> aXclTokArr;
668 // convert BIFF formula tokens to Calc token array
669 if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) )
670 mxTokenArray.reset( pTokens->Clone() );
673 // try to read a following CHSTRING record
674 if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() )
676 mxString.reset( new XclImpString );
677 rStrm.Ignore( 2 );
678 mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
682 void XclImpChSourceLink::SetString( const String& rString )
684 if( !mxString )
685 mxString.reset( new XclImpString );
686 mxString->SetText( rString );
689 void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
691 if( mxString.is() )
692 mxString->SetFormats( rFormats );
695 sal_uInt16 XclImpChSourceLink::GetCellCount() const
697 sal_uInt32 nCellCount = 0;
698 if( mxTokenArray.is() )
700 mxTokenArray->Reset();
701 for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() )
703 switch( pToken->GetType() )
705 case ::formula::svSingleRef:
706 case ::formula::svExternalSingleRef:
707 // single cell
708 ++nCellCount;
709 break;
710 case ::formula::svDoubleRef:
711 case ::formula::svExternalDoubleRef:
713 // cell range
714 const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
715 const ScSingleRefData& rRef1 = rComplexRef.Ref1;
716 const ScSingleRefData& rRef2 = rComplexRef.Ref2;
717 sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
718 sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
719 sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
720 nCellCount += nCols * nRows * nTabs;
722 break;
723 default: ;
727 return limit_cast< sal_uInt16 >( nCellCount );
730 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
732 bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
733 sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND;
734 OUString aPropName = bPercent ? EXC_CHPROP_PERCENTAGENUMFMT : EXC_CHPROP_NUMBERFORMAT;
735 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
736 rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) );
737 else
738 // restore 'link to source' at data point (series may contain manual number format)
739 rPropSet.SetAnyProperty( aPropName, Any() );
742 Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const
744 Reference< XDataSequence > xDataSeq;
745 Reference< XDataProvider > xDataProv = GetDataProvider();
746 if( xDataProv.is() && mxTokenArray.is() )
748 ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray );
749 aComp.SetGrammar( ::formula::FormulaGrammar::GRAM_ENGLISH );
750 OUStringBuffer aRangeRep;
751 aComp.CreateStringFromTokenArray( aRangeRep );
754 xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() );
755 // set sequence role
756 ScfPropertySet aSeqProp( xDataSeq );
757 aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
759 catch( Exception& )
761 // DBG_ERRORFILE( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
764 return xDataSeq;
767 Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence(
768 const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const
770 ::std::vector< Reference< XFormattedString > > aStringVec;
771 if( mxString.is() )
773 for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt )
775 Reference< XFormattedString > xFmtStr(
776 ScfApiHelper::CreateInstance( SERVICE_CHART2_FORMATTEDSTRING ), UNO_QUERY );
777 if( xFmtStr.is() )
779 // set text data
780 xFmtStr->setString( aIt.GetPortionText() );
782 // set font formatting and font color
783 ScfPropertySet aStringProp( xFmtStr );
784 sal_uInt16 nFontIdx = aIt.GetPortionFont();
785 if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) )
786 // leading unformatted portion - use passed font settings
787 rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor );
788 else
789 rRoot.ConvertFont( aStringProp, nFontIdx );
791 // add string to vector of strings
792 aStringVec.push_back( xFmtStr );
796 return ScfApiHelper::VectorToSequence( aStringVec );
799 void XclImpChSourceLink::FillSourceLink(vector<ScSharedTokenRef>& rTokens) const
801 if (!mxTokenArray.is())
802 // no links to fill.
803 return;
805 mxTokenArray->Reset();
806 for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next())
808 ScSharedTokenRef pToken(static_cast<ScToken*>(p->Clone()));
809 if (ScRefTokenHelper::isRef(pToken))
810 // This is a reference token. Store it.
811 ScRefTokenHelper::join(rTokens, pToken);
815 // Text =======================================================================
817 XclImpChFontBase::~XclImpChFontBase()
821 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
823 Color aFontColor = GetFontColor();
824 rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor );
827 void XclImpChFontBase::ConvertRotationBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet, bool bSupportsStacked ) const
829 rRoot.GetChartPropSetHelper().WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked );
832 // ----------------------------------------------------------------------------
834 XclImpChFont::XclImpChFont() :
835 mnFontIdx( EXC_FONT_NOTFOUND )
839 void XclImpChFont::ReadChFont( XclImpStream& rStrm )
841 rStrm >> mnFontIdx;
844 // ----------------------------------------------------------------------------
846 XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) :
847 XclImpChRoot( rRoot )
851 void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm )
853 rStrm >> maData.mnHAlign
854 >> maData.mnVAlign
855 >> maData.mnBackMode
856 >> maData.maTextColor
857 >> maData.maRect
858 >> maData.mnFlags;
860 if( GetBiff() == EXC_BIFF8 )
862 // #116397# BIFF8: index into palette used instead of RGB data
863 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
864 // placement and rotation
865 rStrm >> maData.mnPlacement >> maData.mnRotation;
866 // lower 4 bits used for placement, other bits contain garbage
867 maData.mnPlacement &= 0x000F;
869 else
871 // BIFF2-BIFF7: get rotation from text orientation
872 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 );
873 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
877 void XclImpChText::ReadSubRecord( XclImpStream& rStrm )
879 switch( rStrm.GetRecId() )
881 case EXC_ID_CHFONT:
882 mxFont.reset( new XclImpChFont );
883 mxFont->ReadChFont( rStrm );
884 break;
885 case EXC_ID_CHFORMATRUNS:
886 if( GetBiff() == EXC_BIFF8 )
887 XclImpString::ReadFormats( rStrm, maFormats );
888 break;
889 case EXC_ID_CHSOURCELINK:
890 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
891 mxSrcLink->ReadChSourceLink( rStrm );
892 break;
893 case EXC_ID_CHFRAME:
894 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) );
895 mxFrame->ReadRecordGroup( rStrm );
896 break;
897 case EXC_ID_CHOBJECTLINK:
898 rStrm >> maObjLink.mnTarget >> maObjLink.maPointPos.mnSeriesIdx >> maObjLink.maPointPos.mnPointIdx;
899 break;
900 case EXC_ID_CHFRLABELPROPS:
901 ReadChFrLabelProps( rStrm );
902 break;
903 case EXC_ID_CHEND:
904 if( mxSrcLink.is() && !maFormats.empty() )
905 mxSrcLink->SetTextFormats( maFormats );
906 break;
910 sal_uInt16 XclImpChText::GetFontIndex() const
912 return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
915 Color XclImpChText::GetFontColor() const
917 return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
920 sal_uInt16 XclImpChText::GetRotation() const
922 return maData.mnRotation;
925 void XclImpChText::SetString( const String& rString )
927 if( !mxSrcLink )
928 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
929 mxSrcLink->SetString( rString );
932 void XclImpChText::UpdateText( const XclImpChText* pParentText )
934 if( pParentText )
936 // update missing members
937 if( !mxFrame )
938 mxFrame = pParentText->mxFrame;
939 if( !mxFont )
941 mxFont = pParentText->mxFont;
942 // text color is taken from CHTEXT record, not from font in CHFONT
943 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) );
944 maData.maTextColor = pParentText->maData.maTextColor;
949 void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent )
951 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bCateg );
952 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bValue );
953 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bPercent );
954 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent );
955 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bCateg && !bValue && !bPercent );
958 void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const
960 ConvertFontBase( GetChRoot(), rPropSet );
963 void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
965 ConvertRotationBase( GetChRoot(), rPropSet, bSupportsStacked );
968 void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const
970 if( mxFrame.is() )
971 mxFrame->Convert( rPropSet );
974 void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
976 if( mxSrcLink.is() )
977 mxSrcLink->ConvertNumFmt( rPropSet, bPercent );
980 void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const
982 // existing CHFRLABELPROPS record wins over flags from CHTEXT
983 sal_uInt16 nShowFlags = mxLabelProps.is() ? mxLabelProps->mnFlags : maData.mnFlags;
984 sal_uInt16 SHOWANYCATEG = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG);
985 sal_uInt16 SHOWANYVALUE = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE;
986 sal_uInt16 SHOWANYPERCENT = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC);
987 sal_uInt16 SHOWANYBUBBLE = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE;
989 // get raw flags for label values
990 bool bShowNone = IsDeleted();
991 bool bShowCateg = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG );
992 bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT );
993 bool bShowValue = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE );
994 bool bShowBubble = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE );
996 // adjust to Chart2 behaviour
997 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
998 bShowValue = bShowBubble; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1000 // other flags
1001 bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1002 bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL );
1004 // create API struct for label values, set API label separator
1005 namespace cssc = ::com::sun::star::chart2;
1006 cssc::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
1007 rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel );
1008 String aSep = mxLabelProps.is() ? mxLabelProps->maSeparator : String( sal_Unicode( '\n' ) );
1009 if( aSep.Len() == 0 )
1010 aSep = CREATE_STRING( "; " );
1011 rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep );
1013 // text properties of attached label
1014 if( bShowAny )
1016 ConvertFont( rPropSet );
1017 ConvertRotation( rPropSet, false );
1018 // label placement
1019 using namespace ::com::sun::star::chart::DataLabelPlacement;
1020 sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos;
1021 switch( maData.mnPlacement )
1023 case EXC_CHTEXT_POS_DEFAULT: nPlacement = rTypeInfo.mnDefaultLabelPos; break;
1024 case EXC_CHTEXT_POS_OUTSIDE: nPlacement = OUTSIDE; break;
1025 case EXC_CHTEXT_POS_INSIDE: nPlacement = INSIDE; break;
1026 case EXC_CHTEXT_POS_CENTER: nPlacement = CENTER; break;
1027 case EXC_CHTEXT_POS_AXIS: nPlacement = NEAR_ORIGIN; break;
1028 case EXC_CHTEXT_POS_ABOVE: nPlacement = TOP; break;
1029 case EXC_CHTEXT_POS_BELOW: nPlacement = BOTTOM; break;
1030 case EXC_CHTEXT_POS_LEFT: nPlacement = LEFT; break;
1031 case EXC_CHTEXT_POS_RIGHT: nPlacement = RIGHT; break;
1032 case EXC_CHTEXT_POS_AUTO: nPlacement = AVOID_OVERLAP; break;
1034 rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement );
1035 // label number format (percentage format wins over value format)
1036 if( bShowPercent || bShowValue )
1037 ConvertNumFmt( rPropSet, bShowPercent );
1041 Reference< XTitle > XclImpChText::CreateTitle() const
1043 Reference< XTitle > xTitle;
1044 if( mxSrcLink.is() && mxSrcLink->HasString() )
1046 // create the formatted strings
1047 Sequence< Reference< XFormattedString > > aStringSeq(
1048 mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1049 if( aStringSeq.hasElements() )
1051 // create the title object
1052 xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY );
1053 if( xTitle.is() )
1055 // set the formatted strings
1056 xTitle->setText( aStringSeq );
1057 // more title formatting properties
1058 ScfPropertySet aTitleProp( xTitle );
1059 ConvertFrame( aTitleProp );
1060 ConvertRotation( aTitleProp, true );
1064 return xTitle;
1067 void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm )
1069 if( GetBiff() == EXC_BIFF8 )
1071 mxLabelProps.reset( new XclChFrLabelProps );
1072 sal_uInt16 nSepLen;
1073 rStrm.Ignore( 12 );
1074 rStrm >> mxLabelProps->mnFlags >> nSepLen;
1075 if( nSepLen > 0 )
1076 mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen );
1080 namespace {
1082 void lclUpdateText( XclImpChTextRef& rxText, XclImpChTextRef xDefText )
1084 if( rxText.is() )
1085 rxText->UpdateText( xDefText.get() );
1086 else
1087 rxText = xDefText;
1090 void lclFinalizeTitle( XclImpChTextRef& rxTitle, XclImpChTextRef xDefText )
1092 /* Do not update a title, if it is not visible (if rxTitle is null).
1093 Existing reference indicates enabled title. */
1094 if( rxTitle.is() )
1096 if( rxTitle->HasString() )
1097 rxTitle->UpdateText( xDefText.get() );
1098 else
1099 rxTitle.reset();
1103 } // namespace
1105 // Data series ================================================================
1107 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm )
1109 rStrm >> maData.maLineColor >> maData.maFillColor >> maData.mnMarkerType >> maData.mnFlags;
1111 const XclImpRoot& rRoot = rStrm.GetRoot();
1112 if( rRoot.GetBiff() == EXC_BIFF8 )
1114 // #116397# BIFF8: index into palette used instead of RGB data
1115 const XclImpPalette& rPal = rRoot.GetPalette();
1116 maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() );
1117 maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() );
1118 // marker size
1119 rStrm >> maData.mnMarkerSize;
1123 void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot,
1124 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const
1126 if( IsAuto() )
1128 XclChMarkerFormat aMarkerFmt;
1129 // line and fill color of the symbol are equal to series line color
1130 //! TODO: Excel sets no fill color for specific symbols (e.g. cross)
1131 aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx );
1132 switch( nLineWeight )
1134 case EXC_CHLINEFORMAT_HAIR: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE; break;
1135 case EXC_CHLINEFORMAT_SINGLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; break;
1136 case EXC_CHLINEFORMAT_DOUBLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; break;
1137 case EXC_CHLINEFORMAT_TRIPLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE; break;
1138 default: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;
1140 aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
1141 rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, aMarkerFmt );
1143 else
1145 rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, maData );
1149 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot,
1150 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
1152 Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor;
1153 rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor );
1156 // ----------------------------------------------------------------------------
1158 XclImpChPieFormat::XclImpChPieFormat() :
1159 mnPieDist( 0 )
1163 void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm )
1165 rStrm >> mnPieDist;
1168 void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const
1170 double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 );
1171 rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist );
1174 // ----------------------------------------------------------------------------
1176 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1177 mnFlags( 0 )
1181 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm )
1183 rStrm >> mnFlags;
1186 // ----------------------------------------------------------------------------
1188 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm )
1190 rStrm >> maData.mnBase >> maData.mnTop;
1193 void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const
1195 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1196 sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ?
1197 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) :
1198 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE);
1199 rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType );
1202 // ----------------------------------------------------------------------------
1204 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) :
1205 XclImpChRoot( rRoot ),
1206 mnFlags( 0 )
1210 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm )
1212 rStrm >> mnFlags;
1215 XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( XclImpChTextRef xParent ) const
1217 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE;
1218 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC;
1219 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC;
1221 XclImpChTextRef xLabel( xParent.is() ? new XclImpChText( *xParent ) : new XclImpChText( GetChRoot() ) );
1222 xLabel->UpdateDataLabel(
1223 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ),
1224 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ),
1225 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) );
1226 return xLabel;
1229 // ----------------------------------------------------------------------------
1231 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) :
1232 XclImpChRoot( rRoot )
1236 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm )
1238 rStrm >> maData.maPointPos.mnPointIdx
1239 >> maData.maPointPos.mnSeriesIdx
1240 >> maData.mnFormatIdx
1241 >> maData.mnFlags;
1244 void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm )
1246 switch( rStrm.GetRecId() )
1248 case EXC_ID_CHMARKERFORMAT:
1249 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1250 mxMarkerFmt->ReadChMarkerFormat( rStrm );
1251 break;
1252 case EXC_ID_CHPIEFORMAT:
1253 mxPieFmt.reset( new XclImpChPieFormat );
1254 mxPieFmt->ReadChPieFormat( rStrm );
1255 break;
1256 case EXC_ID_CHSERIESFORMAT:
1257 mxSeriesFmt.reset( new XclImpChSeriesFormat );
1258 mxSeriesFmt->ReadChSeriesFormat( rStrm );
1259 break;
1260 case EXC_ID_CH3DDATAFORMAT:
1261 mx3dDataFmt.reset( new XclImpCh3dDataFormat );
1262 mx3dDataFmt->ReadCh3dDataFormat( rStrm );
1263 break;
1264 case EXC_ID_CHATTACHEDLABEL:
1265 mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) );
1266 mxAttLabel->ReadChAttachedLabel( rStrm );
1267 break;
1268 default:
1269 XclImpChFrameBase::ReadSubRecord( rStrm );
1273 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx )
1275 maData.maPointPos = rPointPos;
1276 maData.mnFormatIdx = nFormatIdx;
1279 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo )
1281 // remove formats not used for the current chart type
1282 RemoveUnusedFormats( rTypeInfo );
1285 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt )
1287 // update missing formats from passed chart type group format
1288 if( pGroupFmt )
1290 if( !mxLineFmt )
1291 mxLineFmt = pGroupFmt->mxLineFmt;
1292 if( !mxAreaFmt && !mxEscherFmt )
1294 mxAreaFmt = pGroupFmt->mxAreaFmt;
1295 mxEscherFmt = pGroupFmt->mxEscherFmt;
1297 if( !mxMarkerFmt )
1298 mxMarkerFmt = pGroupFmt->mxMarkerFmt;
1299 if( !mxPieFmt )
1300 mxPieFmt = pGroupFmt->mxPieFmt;
1301 if( !mxSeriesFmt )
1302 mxSeriesFmt = pGroupFmt->mxSeriesFmt;
1303 if( !mx3dDataFmt )
1304 mx3dDataFmt = pGroupFmt->mx3dDataFmt;
1305 if( !mxAttLabel )
1306 mxAttLabel = pGroupFmt->mxAttLabel;
1309 /* Create missing but required formats. Existing line, area, and marker
1310 format objects are needed to create automatic series formatting. */
1311 if( !mxLineFmt )
1312 mxLineFmt.reset( new XclImpChLineFormat );
1313 if( !mxAreaFmt && !mxEscherFmt )
1314 mxAreaFmt.reset( new XclImpChAreaFormat );
1315 if( !mxMarkerFmt )
1316 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1318 // remove formats not used for the current chart type
1319 RemoveUnusedFormats( rTypeInfo );
1320 // update data label
1321 UpdateDataLabel( pGroupFmt );
1324 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt )
1326 // remove formats if they are automatic in this and in the passed series format
1327 if( pSeriesFmt )
1329 if( IsAutoLine() && pSeriesFmt->IsAutoLine() )
1330 mxLineFmt.reset();
1331 if( IsAutoArea() && pSeriesFmt->IsAutoArea() )
1332 mxAreaFmt.reset();
1333 if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() )
1334 mxMarkerFmt.reset();
1335 mxSeriesFmt.reset();
1338 // Excel ignores 3D bar format for single data points
1339 mx3dDataFmt.reset();
1340 // remove point line formats for linear chart types, TODO: implement in OOChart
1341 if( !rTypeInfo.IsSeriesFrameFormat() )
1342 mxLineFmt.reset();
1344 // remove formats not used for the current chart type
1345 RemoveUnusedFormats( rTypeInfo );
1346 // update data label
1347 UpdateDataLabel( pSeriesFmt );
1350 void XclImpChDataFormat::UpdateTrendLineFormat()
1352 if( !mxLineFmt )
1353 mxLineFmt.reset( new XclImpChLineFormat );
1354 mxAreaFmt.reset();
1355 mxEscherFmt.reset();
1356 mxMarkerFmt.reset();
1357 mxPieFmt.reset();
1358 mxSeriesFmt.reset();
1359 mx3dDataFmt.reset();
1360 mxAttLabel.reset();
1361 // update data label
1362 UpdateDataLabel( 0 );
1365 void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const
1367 // line and area format
1368 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx );
1369 #if EXC_CHART2_3DBAR_HAIRLINES_ONLY
1370 // #i83151# only hair lines in 3D charts with filled data points
1371 if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt.is() && mxLineFmt->HasLine() )
1372 rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "BorderWidth" ), 0 );
1373 #endif
1375 // other formatting
1376 if( mxMarkerFmt.is() )
1377 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() );
1378 if( mxPieFmt.is() )
1379 mxPieFmt->Convert( rPropSet );
1380 if( mx3dDataFmt.is() )
1381 mx3dDataFmt->Convert( rPropSet );
1382 if( mxLabel.is() )
1383 mxLabel->ConvertDataLabel( rPropSet, rTypeInfo );
1385 // 3D settings
1386 rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 );
1388 /* Special case: set marker color as line color, if series line is not
1389 visible. This makes the color visible in the marker area.
1390 TODO: remove this if OOChart supports own colors in markers. */
1391 if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt.is() )
1392 mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx );
1395 void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
1397 ConvertLineBase( GetChRoot(), rPropSet, eObjType );
1400 void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
1402 ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx );
1405 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo )
1407 // data point marker only in linear 2D charts
1408 if( rTypeInfo.IsSeriesFrameFormat() )
1409 mxMarkerFmt.reset();
1410 // pie format only in pie/donut charts
1411 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
1412 mxPieFmt.reset();
1413 // 3D format only in 3D bar charts
1414 if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
1415 mx3dDataFmt.reset();
1418 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt )
1420 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1421 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1422 group, the contents of the CHATTACHEDLABEL record are used. In this
1423 case a new CHTEXT group is created and filled with the settings from
1424 the CHATTACHEDLABEL record. */
1425 XclImpChTextRef xDefText;
1426 if( pParentFmt )
1427 xDefText = pParentFmt->GetDataLabel();
1428 if( !xDefText )
1429 xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL );
1430 if( mxLabel.is() )
1431 mxLabel->UpdateText( xDefText.get() );
1432 else if( mxAttLabel.is() )
1433 mxLabel = mxAttLabel->CreateDataLabel( xDefText );
1436 // ----------------------------------------------------------------------------
1438 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) :
1439 XclImpChRoot( rRoot )
1443 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm )
1445 rStrm >> maData.mnLineType
1446 >> maData.mnOrder
1447 >> maData.mfIntercept
1448 >> maData.mnShowEquation
1449 >> maData.mnShowRSquared
1450 >> maData.mfForecastFor
1451 >> maData.mfForecastBack;
1454 Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const
1456 // trend line type
1457 OUString aService;
1458 switch( maData.mnLineType )
1460 case EXC_CHSERTREND_POLYNOMIAL:
1461 // TODO: only linear trend lines are supported by OOChart (#i20819#)
1462 if( maData.mnOrder == 1 )
1463 aService = SERVICE_CHART2_LINEARREGCURVE;
1464 break;
1465 case EXC_CHSERTREND_EXPONENTIAL:
1466 aService = SERVICE_CHART2_EXPREGCURVE;
1467 break;
1468 case EXC_CHSERTREND_LOGARITHMIC:
1469 aService = SERVICE_CHART2_LOGREGCURVE;
1470 break;
1471 case EXC_CHSERTREND_POWER:
1472 aService = SERVICE_CHART2_POTREGCURVE;
1473 break;
1475 Reference< XRegressionCurve > xRegCurve;
1476 if( aService.getLength() > 0 )
1477 xRegCurve.set( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
1479 // trend line formatting
1480 if( xRegCurve.is() && mxDataFmt.is() )
1482 ScfPropertySet aPropSet( xRegCurve );
1483 mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE );
1485 // #i83100# show equation and correlation coefficient
1486 ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() );
1487 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 );
1488 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 );
1490 // #i83100# formatting of the equation text box
1491 if( const XclImpChText* pLabel = mxDataFmt->GetDataLabel().get() )
1493 pLabel->ConvertFont( aLabelProp );
1494 pLabel->ConvertFrame( aLabelProp );
1495 pLabel->ConvertNumFmt( aLabelProp, false );
1499 // missing features
1500 // #i20819# polynomial trend lines
1501 // #i66819# moving average trend lines
1502 // #i5085# manual trend line size
1503 // #i34093# manual crossing point
1505 return xRegCurve;
1508 // ----------------------------------------------------------------------------
1510 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) :
1511 XclImpChRoot( rRoot )
1515 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm )
1517 rStrm >> maData.mnBarType >> maData.mnSourceType >> maData.mnLineEnd;
1518 rStrm.Ignore( 1 );
1519 rStrm >> maData.mfValue >> maData.mnValueCount;
1522 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef xValueLink, XclImpChDataFormatRef xDataFmt )
1524 mxValueLink = xValueLink;
1525 mxDataFmt = xDataFmt;
1528 Reference< XLabeledDataSequence > XclImpChSerErrorBar::CreateValueSequence() const
1530 return lclCreateLabeledDataSequence( mxValueLink, XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ) );
1533 Reference< XPropertySet > XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar* pPosBar, const XclImpChSerErrorBar* pNegBar )
1535 Reference< XPropertySet > xErrorBar;
1537 if( const XclImpChSerErrorBar* pPrimaryBar = pPosBar ? pPosBar : pNegBar )
1539 xErrorBar.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR ), UNO_QUERY );
1540 ScfPropertySet aBarProp( xErrorBar );
1542 // plus/minus bars visible?
1543 aBarProp.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR, pPosBar != 0 );
1544 aBarProp.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR, pNegBar != 0 );
1546 // type of displayed error
1547 namespace cssc = ::com::sun::star::chart;
1548 switch( pPrimaryBar->maData.mnSourceType )
1550 case EXC_CHSERERR_PERCENT:
1551 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::RELATIVE );
1552 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1553 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1554 break;
1555 case EXC_CHSERERR_FIXED:
1556 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::ABSOLUTE );
1557 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1558 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1559 break;
1560 case EXC_CHSERERR_STDDEV:
1561 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_DEVIATION );
1562 aBarProp.SetProperty( EXC_CHPROP_WEIGHT, pPrimaryBar->maData.mfValue );
1563 break;
1564 case EXC_CHSERERR_STDERR:
1565 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_ERROR );
1566 break;
1567 case EXC_CHSERERR_CUSTOM:
1569 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::FROM_DATA );
1570 // attach data sequences to erorr bar
1571 Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
1572 if( xDataSink.is() )
1574 // create vector of all value sequences
1575 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
1576 // add positive values
1577 if( pPosBar )
1579 Reference< XLabeledDataSequence > xValueSeq = pPosBar->CreateValueSequence();
1580 if( xValueSeq.is() )
1581 aLabeledSeqVec.push_back( xValueSeq );
1583 // add negative values
1584 if( pNegBar )
1586 Reference< XLabeledDataSequence > xValueSeq = pNegBar->CreateValueSequence();
1587 if( xValueSeq.is() )
1588 aLabeledSeqVec.push_back( xValueSeq );
1590 // attach labeled data sequences to series
1591 if( aLabeledSeqVec.empty() )
1592 xErrorBar.clear();
1593 else
1594 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
1597 break;
1598 default:
1599 xErrorBar.clear();
1602 // error bar formatting
1603 if( pPrimaryBar->mxDataFmt.is() && xErrorBar.is() )
1604 pPrimaryBar->mxDataFmt->ConvertLine( aBarProp, EXC_CHOBJTYPE_ERRORBAR );
1607 return xErrorBar;
1610 // ----------------------------------------------------------------------------
1612 XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1613 XclImpChRoot( rRoot ),
1614 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1615 mnSeriesIdx( nSeriesIdx ),
1616 mnParentIdx( EXC_CHSERIES_INVALID )
1620 void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm )
1622 rStrm >> maData.mnCategType >> maData.mnValueType >> maData.mnCategCount >> maData.mnValueCount;
1623 if( GetBiff() == EXC_BIFF8 )
1624 rStrm >> maData.mnBubbleType >> maData.mnBubbleCount;
1627 void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm )
1629 switch( rStrm.GetRecId() )
1631 case EXC_ID_CHSOURCELINK:
1632 ReadChSourceLink( rStrm );
1633 break;
1634 case EXC_ID_CHDATAFORMAT:
1635 ReadChDataFormat( rStrm );
1636 break;
1637 case EXC_ID_CHSERGROUP:
1638 rStrm >> mnGroupIdx;
1639 break;
1640 case EXC_ID_CHSERPARENT:
1641 ReadChSerParent( rStrm );
1642 break;
1643 case EXC_ID_CHSERTRENDLINE:
1644 ReadChSerTrendLine( rStrm );
1645 break;
1646 case EXC_ID_CHSERERRORBAR:
1647 ReadChSerErrorBar( rStrm );
1648 break;
1652 void XclImpChSeries::SetDataFormat( XclImpChDataFormatRef xDataFmt )
1654 if( xDataFmt.is() )
1656 XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( xDataFmt->GetPointPos().mnPointIdx );
1657 // do not overwrite existing data format
1658 if( pxDataFmt && !*pxDataFmt )
1660 *pxDataFmt = xDataFmt;
1661 // #i51639# register series format index at chart type group
1662 if( (pxDataFmt == &mxSeriesFmt) && !HasParentSeries() )
1663 if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1664 pTypeGroup->SetUsedFormatIndex( xDataFmt->GetFormatIdx() );
1669 void XclImpChSeries::SetDataLabel( XclImpChTextRef xLabel )
1671 if( xLabel.is() )
1673 XclImpChTextRef* pxLabel = GetDataLabelRef( xLabel->GetPointPos().mnPointIdx );
1674 if( pxLabel && !*pxLabel )
1675 *pxLabel = xLabel;
1679 void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries )
1681 DBG_ASSERT( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1683 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1684 these are properties of the parent series. This function adds the
1685 settings of the passed series to this series. */
1686 maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() );
1687 maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() );
1690 void XclImpChSeries::FinalizeDataFormats()
1692 if( HasParentSeries() )
1694 // *** series is a child series, e.g. trend line or error bar ***
1696 // create missing series format
1697 if( !mxSeriesFmt )
1698 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 );
1700 if( mxSeriesFmt.is() )
1702 // #i83100# set text label format, e.g. for trend line equations
1703 mxSeriesFmt->SetDataLabel( maLabels.get( EXC_CHDATAFORMAT_ALLPOINTS ) );
1704 // create missing automatic formats
1705 mxSeriesFmt->UpdateTrendLineFormat();
1708 // copy series formatting to child objects
1709 for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt )
1710 (*aLIt)->SetDataFormat( mxSeriesFmt );
1711 for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt )
1712 aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt );
1714 else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1716 // *** series is a regular data series ***
1718 // create missing series format
1719 if( !mxSeriesFmt )
1721 // #i51639# use a new unused format index to create series default format
1722 sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex();
1723 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx );
1726 // set text labels to data formats
1727 for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt )
1729 if( XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( aTIt->first ) )
1731 if( !*pxDataFmt )
1732 *pxDataFmt = CreateDataFormat( aTIt->first, EXC_CHDATAFORMAT_DEFAULT );
1733 (*pxDataFmt)->SetDataLabel( aTIt->second );
1737 // update series format (copy missing formatting from group default format)
1738 if( mxSeriesFmt.is() )
1739 mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() );
1741 // update data point formats (removes unchanged automatic formatting)
1742 for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt )
1743 aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() );
1747 namespace {
1749 /** Returns the property set of the specified data point. */
1750 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx )
1752 ScfPropertySet aPropSet;
1755 aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) );
1757 catch( Exception& )
1759 DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1761 return aPropSet;
1764 } // namespace
1766 Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const
1768 return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() );
1771 Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const
1773 return lclCreateLabeledDataSequence( mxCategLink, rCategRole );
1776 Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const
1778 Reference< XDataSeries > xDataSeries;
1779 if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1781 const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo();
1783 // create the data series object
1784 xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
1786 // attach data and title sequences to series
1787 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
1788 if( xDataSink.is() )
1790 // create vector of all value sequences
1791 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
1792 // add Y values
1793 Reference< XLabeledDataSequence > xYValueSeq =
1794 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES );
1795 if( xYValueSeq.is() )
1796 aLabeledSeqVec.push_back( xYValueSeq );
1797 // add X values
1798 if( !rTypeInfo.mbCategoryAxis )
1800 Reference< XLabeledDataSequence > xXValueSeq =
1801 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES );
1802 if( xXValueSeq.is() )
1803 aLabeledSeqVec.push_back( xXValueSeq );
1804 // add size values of bubble charts
1805 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
1807 Reference< XLabeledDataSequence > xSizeValueSeq =
1808 lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() );
1809 if( xSizeValueSeq.is() )
1810 aLabeledSeqVec.push_back( xSizeValueSeq );
1813 // attach labeled data sequences to series
1814 if( !aLabeledSeqVec.empty() )
1815 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
1818 // series formatting
1819 ScfPropertySet aSeriesProp( xDataSeries );
1820 if( mxSeriesFmt.is() )
1821 mxSeriesFmt->Convert( aSeriesProp, rTypeInfo );
1823 // trend lines
1824 ConvertTrendLines( xDataSeries );
1826 // error bars
1827 Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1828 if( xErrorBarX.is() )
1829 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX );
1830 Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1831 if( xErrorBarY.is() )
1832 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY );
1834 // own area formatting for every data point (TODO: varying line color not supported)
1835 bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat();
1836 #if EXC_CHART2_VARYCOLORSBY_PROP
1837 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt );
1838 #else
1839 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
1840 #endif
1841 // #i91271# always set area formatting for every point in pie/doughnut charts
1842 if( mxSeriesFmt.is() && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)) )
1844 for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx )
1846 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1847 mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx );
1851 // data point formatting
1852 for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt )
1854 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first );
1855 aIt->second->Convert( aPointProp, rTypeInfo );
1858 return xDataSeries;
1861 void XclImpChSeries::FillAllSourceLinks(vector<ScSharedTokenRef>& rTokens) const
1863 mxValueLink->FillSourceLink(rTokens);
1864 mxCategLink->FillSourceLink(rTokens);
1865 mxTitleLink->FillSourceLink(rTokens);
1866 mxBubbleLink->FillSourceLink(rTokens);
1869 void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm )
1871 XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
1872 xSrcLink->ReadChSourceLink( rStrm );
1873 switch( xSrcLink->GetDestType() )
1875 case EXC_CHSRCLINK_TITLE: mxTitleLink = xSrcLink; break;
1876 case EXC_CHSRCLINK_VALUES: mxValueLink = xSrcLink; break;
1877 case EXC_CHSRCLINK_CATEGORY: mxCategLink = xSrcLink; break;
1878 case EXC_CHSRCLINK_BUBBLES: mxBubbleLink = xSrcLink; break;
1882 void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm )
1884 // #i51639# chart stores all data formats and assigns them later to the series
1885 GetChartData().ReadChDataFormat( rStrm );
1888 void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm )
1890 rStrm >> mnParentIdx;
1891 // index to parent series is 1-based, convert it to 0-based
1892 if( mnParentIdx > 0 )
1893 --mnParentIdx;
1894 else
1895 mnParentIdx = EXC_CHSERIES_INVALID;
1898 void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm )
1900 XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
1901 xTrendLine->ReadChSerTrendLine( rStrm );
1902 maTrendLines.push_back( xTrendLine );
1905 void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm )
1907 XclImpChSerErrorBarRef xErrorBar( new XclImpChSerErrorBar( GetChRoot() ) );
1908 xErrorBar->ReadChSerErrorBar( rStrm );
1909 maErrorBars[ xErrorBar->GetBarType() ] = xErrorBar;
1912 XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx )
1914 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
1915 xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx );
1916 return xDataFmt;
1919 XclImpChDataFormatRef* XclImpChSeries::GetDataFormatRef( sal_uInt16 nPointIdx )
1921 if( nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS )
1922 return &mxSeriesFmt;
1923 if( nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT )
1924 return &maPointFmts[ nPointIdx ];
1925 return 0;
1928 XclImpChTextRef* XclImpChSeries::GetDataLabelRef( sal_uInt16 nPointIdx )
1930 if( (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS) || (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT) )
1931 return &maLabels[ nPointIdx ];
1932 return 0;
1935 void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const
1937 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
1938 if( xRegCurveCont.is() )
1940 for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt )
1944 Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve();
1945 if( xRegCurve.is() )
1946 xRegCurveCont->addRegressionCurve( xRegCurve );
1948 catch( Exception& )
1950 DBG_ERRORFILE( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
1956 Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const
1958 return XclImpChSerErrorBar::CreateErrorBar( maErrorBars.get( nPosBarId ).get(), maErrorBars.get( nNegBarId ).get() );
1961 // Chart type groups ==========================================================
1963 XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) :
1964 XclImpChRoot( rRoot ),
1965 mnRecId( EXC_ID_CHUNKNOWN ),
1966 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
1970 void XclImpChType::ReadChType( XclImpStream& rStrm )
1972 sal_uInt16 nRecId = rStrm.GetRecId();
1973 bool bKnownType = true;
1975 switch( nRecId )
1977 case EXC_ID_CHBAR:
1978 rStrm >> maData.mnOverlap >> maData.mnGap >> maData.mnFlags;
1979 break;
1981 case EXC_ID_CHLINE:
1982 case EXC_ID_CHAREA:
1983 case EXC_ID_CHRADARLINE:
1984 case EXC_ID_CHRADARAREA:
1985 rStrm >> maData.mnFlags;
1986 break;
1988 case EXC_ID_CHPIE:
1989 rStrm >> maData.mnRotation >> maData.mnPieHole;
1990 if( GetBiff() == EXC_BIFF8 )
1991 rStrm >> maData.mnFlags;
1992 else
1993 maData.mnFlags = 0;
1994 break;
1996 case EXC_ID_CHPIEEXT:
1997 maData.mnRotation = 0;
1998 maData.mnPieHole = 0;
1999 maData.mnFlags = 0;
2000 break;
2002 case EXC_ID_CHSCATTER:
2003 if( GetBiff() == EXC_BIFF8 )
2004 rStrm >> maData.mnBubbleSize >> maData.mnBubbleType >> maData.mnFlags;
2005 else
2006 maData.mnFlags = 0;
2007 break;
2009 case EXC_ID_CHSURFACE:
2010 rStrm >> maData.mnFlags;
2011 break;
2013 default:
2014 bKnownType = false;
2017 if( bKnownType )
2018 mnRecId = nRecId;
2021 void XclImpChType::Finalize( bool bStockChart )
2023 switch( mnRecId )
2025 case EXC_ID_CHLINE:
2026 maTypeInfo = GetChartTypeInfo( bStockChart ?
2027 EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE );
2028 break;
2029 case EXC_ID_CHBAR:
2030 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2031 maData.mnFlags, EXC_CHBAR_HORIZONTAL,
2032 EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) );
2033 break;
2034 case EXC_ID_CHPIE:
2035 maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ?
2036 EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2037 break;
2038 case EXC_ID_CHSCATTER:
2039 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2040 maData.mnFlags, EXC_CHSCATTER_BUBBLES,
2041 EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) );
2042 break;
2043 default:
2044 maTypeInfo = GetChartTypeInfo( mnRecId );
2047 switch( maTypeInfo.meTypeId )
2049 case EXC_CHTYPEID_PIEEXT:
2050 case EXC_CHTYPEID_BUBBLES:
2051 case EXC_CHTYPEID_SURFACE:
2052 case EXC_CHTYPEID_UNKNOWN:
2053 GetTracer().TraceChartUnKnownType();
2054 break;
2055 default:;
2059 bool XclImpChType::IsStacked() const
2061 bool bStacked = false;
2062 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2064 case EXC_CHTYPECATEG_LINE:
2065 bStacked =
2066 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2067 !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2068 break;
2069 case EXC_CHTYPECATEG_BAR:
2070 bStacked =
2071 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2072 !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2073 break;
2074 default:;
2076 return bStacked;
2079 bool XclImpChType::IsPercent() const
2081 bool bPercent = false;
2082 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2084 case EXC_CHTYPECATEG_LINE:
2085 bPercent =
2086 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2087 ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2088 break;
2089 case EXC_CHTYPECATEG_BAR:
2090 bPercent =
2091 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2092 ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2093 break;
2094 default:;
2096 return bPercent;
2099 bool XclImpChType::HasCategoryLabels() const
2101 // radar charts disable category labels in chart type, not in CHTICK of X axis
2102 return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS );
2105 Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const
2107 // service name
2108 OUString aCoordSysService;
2109 if( maTypeInfo.mbPolarCoordSystem )
2111 if( b3dChart )
2112 aCoordSysService = SERVICE_CHART2_POLARCOORDSYS3D;
2113 else
2114 aCoordSysService = SERVICE_CHART2_POLARCOORDSYS2D;
2116 else
2118 if( b3dChart )
2119 aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS3D;
2120 else
2121 aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS2D;
2124 // create the coordinate system object
2125 Reference< XCoordinateSystem > xCoordSystem( ScfApiHelper::CreateInstance( aCoordSysService ), UNO_QUERY );
2127 // swap X and Y axis
2128 if( maTypeInfo.mbSwappedAxesSet )
2130 ScfPropertySet aCoordSysProp( xCoordSystem );
2131 aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true );
2134 return xCoordSystem;
2137 Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const
2139 OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
2140 Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
2142 // additional properties
2143 switch( maTypeInfo.meTypeCateg )
2145 case EXC_CHTYPECATEG_BAR:
2147 ScfPropertySet aTypeProp( xChartType );
2148 Sequence< sal_Int32 > aInt32Seq( 2 );
2149 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap;
2150 aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq );
2151 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap;
2152 aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq );
2154 break;
2155 case EXC_CHTYPECATEG_PIE:
2157 ScfPropertySet aTypeProp( xChartType );
2158 aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT );
2159 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2160 rotation setting in view3D element. Of-pie charts do not
2161 support pie rotation. */
2162 if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) )
2164 ScfPropertySet aDiaProp( xDiagram );
2165 XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation );
2168 break;
2169 default:;
2172 return xChartType;
2175 // ----------------------------------------------------------------------------
2177 void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm )
2179 rStrm >> maData.mnRotation
2180 >> maData.mnElevation
2181 >> maData.mnEyeDist
2182 >> maData.mnRelHeight
2183 >> maData.mnRelDepth
2184 >> maData.mnDepthGap
2185 >> maData.mnFlags;
2188 void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const
2190 namespace cssd = ::com::sun::star::drawing;
2191 DBG_ASSERT( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2193 sal_Int32 nRotationY = 0;
2194 sal_Int32 nRotationX = 0;
2195 sal_Int32 nPerspective = 15;
2196 bool bRightAngled = false;
2197 cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE;
2198 Color aAmbientColor, aLightColor;
2200 if( b3dWallChart )
2202 // Y rotation (Excel [0..359], Chart2 [-179,180])
2203 nRotationY = maData.mnRotation % 360;
2204 if( nRotationY > 180 ) nRotationY -= 360;
2205 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2206 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 );
2207 // perspective (Excel and Chart2 [0,100])
2208 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2209 // right-angled axes
2210 bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D );
2211 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2212 bool bParallel = bRightAngled || (nPerspective == 0);
2213 eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
2214 // ambient color (Gray 20%)
2215 aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) );
2216 // light color (Gray 60%)
2217 aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) );
2219 else
2221 // Y rotation not used in pie charts, but 'first pie slice angle'
2222 nRotationY = 0;
2223 XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation );
2224 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2225 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90;
2226 // perspective (Excel and Chart2 [0,100])
2227 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2228 // no right-angled axes in pie charts, but parallel projection
2229 bRightAngled = false;
2230 eProjMode = cssd::ProjectionMode_PARALLEL;
2231 // ambient color (Gray 30%)
2232 aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) );
2233 // light color (Gray 70%)
2234 aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) );
2237 // properties
2238 rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY );
2239 rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX );
2240 rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective );
2241 rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled );
2242 rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode );
2244 // light settings
2245 rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT );
2246 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor );
2247 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false );
2248 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true );
2249 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor );
2250 rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2253 // ----------------------------------------------------------------------------
2255 XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) :
2256 XclImpChRoot( rRoot )
2260 void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm )
2262 rStrm >> maData.maRect >> maData.mnDockMode >> maData.mnSpacing >> maData.mnFlags;
2264 // trace unsupported features
2265 if( GetTracer().IsEnabled() )
2267 if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED )
2268 GetTracer().TraceChartLegendPosition();
2269 if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) )
2270 GetTracer().TraceChartDataTable();
2274 void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm )
2276 switch( rStrm.GetRecId() )
2278 case EXC_ID_CHTEXT:
2279 mxText.reset( new XclImpChText( GetChRoot() ) );
2280 mxText->ReadRecordGroup( rStrm );
2281 break;
2282 case EXC_ID_CHFRAME:
2283 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2284 mxFrame->ReadRecordGroup( rStrm );
2285 break;
2289 void XclImpChLegend::Finalize()
2291 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2292 if( !mxFrame )
2293 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2294 // Update text formatting. If mxText is empty, the passed default text is used.
2295 lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) );
2298 Reference< XLegend > XclImpChLegend::CreateLegend() const
2300 Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY );
2301 if( xLegend.is() )
2303 ScfPropertySet aLegendProp( xLegend );
2305 // frame properties
2306 if( mxFrame.is() )
2307 mxFrame->Convert( aLegendProp );
2308 // text properties
2309 if( mxText.is() )
2310 mxText->ConvertFont( aLegendProp );
2311 // special legend properties
2312 GetChartPropSetHelper().WriteLegendProperties( aLegendProp, maData );
2314 return xLegend;
2317 // ----------------------------------------------------------------------------
2319 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) :
2320 mnDropBar( nDropBar ),
2321 mnBarDist( 0 )
2325 void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm )
2327 rStrm >> mnBarDist;
2330 void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
2332 XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND;
2333 switch( mnDropBar )
2335 case EXC_CHDROPBAR_UP: eObjType = EXC_CHOBJTYPE_WHITEDROPBAR; break;
2336 case EXC_CHDROPBAR_DOWN: eObjType = EXC_CHOBJTYPE_BLACKDROPBAR; break;
2338 ConvertFrameBase( rRoot, rPropSet, eObjType );
2341 // ----------------------------------------------------------------------------
2343 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) :
2344 XclImpChRoot( rRoot ),
2345 maType( rRoot ),
2346 maTypeInfo( maType.GetTypeInfo() )
2348 // Initialize unused format indexes set. At this time, all formats are unused.
2349 for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx )
2350 maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx );
2353 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm )
2355 rStrm >> maData.maRect >> maData.mnFlags >> maData.mnGroupIdx;
2358 void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm )
2360 switch( rStrm.GetRecId() )
2362 case EXC_ID_CHCHART3D:
2363 mxChart3d.reset( new XclImpChChart3d );
2364 mxChart3d->ReadChChart3d( rStrm );
2365 break;
2366 case EXC_ID_CHLEGEND:
2367 mxLegend.reset( new XclImpChLegend( GetChRoot() ) );
2368 mxLegend->ReadRecordGroup( rStrm );
2369 break;
2370 case EXC_ID_CHDEFAULTTEXT:
2371 GetChartData().ReadChDefaultText( rStrm );
2372 break;
2373 case EXC_ID_CHDROPBAR:
2374 ReadChDropBar( rStrm );
2375 break;
2376 case EXC_ID_CHCHARTLINE:
2377 ReadChChartLine( rStrm );
2378 break;
2379 case EXC_ID_CHDATAFORMAT:
2380 ReadChDataFormat( rStrm );
2381 break;
2382 default:
2383 maType.ReadChType( rStrm );
2387 void XclImpChTypeGroup::Finalize()
2389 // check and set valid chart type
2390 bool bStockChart =
2391 (maType.GetRecId() == EXC_ID_CHLINE) && // must be a line chart
2392 !mxChart3d && // must be a 2d chart
2393 HasHiLoLine() && // must contain hi-lo lines
2394 (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3)); // correct series count
2395 maType.Finalize( bStockChart );
2397 // extended type info
2398 maTypeInfo.Set( maType.GetTypeInfo(), mxChart3d.is(), false );
2400 // reverse series order for some unstacked 2D chart types
2401 if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() )
2402 ::std::reverse( maSeries.begin(), maSeries.end() );
2404 // update chart type group format, may depend on chart type finalized above
2405 if( mxGroupFmt.is() )
2406 mxGroupFmt->UpdateGroupFormat( maTypeInfo );
2409 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries )
2411 if( xSeries.is() )
2412 maSeries.push_back( xSeries );
2413 // store first inserted series separately, series order may be reversed later
2414 if( !mxFirstSeries )
2415 mxFirstSeries = xSeries;
2418 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx )
2420 maUnusedFormats.erase( nFormatIdx );
2423 sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex()
2425 DBG_ASSERT( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2426 sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin();
2427 SetUsedFormatIndex( nFormatIdx );
2428 return nFormatIdx;
2431 bool XclImpChTypeGroup::HasVarPointFormat() const
2433 return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) &&
2434 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) || // multiple series allowed
2435 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) && // or exactly 1 series?
2436 (maSeries.size() == 1)));
2439 bool XclImpChTypeGroup::HasConnectorLines() const
2441 // existence of connector lines (only in stacked bar charts)
2442 bool bAnyStacked = maType.IsStacked() || maType.IsPercent();
2443 XclImpChLineFormatRef xConnLine = maChartLines.get( EXC_CHCHARTLINE_CONNECT );
2444 return bAnyStacked && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) && xConnLine.is() && xConnLine->HasLine();
2447 const String& XclImpChTypeGroup::GetSingleSeriesTitle() const
2449 // no automatic title for series with trendlines or error bars
2450 // pie charts always show an automatic title, even if more series exist
2451 return (mxFirstSeries.is() && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ?
2452 mxFirstSeries->GetTitle() : String::EmptyString();
2455 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const
2457 if( mxChart3d.is() )
2458 mxChart3d->Convert( rPropSet, Is3dWallChart() );
2461 Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const
2463 return maType.CreateCoordSystem( Is3dChart() );
2466 Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const
2468 DBG_ASSERT( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2470 // create the chart type object
2471 Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() );
2473 // bar chart connector lines
2474 if( HasConnectorLines() )
2476 ScfPropertySet aDiaProp( xDiagram );
2477 aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true );
2480 /* Stock chart needs special processing. Create one 'big' series with
2481 data sequences of different roles. */
2482 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2483 CreateStockSeries( xChartType, nApiAxesSetIdx );
2484 else
2485 CreateDataSeries( xChartType, nApiAxesSetIdx );
2487 return xChartType;
2490 Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const
2492 Reference< XLabeledDataSequence > xLabeledSeq;
2493 // create category sequence from first visible series
2494 if( mxFirstSeries.is() )
2495 xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG );
2496 return xLabeledSeq;
2499 void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm )
2501 sal_uInt16 nDropBar = EXC_CHDROPBAR_NONE;
2502 if( !maDropBars.has( EXC_CHDROPBAR_UP ) )
2503 nDropBar = EXC_CHDROPBAR_UP;
2504 else if( !maDropBars.has( EXC_CHDROPBAR_DOWN ) )
2505 nDropBar = EXC_CHDROPBAR_DOWN;
2507 if( nDropBar != EXC_CHDROPBAR_NONE )
2509 XclImpChDropBarRef xDropBar( new XclImpChDropBar( nDropBar ) );
2510 xDropBar->ReadRecordGroup( rStrm );
2511 maDropBars[ nDropBar ] = xDropBar;
2515 void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm )
2517 sal_uInt16 nLineId = rStrm.ReaduInt16();
2518 if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() )
2520 XclImpChLineFormatRef xLineFmt( new XclImpChLineFormat );
2521 xLineFmt->ReadChLineFormat( rStrm );
2522 maChartLines[ nLineId ] = xLineFmt;
2526 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm )
2528 // global series and data point format
2529 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2530 xDataFmt->ReadRecordGroup( rStrm );
2531 const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
2532 if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) &&
2533 (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) )
2534 mxGroupFmt = xDataFmt;
2538 void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType,
2539 Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const
2541 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2542 if( xSeriesCont.is() && xSeries.is() )
2544 // series stacking mode
2545 namespace cssc = ::com::sun::star::chart2;
2546 cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING;
2547 // stacked overrides deep-3d
2548 if( maType.IsStacked() || maType.IsPercent() )
2549 eStacking = cssc::StackingDirection_Y_STACKING;
2550 else if( Is3dDeepChart() )
2551 eStacking = cssc::StackingDirection_Z_STACKING;
2553 // additional series properties
2554 ScfPropertySet aSeriesProp( xSeries );
2555 aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking );
2556 aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx );
2558 // insert series into container
2561 xSeriesCont->addDataSeries( xSeries );
2563 catch( Exception& )
2565 DBG_ERRORFILE( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2570 void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2572 bool bSpline = false;
2573 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
2575 Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries();
2576 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2577 bSpline |= (*aIt)->HasSpline();
2579 // spline - TODO: set at single series (#i66858#)
2580 if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) )
2582 ScfPropertySet aTypeProp( xChartType );
2583 aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES );
2587 void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2589 // create the data series object
2590 Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2591 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2592 if( xDataSink.is() )
2594 // create a list of data sequences from all series
2595 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2596 DBG_ASSERT( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2597 int nRoleIdx = (maSeries.size() == 3) ? 1 : 0;
2598 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end();
2599 (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
2601 // create a data sequence with a specific role
2602 OUString aRole;
2603 switch( nRoleIdx )
2605 case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES; break;
2606 case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES; break;
2607 case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES; break;
2608 case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES; break;
2610 Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole );
2611 if( xDataSeq.is() )
2612 aLabeledSeqVec.push_back( xDataSeq );
2615 // attach labeled data sequences to series and insert series into chart type
2616 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2618 // formatting of special stock chart elements
2619 ScfPropertySet aTypeProp( xChartType );
2620 aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() );
2621 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() );
2622 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true );
2623 // hi-lo line format
2624 XclImpChLineFormatRef xHiLoLine = maChartLines.get( EXC_CHCHARTLINE_HILO );
2625 if( xHiLoLine.is() )
2627 ScfPropertySet aSeriesProp( xDataSeries );
2628 xHiLoLine->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2630 // white dropbar format
2631 XclImpChDropBarRef xUpBar = maDropBars.get( EXC_CHDROPBAR_UP );
2632 Reference< XPropertySet > xWhitePropSet;
2633 if( xUpBar.is() && aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY ) )
2635 ScfPropertySet aBarProp( xWhitePropSet );
2636 xUpBar->Convert( GetChRoot(), aBarProp );
2638 // black dropbar format
2639 XclImpChDropBarRef xDownBar = maDropBars.get( EXC_CHDROPBAR_DOWN );
2640 Reference< XPropertySet > xBlackPropSet;
2641 if( xDownBar.is() && aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY ) )
2643 ScfPropertySet aBarProp( xBlackPropSet );
2644 xDownBar->Convert( GetChRoot(), aBarProp );
2647 // insert the series into the chart type object
2648 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2652 // Axes =======================================================================
2654 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) :
2655 XclImpChRoot( rRoot )
2659 void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm )
2661 rStrm >> maData.mnCross >> maData.mnLabelFreq >> maData.mnTickFreq >> maData.mnFlags;
2664 void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const
2666 // do not overlap text unless all labels are visible
2667 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maData.mnLabelFreq == 1 );
2668 // do not break text into several lines unless all labels are visible
2669 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maData.mnLabelFreq == 1 );
2670 // do not stagger labels in two lines
2671 namespace cssc = ::com::sun::star::chart;
2672 rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE );
2674 // reverse order
2675 namespace cssc2 = ::com::sun::star::chart2;
2676 bool bReverse = ::get_flag( maData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient;
2677 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
2679 //! TODO #i58731# show n-th category
2682 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const
2684 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
2685 does not move the Y axis in 3D charts, regardless of actual settings.
2686 But: the Y axis has to be moved to "end", if the X axis is mirrored,
2687 to keep it at the left end of the chart. */
2688 bool bMaxCross = ::get_flag( maData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS );
2689 namespace cssc = ::com::sun::star::chart;
2690 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
2691 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
2693 // crossing position
2694 double fCrossingPos = b3dChart ? 1.0 : maData.mnCross;
2695 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
2698 // ----------------------------------------------------------------------------
2700 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) :
2701 XclImpChRoot( rRoot )
2705 void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm )
2707 rStrm >> maData.mfMin
2708 >> maData.mfMax
2709 >> maData.mfMajorStep
2710 >> maData.mfMinorStep
2711 >> maData.mfCross
2712 >> maData.mnFlags;
2715 void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const
2717 // scaling algorithm
2718 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
2719 OUString aScalingService = bLogScale ? SERVICE_CHART2_LOGSCALING : SERVICE_CHART2_LINEARSCALING;
2720 rScaleData.Scaling.set( ScfApiHelper::CreateInstance( aScalingService ), UNO_QUERY );
2722 // min/max
2723 lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) );
2724 lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) );
2726 // increment
2727 bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR );
2728 bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR );
2729 // major increment
2730 IncrementData& rIncrementData = rScaleData.IncrementData;
2731 lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor );
2732 // minor increment
2733 Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2734 rSubIncrementSeq.realloc( 1 );
2735 Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount;
2736 if( bLogScale )
2738 rIntervalCount <<= sal_Int32( 10 );
2740 else
2742 sal_Int32 nCount = 0;
2743 if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) )
2745 double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5;
2746 if( fCount < 1001.0 )
2747 nCount = static_cast< sal_Int32 >( fCount );
2749 lclSetValueOrClearAny( rIntervalCount, nCount, nCount == 0 );
2752 // reverse order
2753 namespace cssc2 = ::com::sun::star::chart2;
2754 bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient;
2755 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
2758 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const
2760 bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2761 bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2762 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
2764 // crossing mode (max-cross flag overrides other crossing settings)
2765 namespace cssc = ::com::sun::star::chart;
2766 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
2767 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
2769 // crossing position
2770 double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross;
2771 if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos );
2772 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
2775 // ----------------------------------------------------------------------------
2777 namespace {
2779 sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos )
2781 using namespace ::com::sun::star::chart2::TickmarkStyle;
2782 sal_Int32 nApiTickmarks = NONE;
2783 ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) );
2784 ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) );
2785 return nApiTickmarks;
2788 ::com::sun::star::chart::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos )
2790 using namespace ::com::sun::star::chart;
2791 switch( nXclLabelPos )
2793 case EXC_CHTICK_LOW: return ChartAxisLabelPosition_OUTSIDE_START;
2794 case EXC_CHTICK_HIGH: return ChartAxisLabelPosition_OUTSIDE_END;
2795 case EXC_CHTICK_NEXT: return ChartAxisLabelPosition_NEAR_AXIS;
2797 return ChartAxisLabelPosition_NEAR_AXIS;
2800 } // namespace
2802 XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) :
2803 XclImpChRoot( rRoot )
2807 void XclImpChTick::ReadChTick( XclImpStream& rStrm )
2809 rStrm >> maData.mnMajor
2810 >> maData.mnMinor
2811 >> maData.mnLabelPos
2812 >> maData.mnBackMode
2813 >> maData.maRect
2814 >> maData.maTextColor
2815 >> maData.mnFlags;
2817 if( GetBiff() == EXC_BIFF8 )
2819 // #116397# BIFF8: index into palette used instead of RGB data
2820 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
2821 // rotation
2822 rStrm >> maData.mnRotation;
2824 else
2826 // BIFF2-BIFF7: get rotation from text orientation
2827 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 );
2828 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
2832 Color XclImpChTick::GetFontColor() const
2834 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
2837 sal_uInt16 XclImpChTick::GetRotation() const
2839 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation;
2842 void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const
2844 rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) );
2845 rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) );
2846 rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) );
2847 rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, ::com::sun::star::chart::ChartAxisMarkPosition_AT_AXIS );
2850 // ----------------------------------------------------------------------------
2852 XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) :
2853 XclImpChRoot( rRoot ),
2854 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2856 maData.mnType = nAxisType;
2859 void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm )
2861 rStrm >> maData.mnType >> maData.maRect;
2864 void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm )
2866 switch( rStrm.GetRecId() )
2868 case EXC_ID_CHLABELRANGE:
2869 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
2870 mxLabelRange->ReadChLabelRange( rStrm );
2871 break;
2872 case EXC_ID_CHVALUERANGE:
2873 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
2874 mxValueRange->ReadChValueRange( rStrm );
2875 break;
2876 case EXC_ID_CHFORMAT:
2877 rStrm >> mnNumFmtIdx;
2878 break;
2879 case EXC_ID_CHTICK:
2880 mxTick.reset( new XclImpChTick( GetChRoot() ) );
2881 mxTick->ReadChTick( rStrm );
2882 break;
2883 case EXC_ID_CHFONT:
2884 mxFont.reset( new XclImpChFont );
2885 mxFont->ReadChFont( rStrm );
2886 break;
2887 case EXC_ID_CHAXISLINE:
2888 ReadChAxisLine( rStrm );
2889 break;
2893 void XclImpChAxis::Finalize()
2895 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
2896 if( !mxLabelRange )
2897 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
2898 if( !mxValueRange )
2899 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
2900 // remove invisible grid lines completely
2901 if( mxMajorGrid.is() && !mxMajorGrid->HasLine() )
2902 mxMajorGrid.reset();
2903 if( mxMinorGrid.is() && !mxMinorGrid->HasLine() )
2904 mxMinorGrid.reset();
2905 // default tick settings different in OOChart and Excel
2906 if( !mxTick )
2907 mxTick.reset( new XclImpChTick( GetChRoot() ) );
2908 // #i4140# different default axis line color
2909 if( !mxAxisLine )
2911 XclChLineFormat aLineFmt;
2912 // set "show axis" flag, default if line format record is missing
2913 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS );
2914 mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) );
2916 // add wall/floor frame for 3d charts
2917 if( !mxWallFrame )
2918 CreateWallFrame();
2921 sal_uInt16 XclImpChAxis::GetFontIndex() const
2923 return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
2926 Color XclImpChAxis::GetFontColor() const
2928 return mxTick.is() ? mxTick->GetFontColor() : GetFontAutoColor();
2931 sal_uInt16 XclImpChAxis::GetRotation() const
2933 return mxTick.is() ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION;
2936 Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const
2938 namespace cssc2 = ::com::sun::star::chart2;
2940 // create the axis object (always)
2941 Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY );
2942 if( xAxis.is() )
2944 ScfPropertySet aAxisProp( xAxis );
2945 // #i58688# axis enabled
2946 aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() );
2948 // axis line properties
2949 if( mxAxisLine.is() )
2950 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2951 // axis ticks properties
2952 if( mxTick.is() )
2953 mxTick->Convert( aAxisProp );
2955 // axis caption text --------------------------------------------------
2957 // radar charts disable their category labels via chart type, not via axis
2958 bool bHasLabels = HasLabels() &&
2959 ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels());
2960 aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels );
2961 if( bHasLabels )
2963 // font settings from CHFONT record or from default text
2964 if( mxFont.is() )
2965 ConvertFontBase( GetChRoot(), aAxisProp );
2966 else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ).get() )
2967 pDefText->ConvertFont( aAxisProp );
2968 // label text rotation
2969 ConvertRotationBase( GetChRoot(), aAxisProp, true );
2970 // number format
2971 sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx );
2972 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
2973 aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) );
2976 // axis scaling and increment -----------------------------------------
2978 const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo();
2979 ScaleData aScaleData = xAxis->getScaleData();
2980 // set axis type
2981 switch( GetAxisType() )
2983 case EXC_CHAXIS_X:
2984 if( rTypeInfo.mbCategoryAxis )
2986 aScaleData.AxisType = cssc2::AxisType::CATEGORY;
2987 aScaleData.Categories = rTypeGroup.CreateCategSequence();
2989 else
2990 aScaleData.AxisType = cssc2::AxisType::REALNUMBER;
2991 break;
2992 case EXC_CHAXIS_Y:
2993 aScaleData.AxisType = rTypeGroup.IsPercent() ?
2994 cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER;
2995 break;
2996 case EXC_CHAXIS_Z:
2997 aScaleData.AxisType = cssc2::AxisType::SERIES;
2998 break;
3000 // axis scaling settings, dependent on axis type
3001 switch( aScaleData.AxisType )
3003 case cssc2::AxisType::CATEGORY:
3004 case cssc2::AxisType::SERIES:
3005 // #i71684# radar charts have reversed rotation direction
3006 mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR );
3007 break;
3008 case cssc2::AxisType::REALNUMBER:
3009 case cssc2::AxisType::PERCENT:
3010 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3011 mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
3012 break;
3013 default:
3014 DBG_ERRORFILE( "XclImpChAxis::CreateAxis - unknown axis type" );
3017 /* Do not set a value to the Origin member anymore (will be done via
3018 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3019 aScaleData.Origin.clear();
3021 // write back
3022 xAxis->setScaleData( aScaleData );
3024 // grid ---------------------------------------------------------------
3026 // main grid
3027 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3028 aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() );
3029 if( mxMajorGrid.is() )
3030 mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3031 // sub grid
3032 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3033 if( aSubGridPropSeq.hasElements() )
3035 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3036 aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() );
3037 if( mxMinorGrid.is() )
3038 mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3041 // position of crossing axis ------------------------------------------
3043 if( pCrossingAxis )
3044 pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup );
3046 return xAxis;
3049 void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const
3051 if( mxWallFrame.is() )
3052 mxWallFrame->Convert( rPropSet );
3055 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const
3057 if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) )
3058 mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() );
3059 else
3060 mxValueRange->ConvertAxisPosition( rPropSet );
3063 void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm )
3065 XclImpChLineFormatRef* pxLineFmt = 0;
3066 bool bWallFrame = false;
3067 switch( rStrm.ReaduInt16() )
3069 case EXC_CHAXISLINE_AXISLINE: pxLineFmt = &mxAxisLine; break;
3070 case EXC_CHAXISLINE_MAJORGRID: pxLineFmt = &mxMajorGrid; break;
3071 case EXC_CHAXISLINE_MINORGRID: pxLineFmt = &mxMinorGrid; break;
3072 case EXC_CHAXISLINE_WALLS: bWallFrame = true; break;
3074 if( bWallFrame )
3075 CreateWallFrame();
3077 bool bLoop = pxLineFmt || bWallFrame;
3078 while( bLoop )
3080 sal_uInt16 nRecId = rStrm.GetNextRecId();
3081 bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) ||
3082 (nRecId == EXC_ID_CHAREAFORMAT) ||
3083 (nRecId == EXC_ID_CHESCHERFORMAT))
3084 && rStrm.StartNextRecord();
3085 if( bLoop )
3087 if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) )
3089 pxLineFmt->reset( new XclImpChLineFormat );
3090 (*pxLineFmt)->ReadChLineFormat( rStrm );
3092 else if( bWallFrame && mxWallFrame.is() )
3094 mxWallFrame->ReadSubRecord( rStrm );
3100 void XclImpChAxis::CreateWallFrame()
3102 switch( GetAxisType() )
3104 case EXC_CHAXIS_X:
3105 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) );
3106 break;
3107 case EXC_CHAXIS_Y:
3108 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) );
3109 break;
3110 default:
3111 mxWallFrame.reset();
3115 // ----------------------------------------------------------------------------
3117 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3118 XclImpChRoot( rRoot )
3120 maData.mnAxesSetId = nAxesSetId;
3123 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm )
3125 rStrm >> maData.mnAxesSetId >> maData.maRect;
3128 void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm )
3130 switch( rStrm.GetRecId() )
3132 case EXC_ID_CHFRAMEPOS:
3133 mxPos.reset( new XclImpChFramePos );
3134 mxPos->ReadChFramePos( rStrm );
3135 break;
3136 case EXC_ID_CHAXIS:
3137 ReadChAxis( rStrm );
3138 break;
3139 case EXC_ID_CHTEXT:
3140 ReadChText( rStrm );
3141 break;
3142 case EXC_ID_CHPLOTFRAME:
3143 ReadChPlotFrame( rStrm );
3144 break;
3145 case EXC_ID_CHTYPEGROUP:
3146 ReadChTypeGroup( rStrm );
3147 break;
3151 void XclImpChAxesSet::Finalize()
3153 if( IsValidAxesSet() )
3155 // finalize chart type groups, erase empty groups without series
3156 XclImpChTypeGroupMap aValidGroups;
3157 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3159 XclImpChTypeGroupRef xTypeGroup = aIt->second;
3160 xTypeGroup->Finalize();
3161 if( xTypeGroup->IsValidGroup() )
3162 aValidGroups[ aIt->first ] = xTypeGroup;
3164 maTypeGroups.swap( aValidGroups );
3167 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3168 if( IsValidAxesSet() )
3170 // always create missing axis objects
3171 if( !mxXAxis )
3172 mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) );
3173 if( !mxYAxis )
3174 mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) );
3175 if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() )
3176 mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) );
3178 // finalize axes
3179 if( mxXAxis.is() ) mxXAxis->Finalize();
3180 if( mxYAxis.is() ) mxYAxis->Finalize();
3181 if( mxZAxis.is() ) mxZAxis->Finalize();
3183 // finalize axis titles
3184 XclImpChTextRef xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE );
3185 lclFinalizeTitle( mxXAxisTitle, xDefText );
3186 lclFinalizeTitle( mxYAxisTitle, xDefText );
3187 lclFinalizeTitle( mxZAxisTitle, xDefText );
3189 // #i47745# missing plot frame -> invisible border and area
3190 if( !mxPlotFrame )
3191 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3195 XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const
3197 XclImpChTypeGroupRef xTypeGroup;
3198 if( !maTypeGroups.empty() )
3199 xTypeGroup = maTypeGroups.begin()->second;
3200 return xTypeGroup;
3203 XclImpChLegendRef XclImpChAxesSet::GetLegend() const
3205 XclImpChLegendRef xLegend;
3206 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt )
3207 xLegend = aIt->second->GetLegend();
3208 return xLegend;
3211 const String& XclImpChAxesSet::GetSingleSeriesTitle() const
3213 return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : String::EmptyString();
3216 void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const
3218 if( IsValidAxesSet() && xDiagram.is() )
3220 // diagram background formatting
3221 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY )
3222 ConvertBackground( xDiagram );
3224 // create the coordinate system, this inserts all chart types and series
3225 Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram );
3226 if( xCoordSystem.is() )
3228 // insert coordinate system, if not already done
3231 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW );
3232 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3233 if( aCoordSystems.getLength() == 0 )
3234 xCoordSystemCont->addCoordinateSystem( xCoordSystem );
3236 catch( Exception& )
3238 DBG_ERRORFILE( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3241 // create the axes with grids and axis titles and insert them into the diagram
3242 ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() );
3243 ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() );
3244 ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 );
3249 void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm )
3251 XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) );
3252 xAxis->ReadRecordGroup( rStrm );
3254 switch( xAxis->GetAxisType() )
3256 case EXC_CHAXIS_X: mxXAxis = xAxis; break;
3257 case EXC_CHAXIS_Y: mxYAxis = xAxis; break;
3258 case EXC_CHAXIS_Z: mxZAxis = xAxis; break;
3262 void XclImpChAxesSet::ReadChText( XclImpStream& rStrm )
3264 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3265 xText->ReadRecordGroup( rStrm );
3267 switch( xText->GetLinkTarget() )
3269 case EXC_CHOBJLINK_XAXIS: mxXAxisTitle = xText; break;
3270 case EXC_CHOBJLINK_YAXIS: mxYAxisTitle = xText; break;
3271 case EXC_CHOBJLINK_ZAXIS: mxZAxisTitle = xText; break;
3275 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm )
3277 if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() )
3279 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3280 mxPlotFrame->ReadRecordGroup( rStrm );
3284 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm )
3286 XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
3287 xTypeGroup->ReadRecordGroup( rStrm );
3288 maTypeGroups[ xTypeGroup->GetGroupIdx() ] = xTypeGroup;
3291 Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const
3293 Reference< XCoordinateSystem > xCoordSystem;
3295 /* Try to get existing ccordinate system. For now, all series from primary
3296 and secondary axes sets are inserted into one coordinate system. Later,
3297 this should be changed to use one coordinate system for each axes set. */
3298 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY );
3299 if( xCoordSystemCont.is() )
3301 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3302 DBG_ASSERT( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3303 if( aCoordSystems.getLength() > 0 )
3304 xCoordSystem = aCoordSystems[ 0 ];
3307 // create the coordinate system according to the first chart type
3308 if( !xCoordSystem.is() )
3310 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3311 if( xTypeGroup.is() )
3313 xCoordSystem = xTypeGroup->CreateCoordSystem();
3314 // convert 3d chart settings
3315 ScfPropertySet aDiaProp( xDiagram );
3316 xTypeGroup->ConvertChart3d( aDiaProp );
3320 /* Create XChartType objects for all chart type groups. Each group will
3321 add its series to the data provider attached to the chart document. */
3322 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3323 if( xChartTypeCont.is() )
3325 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3326 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3330 Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx );
3331 if( xChartType.is() )
3332 xChartTypeCont->addChartType( xChartType );
3334 catch( Exception& )
3336 DBG_ERRORFILE( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3341 return xCoordSystem;
3344 void XclImpChAxesSet::ConvertAxis(
3345 XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle,
3346 Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const
3348 if( xChAxis.is() )
3350 // create and attach the axis object
3351 Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis );
3352 if( xAxis.is() )
3354 // create and attach the axis title
3355 if( xChAxisTitle.is() )
3357 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
3358 if( xTitled.is() )
3359 xTitled->setTitleObject( xChAxisTitle->CreateTitle() );
3362 // insert axis into coordinate system
3365 sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension();
3366 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3367 xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx );
3369 catch( Exception& )
3371 DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3377 Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const
3379 Reference< XAxis > xAxis;
3380 if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() )
3381 xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis );
3382 return xAxis;
3385 void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const
3387 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3388 if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
3390 // wall/floor formatting (3D charts)
3391 if( mxXAxis.is() )
3393 ScfPropertySet aWallProp( xDiagram->getWall() );
3394 mxXAxis->ConvertWall( aWallProp );
3396 if( mxYAxis.is() )
3398 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3399 mxYAxis->ConvertWall( aFloorProp );
3402 else if( mxPlotFrame.is() )
3404 // diagram background formatting
3405 ScfPropertySet aWallProp( xDiagram->getWall() );
3406 mxPlotFrame->Convert( aWallProp );
3410 // The chart object ===========================================================
3412 XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) :
3413 XclImpChRoot( rRoot, this )
3415 mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3416 mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3419 XclImpChChart::~XclImpChChart()
3423 void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm )
3425 // coordinates are stored as 16.16 fixed point
3426 rStrm >> maRect;
3429 void XclImpChChart::ReadSubRecord( XclImpStream& rStrm )
3431 switch( rStrm.GetRecId() )
3433 case EXC_ID_CHFRAME:
3434 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3435 mxFrame->ReadRecordGroup( rStrm );
3436 break;
3437 case EXC_ID_CHSERIES:
3438 ReadChSeries( rStrm );
3439 break;
3440 case EXC_ID_CHPROPERTIES:
3441 ReadChProperties( rStrm );
3442 break;
3443 case EXC_ID_CHDEFAULTTEXT:
3444 ReadChDefaultText( rStrm );
3445 break;
3446 case EXC_ID_CHAXESSET:
3447 ReadChAxesSet( rStrm );
3448 break;
3449 case EXC_ID_CHTEXT:
3450 ReadChText( rStrm );
3451 break;
3452 case EXC_ID_CHEND:
3453 Finalize(); // finalize the entire chart object
3454 break;
3458 void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm )
3460 sal_uInt16 nTextId = rStrm.ReaduInt16();
3461 if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() )
3463 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3464 xText->ReadRecordGroup( rStrm );
3465 maDefTexts[ nTextId ] = xText;
3469 void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm )
3471 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
3472 xDataFmt->ReadRecordGroup( rStrm );
3473 if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3475 XclImpChDataFormatRef& rxMapFmt = maDataFmts[ xDataFmt->GetPointPos() ];
3476 /* Do not overwrite existing data format group, Excel always uses the
3477 first data format group occuring in any CHSERIES group. */
3478 if( !rxMapFmt )
3479 rxMapFmt = xDataFmt;
3483 void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
3485 if( !mxFrame )
3486 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3487 mxFrame->UpdateObjFrame( rLineData, rFillData );
3490 XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3492 XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx );
3493 if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx );
3494 if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup();
3495 return xTypeGroup;
3498 XclImpChTextRef XclImpChChart::GetDefaultText( XclChTextType eTextType ) const
3500 sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL;
3501 bool bBiff8 = GetBiff() == EXC_BIFF8;
3502 switch( eTextType )
3504 case EXC_CHTEXTTYPE_TITLE: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3505 case EXC_CHTEXTTYPE_LEGEND: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3506 case EXC_CHTEXTTYPE_AXISTITLE: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3507 case EXC_CHTEXTTYPE_AXISLABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3508 case EXC_CHTEXTTYPE_DATALABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3510 return maDefTexts.get( nDefTextId );
3513 void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc, ScfProgressBar& rProgress, const OUString& rObjName ) const
3515 // initialize conversion (locks the model to suppress any internal updates)
3516 InitConversion( xChartDoc );
3518 // chart frame and title
3519 if( mxFrame.is() )
3521 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3522 mxFrame->Convert( aFrameProp );
3524 if( mxTitle.is() )
3526 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3527 Reference< XTitle > xTitle = mxTitle->CreateTitle();
3528 if( xTitled.is() && xTitle.is() )
3529 xTitled->setTitleObject( xTitle );
3532 /* Create the diagram object and attach it to the chart document. Currently,
3533 one diagram is used to carry all coordinate systems and data series. */
3534 Reference< XDiagram > xDiagram = CreateDiagram();
3535 xChartDoc->setFirstDiagram( xDiagram );
3537 // coordinate systems and chart types, convert axis settings
3538 mxPrimAxesSet->Convert( xDiagram );
3539 mxSecnAxesSet->Convert( xDiagram );
3541 // legend
3542 if( xDiagram.is() && mxLegend.is() )
3543 xDiagram->setLegend( mxLegend->CreateLegend() );
3545 // set the IncludeHiddenCells property via the old API as only this ensures that the data provider and al created sequences get this flag correctly
3546 Reference< com::sun::star::chart::XChartDocument > xStandardApiChartDoc( xChartDoc, UNO_QUERY );
3547 if( xStandardApiChartDoc.is() )
3549 ScfPropertySet aDiagramProp( xStandardApiChartDoc->getDiagram() );
3550 bool bShowVisCells = (maProps.mnFlags & EXC_CHPROPS_SHOWVISIBLEONLY);
3551 aDiagramProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells );
3554 // unlock the model
3555 FinishConversion( rProgress );
3557 ScDocument* pDoc = &GetRoot().GetDoc();
3558 ScChartListenerCollection* pChartCollection = pDoc->GetChartListenerCollection();
3559 if (pChartCollection)
3561 // Now, start listening to this chart.
3562 ::std::auto_ptr< vector<ScSharedTokenRef> > pRefTokens(new vector<ScSharedTokenRef>);
3563 for (XclImpChSeriesVec::const_iterator itr = maSeries.begin(), itrEnd = maSeries.end(); itr != itrEnd; ++itr)
3565 const XclImpChSeriesRef& rSeries = *itr;
3566 rSeries->FillAllSourceLinks(*pRefTokens);
3568 if (!pRefTokens->empty())
3570 ::std::auto_ptr<ScChartListener> pListener(
3571 new ScChartListener(rObjName, pDoc, pRefTokens.release()));
3572 pListener->SetDirty(true);
3573 pListener->StartListeningTo();
3574 pChartCollection->Insert(pListener.release());
3580 void XclImpChChart::ReadChSeries( XclImpStream& rStrm )
3582 sal_uInt16 nNewSeriesIdx = static_cast< sal_uInt16 >( maSeries.size() );
3583 XclImpChSeriesRef xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx ) );
3584 xSeries->ReadRecordGroup( rStrm );
3585 maSeries.push_back( xSeries );
3588 void XclImpChChart::ReadChProperties( XclImpStream& rStrm )
3590 rStrm >> maProps.mnFlags >> maProps.mnEmptyMode;
3593 void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm )
3595 XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) );
3596 xAxesSet->ReadRecordGroup( rStrm );
3597 switch( xAxesSet->GetAxesSetId() )
3599 case EXC_CHAXESSET_PRIMARY: mxPrimAxesSet = xAxesSet; break;
3600 case EXC_CHAXESSET_SECONDARY: mxSecnAxesSet = xAxesSet; break;
3604 void XclImpChChart::ReadChText( XclImpStream& rStrm )
3606 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3607 xText->ReadRecordGroup( rStrm );
3608 switch( xText->GetLinkTarget() )
3610 case EXC_CHOBJLINK_TITLE:
3611 mxTitle = xText;
3612 break;
3613 case EXC_CHOBJLINK_DATA:
3615 sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx;
3616 if( nSeriesIdx < maSeries.size() )
3617 maSeries[ nSeriesIdx ]->SetDataLabel( xText );
3619 break;
3623 void XclImpChChart::Finalize()
3625 // finalize series (must be done first)
3626 FinalizeSeries();
3627 // #i49218# legend may be attached to primary or secondary axes set
3628 mxLegend = mxPrimAxesSet->GetLegend();
3629 if( !mxLegend )
3630 mxLegend = mxSecnAxesSet->GetLegend();
3631 if( mxLegend.is() )
3632 mxLegend->Finalize();
3633 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
3634 mxPrimAxesSet->Finalize();
3635 mxSecnAxesSet->Finalize();
3636 // formatting of all series
3637 FinalizeDataFormats();
3638 // #i47745# missing frame -> invisible border and area
3639 if( !mxFrame )
3640 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3641 // chart title
3642 FinalizeTitle();
3645 void XclImpChChart::FinalizeSeries()
3647 for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt )
3649 XclImpChSeriesRef xSeries = *aSIt;
3650 if( xSeries->HasParentSeries() )
3652 /* Process child series (trend lines and error bars). Data of
3653 child series will be set at the connected parent series. */
3654 if( xSeries->GetParentIdx() < maSeries.size() )
3655 maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries );
3657 else
3659 // insert the series into the related chart type group
3660 if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() )
3661 pTypeGroup->AddSeries( xSeries );
3666 void XclImpChChart::FinalizeDataFormats()
3668 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
3669 Each CHDATAFORMAT group specifies the series and data point it is
3670 assigned to. This makes it possible to have a data format that is
3671 related to another series, e.g. a CHDATAFORMAT group for series 2 is
3672 part of a CHSERIES group that describes series 1. Therefore the chart
3673 itself has collected all CHDATAFORMAT groups to be able to store data
3674 format groups for series that have not been imported at that time. This
3675 loop finally assigns these groups to the related series. */
3676 for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt )
3678 sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx;
3679 if( nSeriesIdx < maSeries.size() )
3680 maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second );
3683 /* #i51639# (part 2): Finalize data formats of all series. This adds for
3684 example missing CHDATAFORMAT groups for entire series that are needed
3685 for automatic colors of lines and areas. */
3686 for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt )
3687 (*aVIt)->FinalizeDataFormats();
3690 void XclImpChChart::FinalizeTitle()
3692 if( (!mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString())) && !mxSecnAxesSet->IsValidAxesSet() )
3694 /* Chart title is auto-generated from series title, if there is only
3695 one series with title in the chart. */
3696 const String& rSerTitle = mxPrimAxesSet->GetSingleSeriesTitle();
3697 if( rSerTitle.Len() > 0 )
3699 if( !mxTitle )
3700 mxTitle.reset( new XclImpChText( GetChRoot() ) );
3701 mxTitle->SetString( rSerTitle );
3705 // will reset mxTitle, if it does not contain a string
3706 lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ) );
3709 Reference< XDiagram > XclImpChChart::CreateDiagram() const
3711 // create a diagram object
3712 Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY );
3714 // convert global chart settings
3715 ScfPropertySet aDiaProp( xDiagram );
3717 // treatment of missing values
3718 using namespace ::com::sun::star::chart::MissingValueTreatment;
3719 sal_Int32 nMissingValues = LEAVE_GAP;
3720 switch( maProps.mnEmptyMode )
3722 case EXC_CHPROPS_EMPTY_SKIP: nMissingValues = LEAVE_GAP; break;
3723 case EXC_CHPROPS_EMPTY_ZERO: nMissingValues = USE_ZERO; break;
3724 case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE; break;
3726 aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues );
3728 return xDiagram;
3731 // ----------------------------------------------------------------------------
3733 XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) :
3734 XclImpRoot( rRoot ),
3735 mbOwnTab( bOwnTab ),
3736 mbIsPivotChart( false )
3740 void XclImpChart::ReadChartSubStream( XclImpStream& rStrm )
3742 XclImpPageSettings& rPageSett = GetPageSettings();
3743 XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
3745 bool bLoop = true;
3746 while( bLoop && rStrm.StartNextRecord() )
3748 // page settings - only for charts in entire sheet
3749 if( mbOwnTab ) switch( rStrm.GetRecId() )
3751 case EXC_ID_HORPAGEBREAKS:
3752 case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( rStrm ); break;
3753 case EXC_ID_HEADER:
3754 case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( rStrm ); break;
3755 case EXC_ID_LEFTMARGIN:
3756 case EXC_ID_RIGHTMARGIN:
3757 case EXC_ID_TOPMARGIN:
3758 case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( rStrm ); break;
3759 case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( rStrm ); break;
3760 case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm ); break;
3761 case EXC_ID_HCENTER:
3762 case EXC_ID_VCENTER: rPageSett.ReadCenter( rStrm ); break;
3763 case EXC_ID_SETUP: rPageSett.ReadSetup( rStrm ); break;
3764 case EXC_ID8_IMGDATA: rPageSett.ReadImgData( rStrm ); break;
3766 case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( rStrm, true );break;
3767 case EXC_ID_SCL: rTabViewSett.ReadScl( rStrm ); break;
3768 case EXC_ID_SHEETEXT: //0x0862
3770 XclImpPalette& rPal = GetPalette();
3771 rTabViewSett.ReadTabBgColor( rStrm, rPal);
3773 break;
3776 switch( rStrm.GetRecId() )
3778 case EXC_ID_EOF: bLoop = false; break;
3780 // #i31882# ignore embedded chart objects
3781 case EXC_ID2_BOF:
3782 case EXC_ID3_BOF:
3783 case EXC_ID4_BOF:
3784 case EXC_ID5_BOF: XclTools::SkipSubStream( rStrm ); break;
3786 case EXC_ID_CHCHART: ReadChChart( rStrm ); break;
3787 case EXC_ID_OBJ: GetTracer().TraceChartEmbeddedObj(); break;
3789 case EXC_ID8_CHPIVOTREF:
3790 GetTracer().TracePivotChartExists();
3791 mbIsPivotChart = true;
3792 break;
3797 void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
3799 if( !mxChartData )
3800 mxChartData.reset( new XclImpChChart( GetRoot() ) );
3801 mxChartData->UpdateObjFrame( rLineData, rFillData );
3804 sal_Size XclImpChart::GetProgressSize() const
3806 return mxChartData.is() ? mxChartData->GetProgressSize() : 0;
3809 void XclImpChart::Convert( Reference< XModel > xModel, ScfProgressBar& rProgress, const OUString& rObjName ) const
3811 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3812 if( mxChartData.is() && xChartDoc.is() )
3813 mxChartData->Convert( xChartDoc, rProgress, rObjName );
3816 void XclImpChart::ReadChChart( XclImpStream& rStrm )
3818 mxChartData.reset( new XclImpChChart( GetRoot() ) );
3819 mxChartData->ReadRecordGroup( rStrm );
3822 // ============================================================================