bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xichart.cxx
blob10d858ac9a60ef56f9b8d72e6cf762d3fca08cf1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xichart.hxx"
22 #include <algorithm>
23 #include <memory>
25 #include <com/sun/star/frame/XModel.hpp>
26 #include <com/sun/star/drawing/Direction3D.hpp>
27 #include <com/sun/star/drawing/ProjectionMode.hpp>
28 #include <com/sun/star/drawing/ShadeMode.hpp>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
31 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
32 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
33 #include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
34 #include <com/sun/star/chart/ChartAxisPosition.hpp>
35 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
36 #include <com/sun/star/chart/TimeInterval.hpp>
37 #include <com/sun/star/chart/TimeUnit.hpp>
38 #include <com/sun/star/chart/XChartDocument.hpp>
39 #include <com/sun/star/chart/XDiagramPositioning.hpp>
40 #include <com/sun/star/chart/DataLabelPlacement.hpp>
41 #include <com/sun/star/chart/ErrorBarStyle.hpp>
42 #include <com/sun/star/chart/MissingValueTreatment.hpp>
43 #include <com/sun/star/chart2/CartesianCoordinateSystem2d.hpp>
44 #include <com/sun/star/chart2/CartesianCoordinateSystem3d.hpp>
45 #include <com/sun/star/chart2/FormattedString.hpp>
46 #include <com/sun/star/chart2/LogarithmicScaling.hpp>
47 #include <com/sun/star/chart2/LinearScaling.hpp>
48 #include <com/sun/star/chart2/PolarCoordinateSystem2d.hpp>
49 #include <com/sun/star/chart2/PolarCoordinateSystem3d.hpp>
50 #include <com/sun/star/chart2/XChartDocument.hpp>
51 #include <com/sun/star/chart2/XDiagram.hpp>
52 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
53 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
54 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
55 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
56 #include <com/sun/star/chart2/XTitled.hpp>
57 #include <com/sun/star/chart2/AxisType.hpp>
58 #include <com/sun/star/chart2/CurveStyle.hpp>
59 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
60 #include <com/sun/star/chart2/DataPointLabel.hpp>
61 #include <com/sun/star/chart2/LegendPosition.hpp>
62 #include <com/sun/star/chart2/StackingDirection.hpp>
63 #include <com/sun/star/chart2/TickmarkStyle.hpp>
64 #include <com/sun/star/chart2/RelativePosition.hpp>
65 #include <com/sun/star/chart2/RelativeSize.hpp>
66 #include <com/sun/star/chart2/data/XDataProvider.hpp>
67 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
68 #include <com/sun/star/chart2/data/XDataSink.hpp>
69 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
71 #include <sfx2/objsh.hxx>
72 #include <svx/svdpage.hxx>
73 #include <svx/unoapi.hxx>
75 #include "document.hxx"
76 #include "drwlayer.hxx"
77 #include "rangeutl.hxx"
78 #include "tokenarray.hxx"
79 #include "token.hxx"
80 #include "compiler.hxx"
81 #include "reftokenhelper.hxx"
82 #include "chartlis.hxx"
83 #include "fprogressbar.hxx"
84 #include "xltracer.hxx"
85 #include "xistream.hxx"
86 #include "xiformula.hxx"
87 #include "xistyle.hxx"
88 #include "xipage.hxx"
89 #include "xiview.hxx"
91 using ::com::sun::star::uno::Any;
92 using ::com::sun::star::uno::Reference;
93 using ::com::sun::star::uno::Sequence;
94 using ::com::sun::star::uno::UNO_QUERY;
95 using ::com::sun::star::uno::UNO_QUERY_THROW;
96 using ::com::sun::star::uno::UNO_SET_THROW;
97 using ::com::sun::star::uno::Exception;
98 using ::com::sun::star::beans::XPropertySet;
99 using ::com::sun::star::lang::XMultiServiceFactory;
100 using ::com::sun::star::frame::XModel;
101 using ::com::sun::star::util::XNumberFormatsSupplier;
102 using ::com::sun::star::drawing::XDrawPage;
103 using ::com::sun::star::drawing::XDrawPageSupplier;
104 using ::com::sun::star::drawing::XShape;
106 using ::com::sun::star::chart2::IncrementData;
107 using ::com::sun::star::chart2::RelativePosition;
108 using ::com::sun::star::chart2::RelativeSize;
109 using ::com::sun::star::chart2::ScaleData;
110 using ::com::sun::star::chart2::SubIncrement;
111 using ::com::sun::star::chart2::XAxis;
112 using ::com::sun::star::chart2::XChartDocument;
113 using ::com::sun::star::chart2::XChartType;
114 using ::com::sun::star::chart2::XChartTypeContainer;
115 using ::com::sun::star::chart2::XCoordinateSystem;
116 using ::com::sun::star::chart2::XCoordinateSystemContainer;
117 using ::com::sun::star::chart2::XDataSeries;
118 using ::com::sun::star::chart2::XDataSeriesContainer;
119 using ::com::sun::star::chart2::XDiagram;
120 using ::com::sun::star::chart2::XFormattedString;
121 using ::com::sun::star::chart2::XLegend;
122 using ::com::sun::star::chart2::XRegressionCurve;
123 using ::com::sun::star::chart2::XRegressionCurveContainer;
124 using ::com::sun::star::chart2::XScaling;
125 using ::com::sun::star::chart2::XTitle;
126 using ::com::sun::star::chart2::XTitled;
128 using ::com::sun::star::chart2::data::XDataProvider;
129 using ::com::sun::star::chart2::data::XDataReceiver;
130 using ::com::sun::star::chart2::data::XDataSequence;
131 using ::com::sun::star::chart2::data::XDataSink;
132 using ::com::sun::star::chart2::data::XLabeledDataSequence;
133 using ::com::sun::star::chart2::data::LabeledDataSequence;
135 using ::formula::FormulaToken;
136 using ::formula::StackVar;
137 using ::boost::shared_ptr;
138 using ::std::pair;
139 using ::std::auto_ptr;
141 namespace cssc = ::com::sun::star::chart;
142 namespace cssc2 = ::com::sun::star::chart2;
144 // Helpers ====================================================================
146 namespace {
148 XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect )
150 return rStrm >> rRect.mnX >> rRect.mnY >> rRect.mnWidth >> rRect.mnHeight;
153 inline void lclSetValueOrClearAny( Any& rAny, double fValue, bool bClear )
155 if( bClear )
156 rAny.clear();
157 else
158 rAny <<= fValue;
161 void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear )
163 if( !bClear && bLogScale )
164 fValue = pow( 10.0, fValue );
165 lclSetValueOrClearAny( rAny, fValue, bClear );
168 double lclGetSerialDay( const XclImpRoot& rRoot, sal_uInt16 nValue, sal_uInt16 nTimeUnit )
170 switch( nTimeUnit )
172 case EXC_CHDATERANGE_DAYS:
173 return nValue;
174 case EXC_CHDATERANGE_MONTHS:
175 return rRoot.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16 >( 1 + nValue % 12 ), static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue / 12 ) ) );
176 case EXC_CHDATERANGE_YEARS:
177 return rRoot.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue ) ) );
178 default:
179 OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
181 return nValue;
184 void lclConvertTimeValue( const XclImpRoot& rRoot, Any& rAny, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
186 if( bAuto )
187 rAny.clear();
188 else
189 rAny <<= lclGetSerialDay( rRoot, nValue, nTimeUnit );
192 sal_Int32 lclGetApiTimeUnit( sal_uInt16 nTimeUnit )
194 switch( nTimeUnit )
196 case EXC_CHDATERANGE_DAYS: return cssc::TimeUnit::DAY;
197 case EXC_CHDATERANGE_MONTHS: return cssc::TimeUnit::MONTH;
198 case EXC_CHDATERANGE_YEARS: return cssc::TimeUnit::YEAR;
199 default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
201 return cssc::TimeUnit::DAY;
204 void lclConvertTimeInterval( Any& rInterval, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
206 if( bAuto || (nValue == 0) )
207 rInterval.clear();
208 else
209 rInterval <<= cssc::TimeInterval( nValue, lclGetApiTimeUnit( nTimeUnit ) );
212 } // namespace
214 // Common =====================================================================
216 /** Stores global data needed in various classes of the Chart import filter. */
217 struct XclImpChRootData : public XclChRootData
219 XclImpChChart& mrChartData; /// The chart data object.
221 inline explicit XclImpChRootData( XclImpChChart& rChartData ) : mrChartData( rChartData ) {}
224 // ----------------------------------------------------------------------------
226 XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart& rChartData ) :
227 XclImpRoot( rRoot ),
228 mxChData( new XclImpChRootData( rChartData ) )
232 XclImpChRoot::~XclImpChRoot()
236 XclImpChChart& XclImpChRoot::GetChartData() const
238 return mxChData->mrChartData;
241 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
243 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
246 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const
248 return mxChData->mxTypeInfoProv->GetTypeInfoFromRecId( nRecId );
251 const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
253 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
256 Color XclImpChRoot::GetFontAutoColor() const
258 return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT );
261 Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const
263 return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) );
266 Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const
268 const XclImpPalette& rPal = GetPalette();
269 Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) );
270 sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx );
271 return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans );
274 void XclImpChRoot::InitConversion( const Reference<XChartDocument>& xChartDoc, const Rectangle& rChartRect ) const
276 // create formatting object tables
277 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
279 // lock the model to suppress any internal updates
280 Reference< XModel > xModel( xChartDoc, UNO_QUERY );
281 if( xModel.is() )
282 xModel->lockControllers();
284 SfxObjectShell* pDocShell = GetDocShell();
285 Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
286 if( pDocShell && xDataRec.is() )
288 // create and register a data provider
289 Reference< XDataProvider > xDataProv(
290 ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY );
291 if( xDataProv.is() )
292 xDataRec->attachDataProvider( xDataProv );
293 // attach the number formatter
294 Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY );
295 if( xNumFmtSupp.is() )
296 xDataRec->attachNumberFormatsSupplier( xNumFmtSupp );
300 void XclImpChRoot::FinishConversion( XclImpDffConverter& rDffConv ) const
302 rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
303 // unlock the model
304 Reference< XModel > xModel( mxChData->mxChartDoc, UNO_QUERY );
305 if( xModel.is() )
306 xModel->unlockControllers();
307 rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
309 mxChData->FinishConversion();
312 Reference< XDataProvider > XclImpChRoot::GetDataProvider() const
314 return mxChData->mxChartDoc->getDataProvider();
317 Reference< XShape > XclImpChRoot::GetTitleShape( const XclChTextKey& rTitleKey ) const
319 return mxChData->GetTitleShape( rTitleKey );
322 sal_Int32 XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX ) const
324 return static_cast< sal_Int32 >( mxChData->mfUnitSizeX * nPosX + mxChData->mnBorderGapX + 0.5 );
327 sal_Int32 XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY ) const
329 return static_cast< sal_Int32 >( mxChData->mfUnitSizeY * nPosY + mxChData->mnBorderGapY + 0.5 );
332 ::com::sun::star::awt::Rectangle XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle& rRect ) const
334 return ::com::sun::star::awt::Rectangle(
335 CalcHmmFromChartX( rRect.mnX ),
336 CalcHmmFromChartY( rRect.mnY ),
337 CalcHmmFromChartX( rRect.mnWidth ),
338 CalcHmmFromChartY( rRect.mnHeight ) );
341 double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX ) const
343 return static_cast< double >( nPosX ) / mxChData->maChartRect.GetWidth();
346 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY ) const
348 return static_cast< double >( nPosY ) / mxChData->maChartRect.GetHeight();
351 double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX ) const
353 return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX ) );
356 double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY ) const
358 return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY ) );
361 void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet,
362 const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const
364 GetChartPropSetHelper().WriteLineProperties(
365 rPropSet, *mxChData->mxLineDashTable, rLineFmt, ePropMode );
368 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet,
369 const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const
371 GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode );
374 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet,
375 const XclChEscherFormat& rEscherFmt, const XclChPicFormat* pPicFmt,
376 sal_uInt32 nDffFillType, XclChPropertyMode ePropMode ) const
378 GetChartPropSetHelper().WriteEscherProperties( rPropSet,
379 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable,
380 rEscherFmt, pPicFmt, nDffFillType, ePropMode );
383 void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet,
384 sal_uInt16 nFontIdx, const Color* pFontColor ) const
386 GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor );
389 void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle )
391 sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360;
392 rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot );
395 // ----------------------------------------------------------------------------
397 XclImpChGroupBase::~XclImpChGroupBase()
401 void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm )
403 // read contents of the header record
404 ReadHeaderRecord( rStrm );
406 // only read sub records, if the next record is a CHBEGIN
407 if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN )
409 // read the CHBEGIN record, may be used for special initial processing
410 rStrm.StartNextRecord();
411 ReadSubRecord( rStrm );
413 // read the nested records
414 bool bLoop = true;
415 while( bLoop && rStrm.StartNextRecord() )
417 sal_uInt16 nRecId = rStrm.GetRecId();
418 bLoop = nRecId != EXC_ID_CHEND;
419 // skip unsupported nested blocks
420 if( nRecId == EXC_ID_CHBEGIN )
421 SkipBlock( rStrm );
422 else
423 ReadSubRecord( rStrm );
426 /* Returns with current CHEND record or unchanged stream, if no record
427 group present. In every case another call to StartNextRecord() will go
428 to next record of interest. */
431 void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm )
433 OSL_ENSURE( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
434 // do nothing if current record is not CHBEGIN
435 bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN;
436 while( bLoop && rStrm.StartNextRecord() )
438 sal_uInt16 nRecId = rStrm.GetRecId();
439 bLoop = nRecId != EXC_ID_CHEND;
440 // skip nested record groups
441 if( nRecId == EXC_ID_CHBEGIN )
442 SkipBlock( rStrm );
446 // Frame formatting ===========================================================
448 void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm )
450 rStrm >> maData.mnTLMode >> maData.mnBRMode;
451 /* According to the spec, the upper 16 bits of all members in the
452 rectangle are unused and may contain garbage. */
453 maData.maRect.mnX = rStrm.ReadInt16(); rStrm.Ignore( 2 );
454 maData.maRect.mnY = rStrm.ReadInt16(); rStrm.Ignore( 2 );
455 maData.maRect.mnWidth = rStrm.ReadInt16(); rStrm.Ignore( 2 );
456 maData.maRect.mnHeight = rStrm.ReadInt16(); rStrm.Ignore( 2 );
459 // ----------------------------------------------------------------------------
461 void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm )
463 rStrm >> maData.maColor >> maData.mnPattern >> maData.mnWeight >> maData.mnFlags;
465 const XclImpRoot& rRoot = rStrm.GetRoot();
466 if( rRoot.GetBiff() == EXC_BIFF8 )
467 // BIFF8: index into palette used instead of RGB data
468 maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() );
471 void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot,
472 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
474 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
475 if( IsAuto() )
477 XclChLineFormat aLineFmt;
478 aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ?
479 rRoot.GetSeriesLineAutoColor( nFormatIdx ) :
480 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx );
481 aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
482 aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight;
483 rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode );
485 else
487 rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode );
491 // ----------------------------------------------------------------------------
493 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm )
495 rStrm >> maData.maPattColor >> maData.maBackColor >> maData.mnPattern >> maData.mnFlags;
497 const XclImpRoot& rRoot = rStrm.GetRoot();
498 if( rRoot.GetBiff() == EXC_BIFF8 )
500 // BIFF8: index into palette used instead of RGB data
501 const XclImpPalette& rPal = rRoot.GetPalette();
502 maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() );
503 maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16());
507 void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot,
508 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
510 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
511 if( IsAuto() )
513 XclChAreaFormat aAreaFmt;
514 aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ?
515 rRoot.GetSeriesFillAutoColor( nFormatIdx ) :
516 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx );
517 aAreaFmt.mnPattern = EXC_PATT_SOLID;
518 rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode );
520 else
522 rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode );
526 // ----------------------------------------------------------------------------
528 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot ) :
529 mnDffFillType( mso_fillSolid )
531 maData.mxItemSet.reset(
532 new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) );
535 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm )
537 // read from stream - CHESCHERFORMAT uses own ID for record continuation
538 XclImpDffPropSet aPropSet( rStrm.GetRoot() );
539 rStrm.ResetRecord( true, rStrm.GetRecId() );
540 rStrm >> aPropSet;
541 // get the data
542 aPropSet.FillToItemSet( *maData.mxItemSet );
543 // get fill type from DFF property set
544 mnDffFillType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid );
547 void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm )
549 switch( rStrm.GetRecId() )
551 case EXC_ID_CHPICFORMAT:
552 rStrm >> maPicFmt.mnBmpMode;
553 rStrm.Ignore( 2 );
554 rStrm >> maPicFmt.mnFlags >> maPicFmt.mfScale;
555 break;
559 void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot,
560 ScfPropertySet& rPropSet, XclChObjectType eObjType, bool bUsePicFmt ) const
562 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
563 rRoot.ConvertEscherFormat( rPropSet, maData, bUsePicFmt ? &maPicFmt : 0, mnDffFillType, rFmtInfo.mePropMode );
566 // ----------------------------------------------------------------------------
568 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo )
570 if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType )
572 case EXC_CHFRAMETYPE_AUTO:
573 mxLineFmt.reset( new XclImpChLineFormat );
574 if( rFmtInfo.mbIsFrame )
575 mxAreaFmt.reset( new XclImpChAreaFormat );
576 break;
577 case EXC_CHFRAMETYPE_INVISIBLE:
579 XclChLineFormat aLineFmt;
580 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
581 aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
582 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
583 if( rFmtInfo.mbIsFrame )
585 XclChAreaFormat aAreaFmt;
586 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
587 aAreaFmt.mnPattern = EXC_PATT_NONE;
588 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
591 break;
592 default:
593 OSL_FAIL( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
597 void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm )
599 switch( rStrm.GetRecId() )
601 case EXC_ID_CHLINEFORMAT:
602 mxLineFmt.reset( new XclImpChLineFormat );
603 mxLineFmt->ReadChLineFormat( rStrm );
604 break;
605 case EXC_ID_CHAREAFORMAT:
606 mxAreaFmt.reset( new XclImpChAreaFormat );
607 mxAreaFmt->ReadChAreaFormat( rStrm );
608 break;
609 case EXC_ID_CHESCHERFORMAT:
610 mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) );
611 mxEscherFmt->ReadRecordGroup( rStrm );
612 break;
616 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot,
617 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
619 if( mxLineFmt )
620 mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
623 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot,
624 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
626 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
628 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
629 if( mxEscherFmt )
630 mxEscherFmt->Convert( rRoot, rPropSet, eObjType, bUsePicFmt );
631 else if( mxAreaFmt )
632 mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
636 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot,
637 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
639 ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx );
640 ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx, bUsePicFmt );
643 // ----------------------------------------------------------------------------
645 XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) :
646 XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ),
647 XclImpChRoot( rRoot ),
648 meObjType( eObjType )
652 void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm )
654 rStrm >> maData.mnFormat >> maData.mnFlags;
657 void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
659 const XclImpPalette& rPal = GetPalette();
661 if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) )
663 // line formatting
664 XclChLineFormat aLineFmt;
665 aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx );
666 switch( rLineData.mnStyle )
668 case EXC_OBJ_LINE_SOLID: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; break;
669 case EXC_OBJ_LINE_DASH: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH; break;
670 case EXC_OBJ_LINE_DOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT; break;
671 case EXC_OBJ_LINE_DASHDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT; break;
672 case EXC_OBJ_LINE_DASHDOTDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT; break;
673 case EXC_OBJ_LINE_MEDTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS; break;
674 case EXC_OBJ_LINE_DARKTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS; break;
675 case EXC_OBJ_LINE_LIGHTTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS; break;
676 case EXC_OBJ_LINE_NONE: aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; break;
677 default: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
679 switch( rLineData.mnWidth )
681 case EXC_OBJ_LINE_HAIR: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; break;
682 case EXC_OBJ_LINE_THIN: aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE; break;
683 case EXC_OBJ_LINE_MEDIUM: aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE; break;
684 case EXC_OBJ_LINE_THICK: aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE; break;
685 default: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
687 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() );
688 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
691 if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt )
693 // area formatting
694 XclChAreaFormat aAreaFmt;
695 aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx );
696 aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx );
697 aAreaFmt.mnPattern = rFillData.mnPattern;
698 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() );
699 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
703 void XclImpChFrame::Convert( ScfPropertySet& rPropSet, bool bUsePicFmt ) const
705 ConvertFrameBase( GetChRoot(), rPropSet, meObjType, EXC_CHDATAFORMAT_UNKNOWN, bUsePicFmt );
708 // Source links ===============================================================
710 namespace {
712 /** Creates a labeled data sequence object, adds link for series title if present. */
713 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
714 const XclImpChSourceLinkRef& xValueLink, const OUString& rValueRole,
715 const XclImpChSourceLink* pTitleLink = 0 )
717 // create data sequence for values and title
718 Reference< XDataSequence > xValueSeq;
719 if( xValueLink )
720 xValueSeq = xValueLink->CreateDataSequence( rValueRole );
721 Reference< XDataSequence > xTitleSeq;
722 if( pTitleLink )
723 xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL );
725 // create the labeled data sequence, if values or title are present
726 Reference< XLabeledDataSequence > xLabeledSeq;
727 if( xValueSeq.is() || xTitleSeq.is() )
728 xLabeledSeq.set( LabeledDataSequence::create(comphelper::getProcessComponentContext()), UNO_QUERY );
729 if( xLabeledSeq.is() )
731 if( xValueSeq.is() )
732 xLabeledSeq->setValues( xValueSeq );
733 if( xTitleSeq.is() )
734 xLabeledSeq->setLabel( xTitleSeq );
736 return xLabeledSeq;
739 } // namespace
741 // ----------------------------------------------------------------------------
743 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
744 XclImpChRoot( rRoot )
748 XclImpChSourceLink::~XclImpChSourceLink()
752 void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
754 rStrm >> maData.mnDestType
755 >> maData.mnLinkType
756 >> maData.mnFlags
757 >> maData.mnNumFmtIdx;
759 mxTokenArray.reset();
760 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
762 // read token array
763 XclTokenArray aXclTokArr;
764 rStrm >> aXclTokArr;
766 // convert BIFF formula tokens to Calc token array
767 if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) )
768 mxTokenArray.reset( pTokens->Clone() );
771 // try to read a following CHSTRING record
772 if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() )
774 mxString.reset( new XclImpString );
775 rStrm.Ignore( 2 );
776 mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
780 void XclImpChSourceLink::SetString( const String& rString )
782 if( !mxString )
783 mxString.reset( new XclImpString );
784 mxString->SetText( rString );
787 void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
789 if( mxString )
790 mxString->SetFormats( rFormats );
793 sal_uInt16 XclImpChSourceLink::GetCellCount() const
795 sal_uInt32 nCellCount = 0;
796 if( mxTokenArray )
798 mxTokenArray->Reset();
799 for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() )
801 switch( pToken->GetType() )
803 case ::formula::svSingleRef:
804 case ::formula::svExternalSingleRef:
805 // single cell
806 ++nCellCount;
807 break;
808 case ::formula::svDoubleRef:
809 case ::formula::svExternalDoubleRef:
811 // cell range
812 const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
813 const ScSingleRefData& rRef1 = rComplexRef.Ref1;
814 const ScSingleRefData& rRef2 = rComplexRef.Ref2;
815 sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
816 sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
817 sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
818 nCellCount += nCols * nRows * nTabs;
820 break;
821 default: ;
825 return limit_cast< sal_uInt16 >( nCellCount );
828 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
830 bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
831 sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND;
832 OUString aPropName = bPercent ? OUString( EXC_CHPROP_PERCENTAGENUMFMT ) : OUString( EXC_CHPROP_NUMBERFORMAT );
833 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
834 rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) );
835 else
836 // restore 'link to source' at data point (series may contain manual number format)
837 rPropSet.SetAnyProperty( aPropName, Any() );
840 Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const
842 Reference< XDataSequence > xDataSeq;
843 Reference< XDataProvider > xDataProv = GetDataProvider();
844 if( xDataProv.is() && mxTokenArray )
846 ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray );
847 aComp.SetGrammar(GetDoc().GetGrammar());
848 OUStringBuffer aRangeRep;
849 aComp.CreateStringFromTokenArray( aRangeRep );
852 xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() );
853 // set sequence role
854 ScfPropertySet aSeqProp( xDataSeq );
855 aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
857 catch( Exception& )
859 // OSL_FAIL( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
862 else if( rRole == EXC_CHPROP_ROLE_LABEL && mxString && mxString->GetText().Len() )
866 OUString aString = OUString::createFromAscii("\"");
867 xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aString + mxString->GetText() + aString );
868 // set sequence role
869 ScfPropertySet aSeqProp( xDataSeq );
870 aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
872 catch( Exception& ) { }
874 return xDataSeq;
877 Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence(
878 const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const
880 ::std::vector< Reference< XFormattedString > > aStringVec;
881 if( mxString )
883 for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt )
885 Reference< css::chart2::XFormattedString2 > xFmtStr = css::chart2::FormattedString::create( comphelper::getProcessComponentContext() );
886 // set text data
887 xFmtStr->setString( aIt.GetPortionText() );
889 // set font formatting and font color
890 ScfPropertySet aStringProp( xFmtStr );
891 sal_uInt16 nFontIdx = aIt.GetPortionFont();
892 if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) )
893 // leading unformatted portion - use passed font settings
894 rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor );
895 else
896 rRoot.ConvertFont( aStringProp, nFontIdx );
898 // add string to vector of strings
899 aStringVec.push_back( xFmtStr );
902 return ScfApiHelper::VectorToSequence( aStringVec );
905 void XclImpChSourceLink::FillSourceLink( ::std::vector< ScTokenRef >& rTokens ) const
907 if( !mxTokenArray )
908 // no links to fill.
909 return;
911 mxTokenArray->Reset();
912 for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next())
914 ScTokenRef pToken(static_cast<ScToken*>(p->Clone()));
915 if (ScRefTokenHelper::isRef(pToken))
916 // This is a reference token. Store it.
917 ScRefTokenHelper::join(rTokens, pToken);
921 // Text =======================================================================
923 XclImpChFontBase::~XclImpChFontBase()
927 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
929 Color aFontColor = GetFontColor();
930 rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor );
933 void XclImpChFontBase::ConvertRotationBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet, bool bSupportsStacked ) const
935 rRoot.GetChartPropSetHelper().WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked );
938 // ----------------------------------------------------------------------------
940 XclImpChFont::XclImpChFont() :
941 mnFontIdx( EXC_FONT_NOTFOUND )
945 void XclImpChFont::ReadChFont( XclImpStream& rStrm )
947 rStrm >> mnFontIdx;
950 // ----------------------------------------------------------------------------
952 XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) :
953 XclImpChRoot( rRoot )
957 void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm )
959 rStrm >> maData.mnHAlign
960 >> maData.mnVAlign
961 >> maData.mnBackMode
962 >> maData.maTextColor
963 >> maData.maRect
964 >> maData.mnFlags;
966 if( GetBiff() == EXC_BIFF8 )
968 // BIFF8: index into palette used instead of RGB data
969 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
970 // placement and rotation
971 rStrm >> maData.mnFlags2 >> maData.mnRotation;
973 else
975 // BIFF2-BIFF7: get rotation from text orientation
976 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 );
977 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
981 void XclImpChText::ReadSubRecord( XclImpStream& rStrm )
983 switch( rStrm.GetRecId() )
985 case EXC_ID_CHFRAMEPOS:
986 mxFramePos.reset( new XclImpChFramePos );
987 mxFramePos->ReadChFramePos( rStrm );
988 break;
989 case EXC_ID_CHFONT:
990 mxFont.reset( new XclImpChFont );
991 mxFont->ReadChFont( rStrm );
992 break;
993 case EXC_ID_CHFORMATRUNS:
994 if( GetBiff() == EXC_BIFF8 )
995 XclImpString::ReadFormats( rStrm, maFormats );
996 break;
997 case EXC_ID_CHSOURCELINK:
998 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
999 mxSrcLink->ReadChSourceLink( rStrm );
1000 break;
1001 case EXC_ID_CHFRAME:
1002 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) );
1003 mxFrame->ReadRecordGroup( rStrm );
1004 break;
1005 case EXC_ID_CHOBJECTLINK:
1006 rStrm >> maObjLink.mnTarget >> maObjLink.maPointPos.mnSeriesIdx >> maObjLink.maPointPos.mnPointIdx;
1007 break;
1008 case EXC_ID_CHFRLABELPROPS:
1009 ReadChFrLabelProps( rStrm );
1010 break;
1011 case EXC_ID_CHEND:
1012 if( mxSrcLink && !maFormats.empty() )
1013 mxSrcLink->SetTextFormats( maFormats );
1014 break;
1018 sal_uInt16 XclImpChText::GetFontIndex() const
1020 return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
1023 Color XclImpChText::GetFontColor() const
1025 return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
1028 sal_uInt16 XclImpChText::GetRotation() const
1030 return maData.mnRotation;
1033 void XclImpChText::SetString( const String& rString )
1035 if( !mxSrcLink )
1036 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
1037 mxSrcLink->SetString( rString );
1040 void XclImpChText::UpdateText( const XclImpChText* pParentText )
1042 if( pParentText )
1044 // update missing members
1045 if( !mxFrame )
1046 mxFrame = pParentText->mxFrame;
1047 if( !mxFont )
1049 mxFont = pParentText->mxFont;
1050 // text color is taken from CHTEXT record, not from font in CHFONT
1051 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) );
1052 maData.maTextColor = pParentText->maData.maTextColor;
1057 void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent )
1059 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bCateg );
1060 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bValue );
1061 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bPercent );
1062 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent );
1063 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bCateg && !bValue && !bPercent );
1066 void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const
1068 ConvertFontBase( GetChRoot(), rPropSet );
1071 void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
1073 ConvertRotationBase( GetChRoot(), rPropSet, bSupportsStacked );
1076 void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const
1078 if( mxFrame )
1079 mxFrame->Convert( rPropSet );
1082 void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
1084 if( mxSrcLink )
1085 mxSrcLink->ConvertNumFmt( rPropSet, bPercent );
1088 void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const
1090 // existing CHFRLABELPROPS record wins over flags from CHTEXT
1091 sal_uInt16 nShowFlags = mxLabelProps ? mxLabelProps->mnFlags : maData.mnFlags;
1092 sal_uInt16 SHOWANYCATEG = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG);
1093 sal_uInt16 SHOWANYVALUE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE;
1094 sal_uInt16 SHOWANYPERCENT = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC);
1095 sal_uInt16 SHOWANYBUBBLE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE;
1097 // get raw flags for label values
1098 bool bShowNone = IsDeleted();
1099 bool bShowCateg = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG );
1100 bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT );
1101 bool bShowValue = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE );
1102 bool bShowBubble = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE );
1104 // adjust to Chart2 behaviour
1105 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
1106 bShowValue = bShowBubble; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1108 // other flags
1109 bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1110 bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL );
1112 // create API struct for label values, set API label separator
1113 cssc2::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
1114 rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel );
1115 String aSep = mxLabelProps ? mxLabelProps->maSeparator : OUString('\n');
1116 if( aSep.Len() == 0 )
1117 aSep = "; ";
1118 rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep );
1120 // text properties of attached label
1121 if( bShowAny )
1123 ConvertFont( rPropSet );
1124 ConvertRotation( rPropSet, false );
1125 // label placement
1126 using namespace cssc::DataLabelPlacement;
1127 sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos;
1128 switch( ::extract_value< sal_uInt16 >( maData.mnFlags2, 0, 4 ) )
1130 case EXC_CHTEXT_POS_DEFAULT: nPlacement = rTypeInfo.mnDefaultLabelPos; break;
1131 case EXC_CHTEXT_POS_OUTSIDE: nPlacement = OUTSIDE; break;
1132 case EXC_CHTEXT_POS_INSIDE: nPlacement = INSIDE; break;
1133 case EXC_CHTEXT_POS_CENTER: nPlacement = CENTER; break;
1134 case EXC_CHTEXT_POS_AXIS: nPlacement = NEAR_ORIGIN; break;
1135 case EXC_CHTEXT_POS_ABOVE: nPlacement = TOP; break;
1136 case EXC_CHTEXT_POS_BELOW: nPlacement = BOTTOM; break;
1137 case EXC_CHTEXT_POS_LEFT: nPlacement = LEFT; break;
1138 case EXC_CHTEXT_POS_RIGHT: nPlacement = RIGHT; break;
1139 case EXC_CHTEXT_POS_AUTO: nPlacement = AVOID_OVERLAP; break;
1141 rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement );
1142 // label number format (percentage format wins over value format)
1143 if( bShowPercent || bShowValue )
1144 ConvertNumFmt( rPropSet, bShowPercent );
1148 Reference< XTitle > XclImpChText::CreateTitle() const
1150 Reference< XTitle > xTitle;
1151 if( mxSrcLink && mxSrcLink->HasString() )
1153 // create the formatted strings
1154 Sequence< Reference< XFormattedString > > aStringSeq(
1155 mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1156 if( aStringSeq.hasElements() )
1158 // create the title object
1159 xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY );
1160 if( xTitle.is() )
1162 // set the formatted strings
1163 xTitle->setText( aStringSeq );
1164 // more title formatting properties
1165 ScfPropertySet aTitleProp( xTitle );
1166 ConvertFrame( aTitleProp );
1167 ConvertRotation( aTitleProp, true );
1171 return xTitle;
1174 void XclImpChText::ConvertTitlePosition( const XclChTextKey& rTitleKey ) const
1176 if( !mxFramePos ) return;
1178 const XclChFramePos& rPosData = mxFramePos->GetFramePosData();
1179 OSL_ENSURE( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rPosData.mnBRMode == EXC_CHFRAMEPOS_PARENT),
1180 "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1182 /* Check if title is moved manually. To get the actual position of the
1183 title, we do some kind of hack and use the values from the CHTEXT
1184 record, effectively ignoring the contents of the CHFRAMEPOS record
1185 which contains the position relative to the default title position
1186 (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1187 Especially when it comes to axis titles, things would become very
1188 complicated here, because the relative title position is stored in a
1189 measurement unit that is dependent on the size of the inner plot area,
1190 the interpretation of the X and Y coordinate is dependent on the
1191 direction of the axis, and in 3D charts, and the title default
1192 positions are dependent on the 3D view settings (rotation, elevation,
1193 and perspective). Thus, it is easier to assume that the creator has
1194 written out the correct absolute position and size of the title in the
1195 CHTEXT record. This is assured by checking that the shape size stored
1196 in the CHTEXT record is non-zero. */
1197 if( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) &&
1198 ((rPosData.maRect.mnX != 0) || (rPosData.maRect.mnY != 0)) &&
1199 (maData.maRect.mnWidth > 0) && (maData.maRect.mnHeight > 0) ) try
1201 Reference< XShape > xTitleShape( GetTitleShape( rTitleKey ), UNO_SET_THROW );
1202 // the call to XShape.getSize() may recalc the chart view
1203 ::com::sun::star::awt::Size aTitleSize = xTitleShape->getSize();
1204 // rotated titles need special handling...
1205 sal_Int32 nScRot = XclTools::GetScRotation( GetRotation(), 0 );
1206 double fRad = nScRot * F_PI18000;
1207 double fSin = fabs( sin( fRad ) );
1208 double fCos = fabs( cos( fRad ) );
1209 ::com::sun::star::awt::Size aBoundSize(
1210 static_cast< sal_Int32 >( fCos * aTitleSize.Width + fSin * aTitleSize.Height + 0.5 ),
1211 static_cast< sal_Int32 >( fSin * aTitleSize.Width + fCos * aTitleSize.Height + 0.5 ) );
1212 // calculate the title position from the values in the CHTEXT record
1213 ::com::sun::star::awt::Point aTitlePos(
1214 CalcHmmFromChartX( maData.maRect.mnX ),
1215 CalcHmmFromChartY( maData.maRect.mnY ) );
1216 // add part of height to X direction, if title is rotated down (clockwise)
1217 if( nScRot > 18000 )
1218 aTitlePos.X += static_cast< sal_Int32 >( fSin * aTitleSize.Height + 0.5 );
1219 // add part of width to Y direction, if title is rotated up (counterclockwise)
1220 else if( nScRot > 0 )
1221 aTitlePos.Y += static_cast< sal_Int32 >( fSin * aTitleSize.Width + 0.5 );
1222 // set the resulting position at the title shape
1223 xTitleShape->setPosition( aTitlePos );
1225 catch( Exception& )
1230 void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm )
1232 if( GetBiff() == EXC_BIFF8 )
1234 mxLabelProps.reset( new XclChFrLabelProps );
1235 sal_uInt16 nSepLen;
1236 rStrm.Ignore( 12 );
1237 rStrm >> mxLabelProps->mnFlags >> nSepLen;
1238 if( nSepLen > 0 )
1239 mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen );
1243 namespace {
1245 void lclUpdateText( XclImpChTextRef& rxText, const XclImpChText* xDefText )
1247 if( rxText )
1248 rxText->UpdateText( xDefText );
1249 else
1251 XclImpChTextRef xNew(new XclImpChText(*xDefText));
1252 rxText = xNew;
1256 void lclFinalizeTitle( XclImpChTextRef& rxTitle, const XclImpChText* pDefText, const String& rAutoTitle )
1258 /* Do not update a title, if it is not visible (if rxTitle is null).
1259 Existing reference indicates enabled title. */
1260 if( rxTitle )
1262 if( !rxTitle->HasString() )
1263 rxTitle->SetString( rAutoTitle );
1264 if( rxTitle->HasString() )
1265 rxTitle->UpdateText(pDefText);
1266 else
1267 rxTitle.reset();
1271 } // namespace
1273 // Data series ================================================================
1275 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm )
1277 rStrm >> maData.maLineColor >> maData.maFillColor >> maData.mnMarkerType >> maData.mnFlags;
1279 const XclImpRoot& rRoot = rStrm.GetRoot();
1280 if( rRoot.GetBiff() == EXC_BIFF8 )
1282 // BIFF8: index into palette used instead of RGB data
1283 const XclImpPalette& rPal = rRoot.GetPalette();
1284 maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() );
1285 maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() );
1286 // marker size
1287 rStrm >> maData.mnMarkerSize;
1291 void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot,
1292 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const
1294 if( IsAuto() )
1296 XclChMarkerFormat aMarkerFmt;
1297 // line and fill color of the symbol are equal to series line color
1298 //! TODO: Excel sets no fill color for specific symbols (e.g. cross)
1299 aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx );
1300 switch( nLineWeight )
1302 case EXC_CHLINEFORMAT_HAIR: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE; break;
1303 case EXC_CHLINEFORMAT_SINGLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; break;
1304 case EXC_CHLINEFORMAT_DOUBLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; break;
1305 case EXC_CHLINEFORMAT_TRIPLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE; break;
1306 default: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;
1308 aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
1309 rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, aMarkerFmt );
1311 else
1313 rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, maData );
1317 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot,
1318 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
1320 Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor;
1321 rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor );
1324 // ----------------------------------------------------------------------------
1326 XclImpChPieFormat::XclImpChPieFormat() :
1327 mnPieDist( 0 )
1331 void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm )
1333 rStrm >> mnPieDist;
1336 void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const
1338 double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 );
1339 rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist );
1342 // ----------------------------------------------------------------------------
1344 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1345 mnFlags( 0 )
1349 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm )
1351 rStrm >> mnFlags;
1354 // ----------------------------------------------------------------------------
1356 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm )
1358 rStrm >> maData.mnBase >> maData.mnTop;
1361 void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const
1363 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1364 sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ?
1365 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) :
1366 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE);
1367 rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType );
1370 // ----------------------------------------------------------------------------
1372 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) :
1373 XclImpChRoot( rRoot ),
1374 mnFlags( 0 )
1378 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm )
1380 rStrm >> mnFlags;
1383 XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( const XclImpChText* pParent ) const
1385 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE;
1386 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC;
1387 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC;
1389 XclImpChTextRef xLabel( pParent ? new XclImpChText( *pParent ) : new XclImpChText( GetChRoot() ) );
1390 xLabel->UpdateDataLabel(
1391 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ),
1392 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ),
1393 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) );
1394 return xLabel;
1397 // ----------------------------------------------------------------------------
1399 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) :
1400 XclImpChRoot( rRoot )
1404 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm )
1406 rStrm >> maData.maPointPos.mnPointIdx
1407 >> maData.maPointPos.mnSeriesIdx
1408 >> maData.mnFormatIdx
1409 >> maData.mnFlags;
1412 void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm )
1414 switch( rStrm.GetRecId() )
1416 case EXC_ID_CHMARKERFORMAT:
1417 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1418 mxMarkerFmt->ReadChMarkerFormat( rStrm );
1419 break;
1420 case EXC_ID_CHPIEFORMAT:
1421 mxPieFmt.reset( new XclImpChPieFormat );
1422 mxPieFmt->ReadChPieFormat( rStrm );
1423 break;
1424 case EXC_ID_CHSERIESFORMAT:
1425 mxSeriesFmt.reset( new XclImpChSeriesFormat );
1426 mxSeriesFmt->ReadChSeriesFormat( rStrm );
1427 break;
1428 case EXC_ID_CH3DDATAFORMAT:
1429 mx3dDataFmt.reset( new XclImpCh3dDataFormat );
1430 mx3dDataFmt->ReadCh3dDataFormat( rStrm );
1431 break;
1432 case EXC_ID_CHATTACHEDLABEL:
1433 mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) );
1434 mxAttLabel->ReadChAttachedLabel( rStrm );
1435 break;
1436 default:
1437 XclImpChFrameBase::ReadSubRecord( rStrm );
1441 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx )
1443 maData.maPointPos = rPointPos;
1444 maData.mnFormatIdx = nFormatIdx;
1447 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo )
1449 // remove formats not used for the current chart type
1450 RemoveUnusedFormats( rTypeInfo );
1453 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt )
1455 // update missing formats from passed chart type group format
1456 if( pGroupFmt )
1458 if( !mxLineFmt )
1459 mxLineFmt = pGroupFmt->mxLineFmt;
1460 if( !mxAreaFmt && !mxEscherFmt )
1462 mxAreaFmt = pGroupFmt->mxAreaFmt;
1463 mxEscherFmt = pGroupFmt->mxEscherFmt;
1465 if( !mxMarkerFmt )
1466 mxMarkerFmt = pGroupFmt->mxMarkerFmt;
1467 if( !mxPieFmt )
1468 mxPieFmt = pGroupFmt->mxPieFmt;
1469 if( !mxSeriesFmt )
1470 mxSeriesFmt = pGroupFmt->mxSeriesFmt;
1471 if( !mx3dDataFmt )
1472 mx3dDataFmt = pGroupFmt->mx3dDataFmt;
1473 if( !mxAttLabel )
1474 mxAttLabel = pGroupFmt->mxAttLabel;
1477 /* Create missing but required formats. Existing line, area, and marker
1478 format objects are needed to create automatic series formatting. */
1479 if( !mxLineFmt )
1480 mxLineFmt.reset( new XclImpChLineFormat );
1481 if( !mxAreaFmt && !mxEscherFmt )
1482 mxAreaFmt.reset( new XclImpChAreaFormat );
1483 if( !mxMarkerFmt )
1484 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1486 // remove formats not used for the current chart type
1487 RemoveUnusedFormats( rTypeInfo );
1488 // update data label
1489 UpdateDataLabel( pGroupFmt );
1492 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt )
1494 // remove formats if they are automatic in this and in the passed series format
1495 if( pSeriesFmt )
1497 if( IsAutoLine() && pSeriesFmt->IsAutoLine() )
1498 mxLineFmt.reset();
1499 if( IsAutoArea() && pSeriesFmt->IsAutoArea() )
1500 mxAreaFmt.reset();
1501 if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() )
1502 mxMarkerFmt.reset();
1503 mxSeriesFmt.reset();
1506 // Excel ignores 3D bar format for single data points
1507 mx3dDataFmt.reset();
1508 // remove point line formats for linear chart types, TODO: implement in OOChart
1509 if( !rTypeInfo.IsSeriesFrameFormat() )
1510 mxLineFmt.reset();
1512 // remove formats not used for the current chart type
1513 RemoveUnusedFormats( rTypeInfo );
1514 // update data label
1515 UpdateDataLabel( pSeriesFmt );
1518 void XclImpChDataFormat::UpdateTrendLineFormat()
1520 if( !mxLineFmt )
1521 mxLineFmt.reset( new XclImpChLineFormat );
1522 mxAreaFmt.reset();
1523 mxEscherFmt.reset();
1524 mxMarkerFmt.reset();
1525 mxPieFmt.reset();
1526 mxSeriesFmt.reset();
1527 mx3dDataFmt.reset();
1528 mxAttLabel.reset();
1529 // update data label
1530 UpdateDataLabel( 0 );
1533 void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const
1535 /* Line and area format.
1536 #i71810# If the data points are filled with bitmaps, textures, or
1537 patterns, then only bar charts will use the CHPICFORMAT record to
1538 determine stacking/streching mode. All other chart types ignore this
1539 record and always use the property 'fill-type' from the DFF property
1540 set (streched for bitmaps, and stacked for textures and patterns). */
1541 bool bUsePicFmt = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR;
1542 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx, bUsePicFmt );
1544 #if EXC_CHART2_3DBAR_HAIRLINES_ONLY
1545 // #i83151# only hair lines in 3D charts with filled data points
1546 if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt && mxLineFmt->HasLine() )
1547 rPropSet.SetProperty< sal_Int32 >( "BorderWidth", 0 );
1548 #endif
1550 // other formatting
1551 if( mxMarkerFmt )
1552 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() );
1553 if( mxPieFmt )
1554 mxPieFmt->Convert( rPropSet );
1555 if( mx3dDataFmt )
1556 mx3dDataFmt->Convert( rPropSet );
1557 if( mxLabel )
1558 mxLabel->ConvertDataLabel( rPropSet, rTypeInfo );
1560 // 3D settings
1561 rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 );
1563 /* Special case: set marker color as line color, if series line is not
1564 visible. This makes the color visible in the marker area.
1565 TODO: remove this if OOChart supports own colors in markers. */
1566 if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt )
1567 mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx );
1570 void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
1572 ConvertLineBase( GetChRoot(), rPropSet, eObjType );
1575 void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
1577 ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx, bUsePicFmt );
1580 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo )
1582 // data point marker only in linear 2D charts
1583 if( rTypeInfo.IsSeriesFrameFormat() )
1584 mxMarkerFmt.reset();
1585 // pie format only in pie/donut charts
1586 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
1587 mxPieFmt.reset();
1588 // 3D format only in 3D bar charts
1589 if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
1590 mx3dDataFmt.reset();
1593 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt )
1595 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1596 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1597 group, the contents of the CHATTACHEDLABEL record are used. In this
1598 case a new CHTEXT group is created and filled with the settings from
1599 the CHATTACHEDLABEL record. */
1600 const XclImpChText* pDefText = NULL;
1601 if (pParentFmt)
1602 pDefText = pParentFmt->GetDataLabel();
1603 if (!pDefText)
1604 pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL );
1605 if (mxLabel)
1606 mxLabel->UpdateText(pDefText);
1607 else if (mxAttLabel)
1608 mxLabel = mxAttLabel->CreateDataLabel( pDefText );
1611 // ----------------------------------------------------------------------------
1613 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) :
1614 XclImpChRoot( rRoot )
1618 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm )
1620 rStrm >> maData.mnLineType
1621 >> maData.mnOrder
1622 >> maData.mfIntercept
1623 >> maData.mnShowEquation
1624 >> maData.mnShowRSquared
1625 >> maData.mfForecastFor
1626 >> maData.mfForecastBack;
1629 Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const
1631 // trend line type
1632 OUString aService;
1633 switch( maData.mnLineType )
1635 case EXC_CHSERTREND_POLYNOMIAL:
1636 // TODO: only linear trend lines are supported by OOChart (#i20819#)
1637 if( maData.mnOrder == 1 )
1638 aService = SERVICE_CHART2_LINEARREGCURVE;
1639 break;
1640 case EXC_CHSERTREND_EXPONENTIAL:
1641 aService = SERVICE_CHART2_EXPREGCURVE;
1642 break;
1643 case EXC_CHSERTREND_LOGARITHMIC:
1644 aService = SERVICE_CHART2_LOGREGCURVE;
1645 break;
1646 case EXC_CHSERTREND_POWER:
1647 aService = SERVICE_CHART2_POTREGCURVE;
1648 break;
1650 Reference< XRegressionCurve > xRegCurve;
1651 if( !aService.isEmpty() )
1652 xRegCurve.set( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
1654 // trend line formatting
1655 if( xRegCurve.is() && mxDataFmt )
1657 ScfPropertySet aPropSet( xRegCurve );
1658 mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE );
1660 // #i83100# show equation and correlation coefficient
1661 ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() );
1662 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 );
1663 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 );
1665 // #i83100# formatting of the equation text box
1666 if (const XclImpChText* pLabel = mxDataFmt->GetDataLabel())
1668 pLabel->ConvertFont( aLabelProp );
1669 pLabel->ConvertFrame( aLabelProp );
1670 pLabel->ConvertNumFmt( aLabelProp, false );
1674 // missing features
1675 // #i20819# polynomial trend lines
1676 // #i66819# moving average trend lines
1677 // #i5085# manual trend line size
1678 // #i34093# manual crossing point
1680 return xRegCurve;
1683 // ----------------------------------------------------------------------------
1685 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) :
1686 XclImpChRoot( rRoot )
1690 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm )
1692 rStrm >> maData.mnBarType >> maData.mnSourceType >> maData.mnLineEnd;
1693 rStrm.Ignore( 1 );
1694 rStrm >> maData.mfValue >> maData.mnValueCount;
1697 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef xValueLink, XclImpChDataFormatRef xDataFmt )
1699 mxValueLink = xValueLink;
1700 mxDataFmt = xDataFmt;
1703 Reference< XLabeledDataSequence > XclImpChSerErrorBar::CreateValueSequence() const
1705 return lclCreateLabeledDataSequence( mxValueLink, XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ) );
1708 Reference< XPropertySet > XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar* pPosBar, const XclImpChSerErrorBar* pNegBar )
1710 Reference< XPropertySet > xErrorBar;
1712 if( const XclImpChSerErrorBar* pPrimaryBar = pPosBar ? pPosBar : pNegBar )
1714 xErrorBar.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR ), UNO_QUERY );
1715 ScfPropertySet aBarProp( xErrorBar );
1717 // plus/minus bars visible?
1718 aBarProp.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR, pPosBar != 0 );
1719 aBarProp.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR, pNegBar != 0 );
1721 // type of displayed error
1722 switch( pPrimaryBar->maData.mnSourceType )
1724 case EXC_CHSERERR_PERCENT:
1725 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::RELATIVE );
1726 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1727 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1728 break;
1729 case EXC_CHSERERR_FIXED:
1730 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::ABSOLUTE );
1731 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1732 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1733 break;
1734 case EXC_CHSERERR_STDDEV:
1735 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_DEVIATION );
1736 aBarProp.SetProperty( EXC_CHPROP_WEIGHT, pPrimaryBar->maData.mfValue );
1737 break;
1738 case EXC_CHSERERR_STDERR:
1739 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_ERROR );
1740 break;
1741 case EXC_CHSERERR_CUSTOM:
1743 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::FROM_DATA );
1744 // attach data sequences to erorr bar
1745 Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
1746 if( xDataSink.is() )
1748 // create vector of all value sequences
1749 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
1750 // add positive values
1751 if( pPosBar )
1753 Reference< XLabeledDataSequence > xValueSeq = pPosBar->CreateValueSequence();
1754 if( xValueSeq.is() )
1755 aLabeledSeqVec.push_back( xValueSeq );
1757 // add negative values
1758 if( pNegBar )
1760 Reference< XLabeledDataSequence > xValueSeq = pNegBar->CreateValueSequence();
1761 if( xValueSeq.is() )
1762 aLabeledSeqVec.push_back( xValueSeq );
1764 // attach labeled data sequences to series
1765 if( aLabeledSeqVec.empty() )
1766 xErrorBar.clear();
1767 else
1768 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
1771 break;
1772 default:
1773 xErrorBar.clear();
1776 // error bar formatting
1777 if( pPrimaryBar->mxDataFmt && xErrorBar.is() )
1778 pPrimaryBar->mxDataFmt->ConvertLine( aBarProp, EXC_CHOBJTYPE_ERRORBAR );
1781 return xErrorBar;
1784 // ----------------------------------------------------------------------------
1786 XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1787 XclImpChRoot( rRoot ),
1788 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1789 mnSeriesIdx( nSeriesIdx ),
1790 mnParentIdx( EXC_CHSERIES_INVALID )
1794 void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm )
1796 rStrm >> maData.mnCategType >> maData.mnValueType >> maData.mnCategCount >> maData.mnValueCount;
1797 if( GetBiff() == EXC_BIFF8 )
1798 rStrm >> maData.mnBubbleType >> maData.mnBubbleCount;
1801 void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm )
1803 switch( rStrm.GetRecId() )
1805 case EXC_ID_CHSOURCELINK:
1806 ReadChSourceLink( rStrm );
1807 break;
1808 case EXC_ID_CHDATAFORMAT:
1809 ReadChDataFormat( rStrm );
1810 break;
1811 case EXC_ID_CHSERGROUP:
1812 rStrm >> mnGroupIdx;
1813 break;
1814 case EXC_ID_CHSERPARENT:
1815 ReadChSerParent( rStrm );
1816 break;
1817 case EXC_ID_CHSERTRENDLINE:
1818 ReadChSerTrendLine( rStrm );
1819 break;
1820 case EXC_ID_CHSERERRORBAR:
1821 ReadChSerErrorBar( rStrm );
1822 break;
1826 void XclImpChSeries::SetDataFormat( const XclImpChDataFormatRef& xDataFmt )
1828 if (!xDataFmt)
1829 return;
1831 sal_uInt16 nPointIdx = xDataFmt->GetPointPos().mnPointIdx;
1832 if (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS)
1834 if (mxSeriesFmt)
1835 // Don't overwrite the existing format.
1836 return;
1838 mxSeriesFmt = xDataFmt;
1839 if (HasParentSeries())
1840 return;
1842 XclImpChTypeGroupRef pTypeGroup = GetChartData().GetTypeGroup(mnGroupIdx);
1843 if (pTypeGroup)
1844 pTypeGroup->SetUsedFormatIndex(xDataFmt->GetFormatIdx());
1846 return;
1849 if (nPointIdx >= EXC_CHDATAFORMAT_MAXPOINTCOUNT)
1850 // Above the max point count. Bail out.
1851 return;
1853 XclImpChDataFormatMap::iterator itr = maPointFmts.lower_bound(nPointIdx);
1854 if (itr == maPointFmts.end() || maPointFmts.key_comp()(nPointIdx, itr->first))
1856 // No object exists at this point index position. Insert it.
1857 itr = maPointFmts.insert(itr, XclImpChDataFormatMap::value_type(nPointIdx, xDataFmt));
1861 void XclImpChSeries::SetDataLabel( const XclImpChTextRef& xLabel )
1863 if (!xLabel)
1864 return;
1866 sal_uInt16 nPointIdx = xLabel->GetPointPos().mnPointIdx;
1867 if ((nPointIdx != EXC_CHDATAFORMAT_ALLPOINTS) && (nPointIdx >= EXC_CHDATAFORMAT_MAXPOINTCOUNT))
1868 // Above the maximum allowed data points. Bail out.
1869 return;
1871 XclImpChTextMap::iterator itr = maLabels.lower_bound(nPointIdx);
1872 if (itr == maLabels.end() || maLabels.key_comp()(nPointIdx, itr->first))
1874 // No object exists at this point index position. Insert it.
1875 itr = maLabels.insert(itr, XclImpChTextMap::value_type(nPointIdx, xLabel));
1879 void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries )
1881 OSL_ENSURE( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1883 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1884 these are properties of the parent series. This function adds the
1885 settings of the passed series to this series. */
1886 maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() );
1887 maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() );
1890 void XclImpChSeries::FinalizeDataFormats()
1892 if( HasParentSeries() )
1894 // *** series is a child series, e.g. trend line or error bar ***
1896 // create missing series format
1897 if( !mxSeriesFmt )
1898 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 );
1900 if( mxSeriesFmt )
1902 // #i83100# set text label format, e.g. for trend line equations
1903 XclImpChTextRef xLabel;
1904 XclImpChTextMap::iterator itr = maLabels.find(EXC_CHDATAFORMAT_ALLPOINTS);
1905 if (itr != maLabels.end())
1906 xLabel = itr->second;
1907 mxSeriesFmt->SetDataLabel(xLabel);
1908 // create missing automatic formats
1909 mxSeriesFmt->UpdateTrendLineFormat();
1912 // copy series formatting to child objects
1913 for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt )
1914 (*aLIt)->SetDataFormat( mxSeriesFmt );
1915 for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt )
1916 aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt );
1918 else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1920 // *** series is a regular data series ***
1922 // create missing series format
1923 if( !mxSeriesFmt )
1925 // #i51639# use a new unused format index to create series default format
1926 sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex();
1927 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx );
1930 // set text labels to data formats
1931 for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt )
1933 sal_uInt16 nPointIdx = aTIt->first;
1934 if (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS)
1936 if (!mxSeriesFmt)
1937 mxSeriesFmt = CreateDataFormat(nPointIdx, EXC_CHDATAFORMAT_DEFAULT);
1938 mxSeriesFmt->SetDataLabel(aTIt->second);
1940 else if (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT)
1942 XclImpChDataFormatRef p;
1943 XclImpChDataFormatMap::iterator itr = maPointFmts.lower_bound(nPointIdx);
1944 if (itr == maPointFmts.end() || maPointFmts.key_comp()(nPointIdx, itr->first))
1946 // No object exists at this point index position. Insert
1947 // a new one.
1948 p = CreateDataFormat(nPointIdx, EXC_CHDATAFORMAT_DEFAULT);
1949 itr = maPointFmts.insert(
1950 itr, XclImpChDataFormatMap::value_type(nPointIdx, p));
1952 else
1953 p = itr->second;
1954 p->SetDataLabel(aTIt->second);
1958 // update series format (copy missing formatting from group default format)
1959 if( mxSeriesFmt )
1960 mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() );
1962 // update data point formats (removes unchanged automatic formatting)
1963 for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt )
1964 aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() );
1968 namespace {
1970 /** Returns the property set of the specified data point. */
1971 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx )
1973 ScfPropertySet aPropSet;
1976 aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) );
1978 catch( Exception& )
1980 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1982 return aPropSet;
1985 } // namespace
1987 Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const
1989 return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() );
1992 Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const
1994 return lclCreateLabeledDataSequence( mxCategLink, rCategRole );
1997 Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const
1999 Reference< XDataSeries > xDataSeries;
2000 if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
2002 const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo();
2004 // create the data series object
2005 xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2007 // attach data and title sequences to series
2008 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2009 if( xDataSink.is() )
2011 // create vector of all value sequences
2012 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2013 // add Y values
2014 Reference< XLabeledDataSequence > xYValueSeq =
2015 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES );
2016 if( xYValueSeq.is() )
2017 aLabeledSeqVec.push_back( xYValueSeq );
2018 // add X values
2019 if( !rTypeInfo.mbCategoryAxis )
2021 Reference< XLabeledDataSequence > xXValueSeq =
2022 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES );
2023 if( xXValueSeq.is() )
2024 aLabeledSeqVec.push_back( xXValueSeq );
2025 // add size values of bubble charts
2026 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
2028 Reference< XLabeledDataSequence > xSizeValueSeq =
2029 lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() );
2030 if( xSizeValueSeq.is() )
2031 aLabeledSeqVec.push_back( xSizeValueSeq );
2034 // attach labeled data sequences to series
2035 if( !aLabeledSeqVec.empty() )
2036 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2039 // series formatting
2040 ScfPropertySet aSeriesProp( xDataSeries );
2041 if( mxSeriesFmt )
2042 mxSeriesFmt->Convert( aSeriesProp, rTypeInfo );
2044 // trend lines
2045 ConvertTrendLines( xDataSeries );
2047 // error bars
2048 Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
2049 if( xErrorBarX.is() )
2050 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX );
2051 Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
2052 if( xErrorBarY.is() )
2053 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY );
2055 // own area formatting for every data point (TODO: varying line color not supported)
2056 bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat();
2057 #if EXC_CHART2_VARYCOLORSBY_PROP
2058 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt );
2059 #else
2060 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
2061 #endif
2062 // #i91271# always set area formatting for every point in pie/doughnut charts
2063 if (mxSeriesFmt && mxValueLink && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)))
2065 for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx )
2067 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
2068 mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx, false );
2072 // data point formatting
2073 for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt )
2075 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first );
2076 aIt->second->Convert( aPointProp, rTypeInfo );
2079 return xDataSeries;
2082 void XclImpChSeries::FillAllSourceLinks( ::std::vector< ScTokenRef >& rTokens ) const
2084 if( mxValueLink )
2085 mxValueLink->FillSourceLink( rTokens );
2086 if( mxCategLink )
2087 mxCategLink->FillSourceLink( rTokens );
2088 if( mxTitleLink )
2089 mxTitleLink->FillSourceLink( rTokens );
2090 if( mxBubbleLink )
2091 mxBubbleLink->FillSourceLink( rTokens );
2094 void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm )
2096 XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
2097 xSrcLink->ReadChSourceLink( rStrm );
2098 switch( xSrcLink->GetDestType() )
2100 case EXC_CHSRCLINK_TITLE: mxTitleLink = xSrcLink; break;
2101 case EXC_CHSRCLINK_VALUES: mxValueLink = xSrcLink; break;
2102 case EXC_CHSRCLINK_CATEGORY: mxCategLink = xSrcLink; break;
2103 case EXC_CHSRCLINK_BUBBLES: mxBubbleLink = xSrcLink; break;
2107 void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm )
2109 // #i51639# chart stores all data formats and assigns them later to the series
2110 GetChartData().ReadChDataFormat( rStrm );
2113 void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm )
2115 rStrm >> mnParentIdx;
2116 // index to parent series is 1-based, convert it to 0-based
2117 if( mnParentIdx > 0 )
2118 --mnParentIdx;
2119 else
2120 mnParentIdx = EXC_CHSERIES_INVALID;
2123 void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm )
2125 XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
2126 xTrendLine->ReadChSerTrendLine( rStrm );
2127 maTrendLines.push_back( xTrendLine );
2130 void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm )
2132 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2133 auto_ptr<XclImpChSerErrorBar> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
2134 SAL_WNODEPRECATED_DECLARATIONS_POP
2135 pErrorBar->ReadChSerErrorBar(rStrm);
2136 sal_uInt8 nBarType = pErrorBar->GetBarType();
2137 maErrorBars.insert(nBarType, pErrorBar);
2140 XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx )
2142 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2143 xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx );
2144 return xDataFmt;
2147 void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const
2149 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2150 if( xRegCurveCont.is() )
2152 for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt )
2156 Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve();
2157 if( xRegCurve.is() )
2158 xRegCurveCont->addRegressionCurve( xRegCurve );
2160 catch( Exception& )
2162 OSL_FAIL( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2168 Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const
2170 XclImpChSerErrorBarMap::const_iterator itrPosBar = maErrorBars.find(nPosBarId);
2171 XclImpChSerErrorBarMap::const_iterator itrNegBar = maErrorBars.find(nNegBarId);
2172 XclImpChSerErrorBarMap::const_iterator itrEnd = maErrorBars.end();
2173 if (itrPosBar == itrEnd || itrNegBar == itrEnd)
2174 return Reference<XPropertySet>();
2176 return XclImpChSerErrorBar::CreateErrorBar(itrPosBar->second, itrNegBar->second);
2179 // Chart type groups ==========================================================
2181 XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) :
2182 XclImpChRoot( rRoot ),
2183 mnRecId( EXC_ID_CHUNKNOWN ),
2184 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2188 void XclImpChType::ReadChType( XclImpStream& rStrm )
2190 sal_uInt16 nRecId = rStrm.GetRecId();
2191 bool bKnownType = true;
2193 switch( nRecId )
2195 case EXC_ID_CHBAR:
2196 rStrm >> maData.mnOverlap >> maData.mnGap >> maData.mnFlags;
2197 break;
2199 case EXC_ID_CHLINE:
2200 case EXC_ID_CHAREA:
2201 case EXC_ID_CHRADARLINE:
2202 case EXC_ID_CHRADARAREA:
2203 rStrm >> maData.mnFlags;
2204 break;
2206 case EXC_ID_CHPIE:
2207 rStrm >> maData.mnRotation >> maData.mnPieHole;
2208 if( GetBiff() == EXC_BIFF8 )
2209 rStrm >> maData.mnFlags;
2210 else
2211 maData.mnFlags = 0;
2212 break;
2214 case EXC_ID_CHPIEEXT:
2215 maData.mnRotation = 0;
2216 maData.mnPieHole = 0;
2217 maData.mnFlags = 0;
2218 break;
2220 case EXC_ID_CHSCATTER:
2221 if( GetBiff() == EXC_BIFF8 )
2222 rStrm >> maData.mnBubbleSize >> maData.mnBubbleType >> maData.mnFlags;
2223 else
2224 maData.mnFlags = 0;
2225 break;
2227 case EXC_ID_CHSURFACE:
2228 rStrm >> maData.mnFlags;
2229 break;
2231 default:
2232 bKnownType = false;
2235 if( bKnownType )
2236 mnRecId = nRecId;
2239 void XclImpChType::Finalize( bool bStockChart )
2241 switch( mnRecId )
2243 case EXC_ID_CHLINE:
2244 maTypeInfo = GetChartTypeInfo( bStockChart ?
2245 EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE );
2246 break;
2247 case EXC_ID_CHBAR:
2248 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2249 maData.mnFlags, EXC_CHBAR_HORIZONTAL,
2250 EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) );
2251 break;
2252 case EXC_ID_CHPIE:
2253 maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ?
2254 EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2255 break;
2256 case EXC_ID_CHSCATTER:
2257 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2258 maData.mnFlags, EXC_CHSCATTER_BUBBLES,
2259 EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) );
2260 break;
2261 default:
2262 maTypeInfo = GetChartTypeInfo( mnRecId );
2265 switch( maTypeInfo.meTypeId )
2267 case EXC_CHTYPEID_PIEEXT:
2268 case EXC_CHTYPEID_BUBBLES:
2269 case EXC_CHTYPEID_SURFACE:
2270 case EXC_CHTYPEID_UNKNOWN:
2271 GetTracer().TraceChartUnKnownType();
2272 break;
2273 default:;
2277 bool XclImpChType::IsStacked() const
2279 bool bStacked = false;
2280 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2282 case EXC_CHTYPECATEG_LINE:
2283 bStacked =
2284 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2285 !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2286 break;
2287 case EXC_CHTYPECATEG_BAR:
2288 bStacked =
2289 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2290 !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2291 break;
2292 default:;
2294 return bStacked;
2297 bool XclImpChType::IsPercent() const
2299 bool bPercent = false;
2300 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2302 case EXC_CHTYPECATEG_LINE:
2303 bPercent =
2304 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2305 ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2306 break;
2307 case EXC_CHTYPECATEG_BAR:
2308 bPercent =
2309 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2310 ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2311 break;
2312 default:;
2314 return bPercent;
2317 bool XclImpChType::HasCategoryLabels() const
2319 // radar charts disable category labels in chart type, not in CHTICK of X axis
2320 return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS );
2323 Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const
2325 // create the coordinate system object
2326 Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
2327 Reference< XCoordinateSystem > xCoordSystem;
2328 if( maTypeInfo.mbPolarCoordSystem )
2330 if( b3dChart )
2331 xCoordSystem = css::chart2::PolarCoordinateSystem3d::create(xContext);
2332 else
2333 xCoordSystem = css::chart2::PolarCoordinateSystem2d::create(xContext);
2335 else
2337 if( b3dChart )
2338 xCoordSystem = css::chart2::CartesianCoordinateSystem3d::create(xContext);
2339 else
2340 xCoordSystem = css::chart2::CartesianCoordinateSystem2d::create(xContext);
2343 // swap X and Y axis
2344 if( maTypeInfo.mbSwappedAxesSet )
2346 ScfPropertySet aCoordSysProp( xCoordSystem );
2347 aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true );
2350 return xCoordSystem;
2353 Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const
2355 OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
2356 Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
2358 // additional properties
2359 switch( maTypeInfo.meTypeCateg )
2361 case EXC_CHTYPECATEG_BAR:
2363 ScfPropertySet aTypeProp( xChartType );
2364 Sequence< sal_Int32 > aInt32Seq( 2 );
2365 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap;
2366 aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq );
2367 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap;
2368 aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq );
2370 break;
2371 case EXC_CHTYPECATEG_PIE:
2373 ScfPropertySet aTypeProp( xChartType );
2374 aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT );
2375 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2376 rotation setting in view3D element. Of-pie charts do not
2377 support pie rotation. */
2378 if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) )
2380 ScfPropertySet aDiaProp( xDiagram );
2381 XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation );
2384 break;
2385 default:;
2388 return xChartType;
2391 // ----------------------------------------------------------------------------
2393 void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm )
2395 rStrm >> maData.mnRotation
2396 >> maData.mnElevation
2397 >> maData.mnEyeDist
2398 >> maData.mnRelHeight
2399 >> maData.mnRelDepth
2400 >> maData.mnDepthGap
2401 >> maData.mnFlags;
2404 void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const
2406 namespace cssd = ::com::sun::star::drawing;
2408 // #i104057# do not assert this, written by broken external generators
2409 // OSL_ENSURE( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2411 sal_Int32 nRotationY = 0;
2412 sal_Int32 nRotationX = 0;
2413 sal_Int32 nPerspective = 15;
2414 bool bRightAngled = false;
2415 cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE;
2416 Color aAmbientColor, aLightColor;
2418 if( b3dWallChart )
2420 // Y rotation (Excel [0..359], Chart2 [-179,180])
2421 nRotationY = maData.mnRotation % 360;
2422 if( nRotationY > 180 ) nRotationY -= 360;
2423 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2424 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 );
2425 // perspective (Excel and Chart2 [0,100])
2426 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2427 // right-angled axes
2428 bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D );
2429 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2430 bool bParallel = bRightAngled || (nPerspective == 0);
2431 eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
2432 // ambient color (Gray 20%)
2433 aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) );
2434 // light color (Gray 60%)
2435 aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) );
2437 else
2439 // Y rotation not used in pie charts, but 'first pie slice angle'
2440 nRotationY = 0;
2441 XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation );
2442 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2443 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90;
2444 // perspective (Excel and Chart2 [0,100])
2445 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2446 // no right-angled axes in pie charts, but parallel projection
2447 bRightAngled = false;
2448 eProjMode = cssd::ProjectionMode_PARALLEL;
2449 // ambient color (Gray 30%)
2450 aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) );
2451 // light color (Gray 70%)
2452 aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) );
2455 // properties
2456 rPropSet.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT, (sal_Int32)(maData.mnRelHeight / 2)); // seems to be 200%, cange to 100%
2457 rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY );
2458 rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX );
2459 rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective );
2460 rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled );
2461 rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode );
2463 // light settings
2464 rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT );
2465 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor );
2466 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false );
2467 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true );
2468 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor );
2469 rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2472 // ----------------------------------------------------------------------------
2474 XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) :
2475 XclImpChRoot( rRoot )
2479 void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm )
2481 rStrm >> maData.maRect >> maData.mnDockMode >> maData.mnSpacing >> maData.mnFlags;
2483 // trace unsupported features
2484 if( GetTracer().IsEnabled() )
2486 if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED )
2487 GetTracer().TraceChartLegendPosition();
2488 if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) )
2489 GetTracer().TraceChartDataTable();
2493 void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm )
2495 switch( rStrm.GetRecId() )
2497 case EXC_ID_CHFRAMEPOS:
2498 mxFramePos.reset( new XclImpChFramePos );
2499 mxFramePos->ReadChFramePos( rStrm );
2500 break;
2501 case EXC_ID_CHTEXT:
2502 mxText.reset( new XclImpChText( GetChRoot() ) );
2503 mxText->ReadRecordGroup( rStrm );
2504 break;
2505 case EXC_ID_CHFRAME:
2506 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2507 mxFrame->ReadRecordGroup( rStrm );
2508 break;
2512 void XclImpChLegend::Finalize()
2514 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2515 if( !mxFrame )
2516 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2517 // Update text formatting. If mxText is empty, the passed default text is used.
2518 lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) );
2521 Reference< XLegend > XclImpChLegend::CreateLegend() const
2523 Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY );
2524 if( xLegend.is() )
2526 ScfPropertySet aLegendProp( xLegend );
2527 aLegendProp.SetBoolProperty( EXC_CHPROP_SHOW, true );
2529 // frame properties
2530 if( mxFrame )
2531 mxFrame->Convert( aLegendProp );
2532 // text properties
2533 if( mxText )
2534 mxText->ConvertFont( aLegendProp );
2536 /* Legend position and size. Default positions are used only if the
2537 plot area is positioned automatically (Excel sets the plot area to
2538 manual mode, if the legend is moved or resized). With manual plot
2539 areas, Excel ignores the value in maData.mnDockMode completely. */
2540 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2541 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2542 if( !GetChartData().IsManualPlotArea() ) switch( maData.mnDockMode )
2544 case EXC_CHLEGEND_LEFT:
2545 eApiPos = cssc2::LegendPosition_LINE_START;
2546 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2547 break;
2548 case EXC_CHLEGEND_RIGHT:
2549 // top-right not supported
2550 case EXC_CHLEGEND_CORNER:
2551 eApiPos = cssc2::LegendPosition_LINE_END;
2552 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2553 break;
2554 case EXC_CHLEGEND_TOP:
2555 eApiPos = cssc2::LegendPosition_PAGE_START;
2556 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2557 break;
2558 case EXC_CHLEGEND_BOTTOM:
2559 eApiPos = cssc2::LegendPosition_PAGE_END;
2560 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2561 break;
2564 // no automatic position/size: try to find the correct position and size
2565 if( eApiPos == cssc2::LegendPosition_CUSTOM )
2567 const XclChFramePos* pFramePos = mxFramePos ? &mxFramePos->GetFramePosData() : 0;
2569 /* Legend position. Only the settings from the CHFRAMEPOS record
2570 are used by Excel, the position in the CHLEGEND record will be
2571 ignored. */
2572 if( pFramePos )
2574 RelativePosition aRelPos(
2575 CalcRelativeFromChartX( pFramePos->maRect.mnX ),
2576 CalcRelativeFromChartY( pFramePos->maRect.mnY ),
2577 ::com::sun::star::drawing::Alignment_TOP_LEFT );
2578 aLegendProp.SetProperty( EXC_CHPROP_RELATIVEPOSITION, aRelPos );
2580 else
2582 // no manual position/size found, just go for the default
2583 eApiPos = cssc2::LegendPosition_LINE_END;
2586 /* Legend size. The member mnBRMode specifies whether size is
2587 automatic or changes manually. Manual size is given in points,
2588 not in chart units. */
2589 if( pFramePos && (pFramePos->mnBRMode == EXC_CHFRAMEPOS_ABSSIZE_POINTS) &&
2590 (pFramePos->maRect.mnWidth > 0) && (pFramePos->maRect.mnHeight > 0) )
2592 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2593 sal_Int32 nWidthHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnWidth / EXC_POINTS_PER_HMM );
2594 sal_Int32 nHeightHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnHeight / EXC_POINTS_PER_HMM );
2595 RelativeSize aRelSize( CalcRelativeFromHmmX( nWidthHmm ), CalcRelativeFromHmmY( nHeightHmm ) );
2596 aLegendProp.SetProperty( EXC_CHPROP_RELATIVESIZE, aRelSize );
2598 else
2600 // automatic size: determine entry direction from flags
2601 eApiExpand = ::get_flagvalue( maData.mnFlags, EXC_CHLEGEND_STACKED,
2602 cssc::ChartLegendExpansion_HIGH, cssc::ChartLegendExpansion_WIDE );
2605 aLegendProp.SetProperty( EXC_CHPROP_ANCHORPOSITION, eApiPos );
2606 aLegendProp.SetProperty( EXC_CHPROP_EXPANSION, eApiExpand );
2608 return xLegend;
2611 // ----------------------------------------------------------------------------
2613 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) :
2614 mnDropBar( nDropBar ),
2615 mnBarDist( 0 )
2619 void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm )
2621 rStrm >> mnBarDist;
2624 void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
2626 XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND;
2627 switch( mnDropBar )
2629 case EXC_CHDROPBAR_UP: eObjType = EXC_CHOBJTYPE_WHITEDROPBAR; break;
2630 case EXC_CHDROPBAR_DOWN: eObjType = EXC_CHOBJTYPE_BLACKDROPBAR; break;
2632 ConvertFrameBase( rRoot, rPropSet, eObjType );
2635 // ----------------------------------------------------------------------------
2637 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) :
2638 XclImpChRoot( rRoot ),
2639 maType( rRoot ),
2640 maTypeInfo( maType.GetTypeInfo() )
2642 // Initialize unused format indexes set. At this time, all formats are unused.
2643 for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx )
2644 maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx );
2647 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm )
2649 rStrm.Ignore( 16 );
2650 rStrm >> maData.mnFlags >> maData.mnGroupIdx;
2653 void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm )
2655 switch( rStrm.GetRecId() )
2657 case EXC_ID_CHCHART3D:
2658 mxChart3d.reset( new XclImpChChart3d );
2659 mxChart3d->ReadChChart3d( rStrm );
2660 break;
2661 case EXC_ID_CHLEGEND:
2662 mxLegend.reset( new XclImpChLegend( GetChRoot() ) );
2663 mxLegend->ReadRecordGroup( rStrm );
2664 break;
2665 case EXC_ID_CHDEFAULTTEXT:
2666 GetChartData().ReadChDefaultText( rStrm );
2667 break;
2668 case EXC_ID_CHDROPBAR:
2669 ReadChDropBar( rStrm );
2670 break;
2671 case EXC_ID_CHCHARTLINE:
2672 ReadChChartLine( rStrm );
2673 break;
2674 case EXC_ID_CHDATAFORMAT:
2675 ReadChDataFormat( rStrm );
2676 break;
2677 default:
2678 maType.ReadChType( rStrm );
2682 void XclImpChTypeGroup::Finalize()
2684 // check and set valid chart type
2685 bool bStockChart =
2686 (maType.GetRecId() == EXC_ID_CHLINE) && // must be a line chart
2687 !mxChart3d && // must be a 2d chart
2688 HasHiLoLine() && // must contain hi-lo lines
2689 (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3)); // correct series count
2690 maType.Finalize( bStockChart );
2692 // extended type info
2693 maTypeInfo.Set( maType.GetTypeInfo(), static_cast< bool >(mxChart3d), false );
2695 // reverse series order for some unstacked 2D chart types
2696 if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() )
2697 ::std::reverse( maSeries.begin(), maSeries.end() );
2699 // update chart type group format, may depend on chart type finalized above
2700 if( mxGroupFmt )
2701 mxGroupFmt->UpdateGroupFormat( maTypeInfo );
2704 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries )
2706 if( xSeries )
2707 maSeries.push_back( xSeries );
2708 // store first inserted series separately, series order may be reversed later
2709 if( !mxFirstSeries )
2710 mxFirstSeries = xSeries;
2713 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx )
2715 maUnusedFormats.erase( nFormatIdx );
2718 sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex()
2720 OSL_ENSURE( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2721 sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin();
2722 SetUsedFormatIndex( nFormatIdx );
2723 return nFormatIdx;
2726 bool XclImpChTypeGroup::HasVarPointFormat() const
2728 return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) &&
2729 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) || // multiple series allowed
2730 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) && // or exactly 1 series?
2731 (maSeries.size() == 1)));
2734 bool XclImpChTypeGroup::HasConnectorLines() const
2736 // existence of connector lines (only in stacked bar charts)
2737 if ( !(maType.IsStacked() || maType.IsPercent()) || (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
2738 return false;
2739 XclImpChLineFormatMap::const_iterator xConLine = maChartLines.find( EXC_CHCHARTLINE_CONNECT );
2740 return ( xConLine != maChartLines.end() && xConLine->second->HasLine() );
2743 const String& XclImpChTypeGroup::GetSingleSeriesTitle() const
2745 // no automatic title for series with trendlines or error bars
2746 // pie charts always show an automatic title, even if more series exist
2747 return (mxFirstSeries && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ?
2748 mxFirstSeries->GetTitle() : String::EmptyString();
2751 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const
2753 if( mxChart3d )
2754 mxChart3d->Convert( rPropSet, Is3dWallChart() );
2757 Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const
2759 return maType.CreateCoordSystem( Is3dChart() );
2762 Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const
2764 OSL_ENSURE( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2766 // create the chart type object
2767 Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() );
2769 // bar chart connector lines
2770 if( HasConnectorLines() )
2772 ScfPropertySet aDiaProp( xDiagram );
2773 aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true );
2776 /* Stock chart needs special processing. Create one 'big' series with
2777 data sequences of different roles. */
2778 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2779 CreateStockSeries( xChartType, nApiAxesSetIdx );
2780 else
2781 CreateDataSeries( xChartType, nApiAxesSetIdx );
2783 return xChartType;
2786 Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const
2788 Reference< XLabeledDataSequence > xLabeledSeq;
2789 // create category sequence from first visible series
2790 if( mxFirstSeries )
2791 xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG );
2792 return xLabeledSeq;
2795 void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm )
2797 if (maDropBars.find(EXC_CHDROPBAR_UP) == maDropBars.end())
2799 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2800 auto_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_UP));
2801 SAL_WNODEPRECATED_DECLARATIONS_POP
2802 p->ReadRecordGroup(rStrm);
2803 maDropBars.insert(EXC_CHDROPBAR_UP, p);
2805 else if(maDropBars.find(EXC_CHDROPBAR_DOWN) == maDropBars.end())
2807 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2808 auto_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN));
2809 SAL_WNODEPRECATED_DECLARATIONS_POP
2810 p->ReadRecordGroup(rStrm);
2811 maDropBars.insert(EXC_CHDROPBAR_DOWN, p);
2815 void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm )
2817 sal_uInt16 nLineId = rStrm.ReaduInt16();
2818 if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() )
2820 XclImpChLineFormat xLineFmt;
2821 xLineFmt.ReadChLineFormat( rStrm );
2822 maChartLines[ nLineId ] = xLineFmt;
2826 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm )
2828 // global series and data point format
2829 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2830 xDataFmt->ReadRecordGroup( rStrm );
2831 const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
2832 if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) &&
2833 (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) )
2834 mxGroupFmt = xDataFmt;
2838 void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType,
2839 Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const
2841 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2842 if( xSeriesCont.is() && xSeries.is() )
2844 // series stacking mode
2845 cssc2::StackingDirection eStacking = cssc2::StackingDirection_NO_STACKING;
2846 // stacked overrides deep-3d
2847 if( maType.IsStacked() || maType.IsPercent() )
2848 eStacking = cssc2::StackingDirection_Y_STACKING;
2849 else if( Is3dDeepChart() )
2850 eStacking = cssc2::StackingDirection_Z_STACKING;
2852 // additional series properties
2853 ScfPropertySet aSeriesProp( xSeries );
2854 aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking );
2855 aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx );
2857 // insert series into container
2860 xSeriesCont->addDataSeries( xSeries );
2862 catch( Exception& )
2864 OSL_FAIL( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2869 void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2871 bool bSpline = false;
2872 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
2874 Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries();
2875 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2876 bSpline |= (*aIt)->HasSpline();
2878 // spline - TODO: set at single series (#i66858#)
2879 if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) )
2881 ScfPropertySet aTypeProp( xChartType );
2882 aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES );
2886 void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2888 // create the data series object
2889 Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2890 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2891 if( xDataSink.is() )
2893 // create a list of data sequences from all series
2894 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2895 OSL_ENSURE( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2896 int nRoleIdx = (maSeries.size() == 3) ? 1 : 0;
2897 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end();
2898 (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
2900 // create a data sequence with a specific role
2901 OUString aRole;
2902 switch( nRoleIdx )
2904 case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES; break;
2905 case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES; break;
2906 case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES; break;
2907 case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES; break;
2909 Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole );
2910 if( xDataSeq.is() )
2911 aLabeledSeqVec.push_back( xDataSeq );
2914 // attach labeled data sequences to series and insert series into chart type
2915 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2917 // formatting of special stock chart elements
2918 ScfPropertySet aTypeProp( xChartType );
2919 aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() );
2920 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() );
2921 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true );
2922 // hi-lo line format
2923 XclImpChLineFormatMap::const_iterator xHiLoLine = maChartLines.find( EXC_CHCHARTLINE_HILO );
2924 if ( xHiLoLine != maChartLines.end() )
2926 ScfPropertySet aSeriesProp( xDataSeries );
2927 xHiLoLine->second->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2929 // white dropbar format
2930 XclImpChDropBarMap::const_iterator itr = maDropBars.find(EXC_CHDROPBAR_UP);
2931 Reference<XPropertySet> xWhitePropSet;
2932 if (itr != maDropBars.end() && aTypeProp.GetProperty(xWhitePropSet, EXC_CHPROP_WHITEDAY))
2934 ScfPropertySet aBarProp( xWhitePropSet );
2935 itr->second->Convert(GetChRoot(), aBarProp);
2937 // black dropbar format
2938 itr = maDropBars.find(EXC_CHDROPBAR_DOWN);
2939 Reference<XPropertySet> xBlackPropSet;
2940 if (itr != maDropBars.end() && aTypeProp.GetProperty(xBlackPropSet, EXC_CHPROP_BLACKDAY))
2942 ScfPropertySet aBarProp( xBlackPropSet );
2943 itr->second->Convert(GetChRoot(), aBarProp);
2946 // insert the series into the chart type object
2947 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2951 // Axes =======================================================================
2953 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) :
2954 XclImpChRoot( rRoot )
2958 void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm )
2960 rStrm >> maLabelData.mnCross >> maLabelData.mnLabelFreq >> maLabelData.mnTickFreq >> maLabelData.mnFlags;
2963 void XclImpChLabelRange::ReadChDateRange( XclImpStream& rStrm )
2965 rStrm >> maDateData.mnMinDate
2966 >> maDateData.mnMaxDate
2967 >> maDateData.mnMajorStep
2968 >> maDateData.mnMajorUnit
2969 >> maDateData.mnMinorStep
2970 >> maDateData.mnMinorUnit
2971 >> maDateData.mnBaseUnit
2972 >> maDateData.mnCross
2973 >> maDateData.mnFlags;
2976 void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const
2978 // automatic axis type detection
2979 rScaleData.AutoDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE );
2981 // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
2982 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
2984 /* Chart2 requires axis type CATEGORY for automatic category/date axis
2985 (even if it is a date axis currently). */
2986 rScaleData.AxisType = rScaleData.AutoDateAxis ? cssc2::AxisType::CATEGORY : cssc2::AxisType::DATE;
2987 rScaleData.Scaling = css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
2988 /* Min/max values depend on base time unit, they specify the number of
2989 days, months, or years starting from null date. */
2990 lclConvertTimeValue( GetRoot(), rScaleData.Minimum, maDateData.mnMinDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN ), maDateData.mnBaseUnit );
2991 lclConvertTimeValue( GetRoot(), rScaleData.Maximum, maDateData.mnMaxDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX ), maDateData.mnBaseUnit );
2992 // increment
2993 cssc::TimeIncrement& rTimeIncrement = rScaleData.TimeIncrement;
2994 lclConvertTimeInterval( rTimeIncrement.MajorTimeInterval, maDateData.mnMajorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR ), maDateData.mnMajorUnit );
2995 lclConvertTimeInterval( rTimeIncrement.MinorTimeInterval, maDateData.mnMinorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR ), maDateData.mnMinorUnit );
2996 // base unit
2997 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE ) )
2998 rTimeIncrement.TimeResolution.clear();
2999 else
3000 rTimeIncrement.TimeResolution <<= lclGetApiTimeUnit( maDateData.mnBaseUnit );
3002 else
3004 // do not overlap text unless all labels are visible
3005 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maLabelData.mnLabelFreq == 1 );
3006 // do not break text into several lines unless all labels are visible
3007 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maLabelData.mnLabelFreq == 1 );
3008 // do not stagger labels in two lines
3009 rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE );
3012 // reverse order
3013 bool bReverse = ::get_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient;
3014 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
3016 //! TODO #i58731# show n-th category
3019 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const
3021 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
3022 does not move the Y axis in 3D charts, regardless of actual settings.
3023 But: the Y axis has to be moved to "end", if the X axis is mirrored,
3024 to keep it at the left end of the chart. */
3025 bool bMaxCross = ::get_flag( maLabelData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS );
3026 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
3027 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
3029 // crossing position (depending on axis type text/date)
3030 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
3032 bool bAutoCross = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
3033 /* Crossing position value depends on base time unit, it specifies the
3034 number of days, months, or years from null date. Note that Excel
3035 2007/2010 write broken BIFF8 files, they always stores the number
3036 of days cregardless of the base time unit (and they are reading it
3037 the same way, thus wrongly displaying files written by Excel
3038 97-2003). This filter sticks to the correct behaviour of Excel
3039 97-2003. */
3040 double fCrossingPos = bAutoCross ? 1.0 : lclGetSerialDay( GetRoot(), maDateData.mnCross, maDateData.mnBaseUnit );
3041 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3043 else
3045 double fCrossingPos = b3dChart ? 1.0 : maLabelData.mnCross;
3046 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3050 // ----------------------------------------------------------------------------
3052 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) :
3053 XclImpChRoot( rRoot )
3057 void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm )
3059 rStrm >> maData.mfMin
3060 >> maData.mfMax
3061 >> maData.mfMajorStep
3062 >> maData.mfMinorStep
3063 >> maData.mfCross
3064 >> maData.mnFlags;
3067 void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const
3069 // scaling algorithm
3070 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3071 if( bLogScale )
3072 rScaleData.Scaling = css::chart2::LogarithmicScaling::create( comphelper::getProcessComponentContext() );
3073 else
3074 rScaleData.Scaling = css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3076 // min/max
3077 lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) );
3078 lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) );
3080 // increment
3081 bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR );
3082 bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR );
3083 // major increment
3084 IncrementData& rIncrementData = rScaleData.IncrementData;
3085 lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor );
3086 // minor increment
3087 Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
3088 rSubIncrementSeq.realloc( 1 );
3089 Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount;
3090 rIntervalCount.clear();
3091 if( bLogScale )
3093 if( !bAutoMinor )
3094 rIntervalCount <<= sal_Int32( 9 );
3096 else
3098 if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) )
3100 double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5;
3101 if( (1.0 <= fCount) && (fCount < 1001.0) )
3102 rIntervalCount <<= static_cast< sal_Int32 >( fCount );
3106 // reverse order
3107 bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient;
3108 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
3111 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const
3113 bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
3114 bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
3115 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3117 // crossing mode (max-cross flag overrides other crossing settings)
3118 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
3119 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
3121 // crossing position
3122 double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross;
3123 if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos );
3124 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3127 // ----------------------------------------------------------------------------
3129 namespace {
3131 sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos )
3133 using namespace ::com::sun::star::chart2::TickmarkStyle;
3134 sal_Int32 nApiTickmarks = NONE;
3135 ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) );
3136 ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) );
3137 return nApiTickmarks;
3140 cssc::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos )
3142 using namespace ::com::sun::star::chart;
3143 switch( nXclLabelPos )
3145 case EXC_CHTICK_LOW: return ChartAxisLabelPosition_OUTSIDE_START;
3146 case EXC_CHTICK_HIGH: return ChartAxisLabelPosition_OUTSIDE_END;
3147 case EXC_CHTICK_NEXT: return ChartAxisLabelPosition_NEAR_AXIS;
3149 return ChartAxisLabelPosition_NEAR_AXIS;
3152 } // namespace
3154 XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) :
3155 XclImpChRoot( rRoot )
3159 void XclImpChTick::ReadChTick( XclImpStream& rStrm )
3161 rStrm >> maData.mnMajor
3162 >> maData.mnMinor
3163 >> maData.mnLabelPos
3164 >> maData.mnBackMode;
3165 rStrm.Ignore( 16 );
3166 rStrm >> maData.maTextColor
3167 >> maData.mnFlags;
3169 if( GetBiff() == EXC_BIFF8 )
3171 // BIFF8: index into palette used instead of RGB data
3172 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
3173 // rotation
3174 rStrm >> maData.mnRotation;
3176 else
3178 // BIFF2-BIFF7: get rotation from text orientation
3179 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 );
3180 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
3184 Color XclImpChTick::GetFontColor() const
3186 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
3189 sal_uInt16 XclImpChTick::GetRotation() const
3191 /* n#720443: Ignore auto-rotation if there is a suggested rotation.
3192 * Better fix would be to improve our axis auto rotation algorithm.
3194 if( maData.mnRotation != EXC_ROT_NONE )
3195 return maData.mnRotation;
3196 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation;
3199 void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const
3201 rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) );
3202 rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) );
3203 rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) );
3204 rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, cssc::ChartAxisMarkPosition_AT_AXIS );
3207 // ----------------------------------------------------------------------------
3209 XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) :
3210 XclImpChRoot( rRoot ),
3211 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
3213 maData.mnType = nAxisType;
3216 void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm )
3218 rStrm >> maData.mnType;
3221 void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm )
3223 switch( rStrm.GetRecId() )
3225 case EXC_ID_CHLABELRANGE:
3226 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3227 mxLabelRange->ReadChLabelRange( rStrm );
3228 break;
3229 case EXC_ID_CHDATERANGE:
3230 if( !mxLabelRange )
3231 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3232 mxLabelRange->ReadChDateRange( rStrm );
3233 break;
3234 case EXC_ID_CHVALUERANGE:
3235 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3236 mxValueRange->ReadChValueRange( rStrm );
3237 break;
3238 case EXC_ID_CHFORMAT:
3239 rStrm >> mnNumFmtIdx;
3240 break;
3241 case EXC_ID_CHTICK:
3242 mxTick.reset( new XclImpChTick( GetChRoot() ) );
3243 mxTick->ReadChTick( rStrm );
3244 break;
3245 case EXC_ID_CHFONT:
3246 mxFont.reset( new XclImpChFont );
3247 mxFont->ReadChFont( rStrm );
3248 break;
3249 case EXC_ID_CHAXISLINE:
3250 ReadChAxisLine( rStrm );
3251 break;
3255 void XclImpChAxis::Finalize()
3257 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3258 if( !mxLabelRange )
3259 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3260 if( !mxValueRange )
3261 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3262 // remove invisible grid lines completely
3263 if( mxMajorGrid && !mxMajorGrid->HasLine() )
3264 mxMajorGrid.reset();
3265 if( mxMinorGrid && !mxMinorGrid->HasLine() )
3266 mxMinorGrid.reset();
3267 // default tick settings different in OOChart and Excel
3268 if( !mxTick )
3269 mxTick.reset( new XclImpChTick( GetChRoot() ) );
3270 // #i4140# different default axis line color
3271 if( !mxAxisLine )
3273 XclChLineFormat aLineFmt;
3274 // set "show axis" flag, default if line format record is missing
3275 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS );
3276 mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) );
3278 // add wall/floor frame for 3d charts
3279 if( !mxWallFrame )
3280 CreateWallFrame();
3283 sal_uInt16 XclImpChAxis::GetFontIndex() const
3285 return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
3288 Color XclImpChAxis::GetFontColor() const
3290 return mxTick ? mxTick->GetFontColor() : GetFontAutoColor();
3293 sal_uInt16 XclImpChAxis::GetRotation() const
3295 return mxTick ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION;
3298 Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const
3300 // create the axis object (always)
3301 Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY );
3302 if( xAxis.is() )
3304 ScfPropertySet aAxisProp( xAxis );
3305 // #i58688# axis enabled
3306 aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() );
3308 // axis line properties
3309 if( mxAxisLine )
3310 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
3311 // axis ticks properties
3312 if( mxTick )
3313 mxTick->Convert( aAxisProp );
3315 // axis caption text --------------------------------------------------
3317 // radar charts disable their category labels via chart type, not via axis
3318 bool bHasLabels = HasLabels() &&
3319 ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels());
3320 aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels );
3321 if( bHasLabels )
3323 // font settings from CHFONT record or from default text
3324 if( mxFont )
3325 ConvertFontBase( GetChRoot(), aAxisProp );
3326 else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ) )
3327 pDefText->ConvertFont( aAxisProp );
3328 // label text rotation
3329 ConvertRotationBase( GetChRoot(), aAxisProp, true );
3330 // number format
3331 sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx );
3332 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
3333 aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) );
3336 // axis scaling and increment -----------------------------------------
3338 const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo();
3339 ScaleData aScaleData = xAxis->getScaleData();
3340 // set axis type
3341 switch( GetAxisType() )
3343 case EXC_CHAXIS_X:
3344 if( rTypeInfo.mbCategoryAxis )
3346 aScaleData.AxisType = cssc2::AxisType::CATEGORY;
3347 aScaleData.Categories = rTypeGroup.CreateCategSequence();
3349 else
3350 aScaleData.AxisType = cssc2::AxisType::REALNUMBER;
3351 break;
3352 case EXC_CHAXIS_Y:
3353 aScaleData.AxisType = rTypeGroup.IsPercent() ?
3354 cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER;
3355 break;
3356 case EXC_CHAXIS_Z:
3357 aScaleData.AxisType = cssc2::AxisType::SERIES;
3358 break;
3360 // axis scaling settings, dependent on axis type
3361 switch( aScaleData.AxisType )
3363 case cssc2::AxisType::CATEGORY:
3364 case cssc2::AxisType::SERIES:
3365 OSL_ENSURE( mxLabelRange, "Missing Label Range" );
3366 // #i71684# radar charts have reversed rotation direction
3367 if (mxLabelRange)
3368 mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR );
3369 break;
3370 case cssc2::AxisType::REALNUMBER:
3371 case cssc2::AxisType::PERCENT:
3372 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3373 mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
3374 break;
3375 default:
3376 OSL_FAIL( "XclImpChAxis::CreateAxis - unknown axis type" );
3379 /* Do not set a value to the Origin member anymore (will be done via
3380 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3381 aScaleData.Origin.clear();
3383 // write back
3384 xAxis->setScaleData( aScaleData );
3386 // grid ---------------------------------------------------------------
3388 // main grid
3389 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3390 aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() );
3391 if( mxMajorGrid )
3392 mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3393 // sub grid
3394 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3395 if( aSubGridPropSeq.hasElements() )
3397 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3398 aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() );
3399 if( mxMinorGrid )
3400 mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3403 // position of crossing axis ------------------------------------------
3405 if( pCrossingAxis )
3406 pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup );
3408 return xAxis;
3411 void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const
3413 // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3414 if( mxWallFrame )
3415 mxWallFrame->Convert( rPropSet, true );
3418 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const
3420 if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) )
3422 OSL_ENSURE( mxLabelRange, "Missing Label Range" );
3423 if (mxLabelRange)
3424 mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() );
3426 else
3427 mxValueRange->ConvertAxisPosition( rPropSet );
3430 void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm )
3432 XclImpChLineFormatRef* pxLineFmt = 0;
3433 bool bWallFrame = false;
3434 switch( rStrm.ReaduInt16() )
3436 case EXC_CHAXISLINE_AXISLINE: pxLineFmt = &mxAxisLine; break;
3437 case EXC_CHAXISLINE_MAJORGRID: pxLineFmt = &mxMajorGrid; break;
3438 case EXC_CHAXISLINE_MINORGRID: pxLineFmt = &mxMinorGrid; break;
3439 case EXC_CHAXISLINE_WALLS: bWallFrame = true; break;
3441 if( bWallFrame )
3442 CreateWallFrame();
3444 bool bLoop = pxLineFmt || bWallFrame;
3445 while( bLoop )
3447 sal_uInt16 nRecId = rStrm.GetNextRecId();
3448 bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) ||
3449 (nRecId == EXC_ID_CHAREAFORMAT) ||
3450 (nRecId == EXC_ID_CHESCHERFORMAT))
3451 && rStrm.StartNextRecord();
3452 if( bLoop )
3454 if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) )
3456 pxLineFmt->reset( new XclImpChLineFormat );
3457 (*pxLineFmt)->ReadChLineFormat( rStrm );
3459 else if( bWallFrame && mxWallFrame )
3461 mxWallFrame->ReadSubRecord( rStrm );
3467 void XclImpChAxis::CreateWallFrame()
3469 switch( GetAxisType() )
3471 case EXC_CHAXIS_X:
3472 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) );
3473 break;
3474 case EXC_CHAXIS_Y:
3475 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) );
3476 break;
3477 default:
3478 mxWallFrame.reset();
3482 // ----------------------------------------------------------------------------
3484 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3485 XclImpChRoot( rRoot )
3487 maData.mnAxesSetId = nAxesSetId;
3490 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm )
3492 rStrm >> maData.mnAxesSetId >> maData.maRect;
3495 void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm )
3497 switch( rStrm.GetRecId() )
3499 case EXC_ID_CHFRAMEPOS:
3500 mxFramePos.reset( new XclImpChFramePos );
3501 mxFramePos->ReadChFramePos( rStrm );
3502 break;
3503 case EXC_ID_CHAXIS:
3504 ReadChAxis( rStrm );
3505 break;
3506 case EXC_ID_CHTEXT:
3507 ReadChText( rStrm );
3508 break;
3509 case EXC_ID_CHPLOTFRAME:
3510 ReadChPlotFrame( rStrm );
3511 break;
3512 case EXC_ID_CHTYPEGROUP:
3513 ReadChTypeGroup( rStrm );
3514 break;
3518 void XclImpChAxesSet::Finalize()
3520 if( IsValidAxesSet() )
3522 // finalize chart type groups, erase empty groups without series
3523 XclImpChTypeGroupMap aValidGroups;
3524 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3526 XclImpChTypeGroupRef xTypeGroup = aIt->second;
3527 xTypeGroup->Finalize();
3528 if( xTypeGroup->IsValidGroup() )
3529 aValidGroups.insert(
3530 XclImpChTypeGroupMap::value_type(aIt->first, xTypeGroup));
3532 maTypeGroups.swap( aValidGroups );
3535 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3536 if( IsValidAxesSet() )
3538 // always create missing axis objects
3539 if( !mxXAxis )
3540 mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) );
3541 if( !mxYAxis )
3542 mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) );
3543 if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() )
3544 mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) );
3546 // finalize axes
3547 if( mxXAxis ) mxXAxis->Finalize();
3548 if( mxYAxis ) mxYAxis->Finalize();
3549 if( mxZAxis ) mxZAxis->Finalize();
3551 // finalize axis titles
3552 const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE );
3553 String aAutoTitle("Axis Title");
3554 lclFinalizeTitle( mxXAxisTitle, pDefText, aAutoTitle );
3555 lclFinalizeTitle( mxYAxisTitle, pDefText, aAutoTitle );
3556 lclFinalizeTitle( mxZAxisTitle, pDefText, aAutoTitle );
3558 // #i47745# missing plot frame -> invisible border and area
3559 if( !mxPlotFrame )
3560 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3564 XclImpChTypeGroupRef XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3566 XclImpChTypeGroupMap::const_iterator itr = maTypeGroups.find(nGroupIdx);
3567 return itr == maTypeGroups.end() ? XclImpChTypeGroupRef() : itr->second;
3570 XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const
3572 XclImpChTypeGroupRef xTypeGroup;
3573 if( !maTypeGroups.empty() )
3574 xTypeGroup = maTypeGroups.begin()->second;
3575 return xTypeGroup;
3578 XclImpChLegendRef XclImpChAxesSet::GetLegend() const
3580 XclImpChLegendRef xLegend;
3581 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt )
3582 xLegend = aIt->second->GetLegend();
3583 return xLegend;
3586 const String& XclImpChAxesSet::GetSingleSeriesTitle() const
3588 return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : String::EmptyString();
3591 void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const
3593 if( IsValidAxesSet() && xDiagram.is() )
3595 // diagram background formatting
3596 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY )
3597 ConvertBackground( xDiagram );
3599 // create the coordinate system, this inserts all chart types and series
3600 Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram );
3601 if( xCoordSystem.is() )
3603 // insert coordinate system, if not already done
3606 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW );
3607 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3608 if( aCoordSystems.getLength() == 0 )
3609 xCoordSystemCont->addCoordinateSystem( xCoordSystem );
3611 catch( Exception& )
3613 OSL_FAIL( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3616 // create the axes with grids and axis titles and insert them into the diagram
3617 ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() );
3618 ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() );
3619 ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 );
3624 void XclImpChAxesSet::ConvertTitlePositions() const
3626 if( mxXAxisTitle )
3627 mxXAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_X ) );
3628 if( mxYAxisTitle )
3629 mxYAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Y ) );
3630 if( mxZAxisTitle )
3631 mxZAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Z ) );
3634 void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm )
3636 XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) );
3637 xAxis->ReadRecordGroup( rStrm );
3639 switch( xAxis->GetAxisType() )
3641 case EXC_CHAXIS_X: mxXAxis = xAxis; break;
3642 case EXC_CHAXIS_Y: mxYAxis = xAxis; break;
3643 case EXC_CHAXIS_Z: mxZAxis = xAxis; break;
3647 void XclImpChAxesSet::ReadChText( XclImpStream& rStrm )
3649 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3650 xText->ReadRecordGroup( rStrm );
3652 switch( xText->GetLinkTarget() )
3654 case EXC_CHOBJLINK_XAXIS: mxXAxisTitle = xText; break;
3655 case EXC_CHOBJLINK_YAXIS: mxYAxisTitle = xText; break;
3656 case EXC_CHOBJLINK_ZAXIS: mxZAxisTitle = xText; break;
3660 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm )
3662 if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() )
3664 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3665 mxPlotFrame->ReadRecordGroup( rStrm );
3669 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm )
3671 XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
3672 xTypeGroup->ReadRecordGroup( rStrm );
3673 sal_uInt16 nGroupIdx = xTypeGroup->GetGroupIdx();
3674 XclImpChTypeGroupMap::iterator itr = maTypeGroups.lower_bound(nGroupIdx);
3675 if (itr != maTypeGroups.end() && !maTypeGroups.key_comp()(nGroupIdx, itr->first))
3676 // Overwrite the existing element.
3677 itr->second = xTypeGroup;
3678 else
3679 maTypeGroups.insert(
3680 itr, XclImpChTypeGroupMap::value_type(nGroupIdx, xTypeGroup));
3683 Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const
3685 Reference< XCoordinateSystem > xCoordSystem;
3687 /* Try to get existing ccordinate system. For now, all series from primary
3688 and secondary axes sets are inserted into one coordinate system. Later,
3689 this should be changed to use one coordinate system for each axes set. */
3690 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY );
3691 if( xCoordSystemCont.is() )
3693 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3694 OSL_ENSURE( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3695 if( aCoordSystems.getLength() > 0 )
3696 xCoordSystem = aCoordSystems[ 0 ];
3699 // create the coordinate system according to the first chart type
3700 if( !xCoordSystem.is() )
3702 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3703 if( xTypeGroup )
3705 xCoordSystem = xTypeGroup->CreateCoordSystem();
3706 // convert 3d chart settings
3707 ScfPropertySet aDiaProp( xDiagram );
3708 xTypeGroup->ConvertChart3d( aDiaProp );
3712 /* Create XChartType objects for all chart type groups. Each group will
3713 add its series to the data provider attached to the chart document. */
3714 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3715 if( xChartTypeCont.is() )
3717 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3718 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3722 Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx );
3723 if( xChartType.is() )
3724 xChartTypeCont->addChartType( xChartType );
3726 catch( Exception& )
3728 OSL_FAIL( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3733 return xCoordSystem;
3736 void XclImpChAxesSet::ConvertAxis(
3737 XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle,
3738 Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const
3740 if( xChAxis )
3742 // create and attach the axis object
3743 Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis );
3744 if( xAxis.is() )
3746 // create and attach the axis title
3747 if( xChAxisTitle ) try
3749 Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW );
3750 Reference< XTitle > xTitle( xChAxisTitle->CreateTitle(), UNO_SET_THROW );
3751 xTitled->setTitleObject( xTitle );
3753 catch( Exception& )
3755 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3758 // insert axis into coordinate system
3761 sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension();
3762 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3763 xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx );
3765 catch( Exception& )
3767 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3773 Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const
3775 Reference< XAxis > xAxis;
3776 if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() )
3777 xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis );
3778 return xAxis;
3781 void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const
3783 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3784 if( xTypeGroup && xTypeGroup->Is3dWallChart() )
3786 // wall/floor formatting (3D charts)
3787 if( mxXAxis )
3789 ScfPropertySet aWallProp( xDiagram->getWall() );
3790 mxXAxis->ConvertWall( aWallProp );
3792 if( mxYAxis )
3794 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3795 mxYAxis->ConvertWall( aFloorProp );
3798 else if( mxPlotFrame )
3800 // diagram background formatting
3801 ScfPropertySet aWallProp( xDiagram->getWall() );
3802 mxPlotFrame->Convert( aWallProp );
3806 // The chart object ===========================================================
3808 XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) :
3809 XclImpChRoot( rRoot, *this )
3811 mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3812 mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3815 XclImpChChart::~XclImpChChart()
3819 void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm )
3821 // coordinates are stored as 16.16 fixed point
3822 rStrm >> maRect;
3825 void XclImpChChart::ReadSubRecord( XclImpStream& rStrm )
3827 switch( rStrm.GetRecId() )
3829 case EXC_ID_CHFRAME:
3830 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3831 mxFrame->ReadRecordGroup( rStrm );
3832 break;
3833 case EXC_ID_CHSERIES:
3834 ReadChSeries( rStrm );
3835 break;
3836 case EXC_ID_CHPROPERTIES:
3837 ReadChProperties( rStrm );
3838 break;
3839 case EXC_ID_CHDEFAULTTEXT:
3840 ReadChDefaultText( rStrm );
3841 break;
3842 case EXC_ID_CHAXESSET:
3843 ReadChAxesSet( rStrm );
3844 break;
3845 case EXC_ID_CHTEXT:
3846 ReadChText( rStrm );
3847 break;
3848 case EXC_ID_CHEND:
3849 Finalize(); // finalize the entire chart object
3850 break;
3854 void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm )
3856 sal_uInt16 nTextId = rStrm.ReaduInt16();
3857 if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() )
3859 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3860 auto_ptr<XclImpChText> pText(new XclImpChText(GetChRoot()));
3861 SAL_WNODEPRECATED_DECLARATIONS_POP
3862 pText->ReadRecordGroup(rStrm);
3863 maDefTexts.insert(nTextId, pText);
3867 void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm )
3869 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
3870 xDataFmt->ReadRecordGroup( rStrm );
3871 if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3873 const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
3874 XclImpChDataFormatMap::iterator itr = maDataFmts.lower_bound(rPos);
3875 if (itr == maDataFmts.end() || maDataFmts.key_comp()(rPos, itr->first))
3876 // No element exists for this data point. Insert it.
3877 maDataFmts.insert(
3878 itr, XclImpChDataFormatMap::value_type(rPos, xDataFmt));
3880 /* Do not overwrite existing data format group, Excel always uses the
3881 first data format group occuring in any CHSERIES group. */
3885 void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
3887 if( !mxFrame )
3888 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3889 mxFrame->UpdateObjFrame( rLineData, rFillData );
3892 XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3894 XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx );
3895 if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx );
3896 if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup();
3897 return xTypeGroup;
3900 const XclImpChText* XclImpChChart::GetDefaultText( XclChTextType eTextType ) const
3902 sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL;
3903 bool bBiff8 = GetBiff() == EXC_BIFF8;
3904 switch( eTextType )
3906 case EXC_CHTEXTTYPE_TITLE: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3907 case EXC_CHTEXTTYPE_LEGEND: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3908 case EXC_CHTEXTTYPE_AXISTITLE: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3909 case EXC_CHTEXTTYPE_AXISLABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3910 case EXC_CHTEXTTYPE_DATALABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3913 XclImpChTextMap::const_iterator itr = maDefTexts.find(nDefTextId);
3914 return itr == maDefTexts.end() ? NULL : itr->second;
3917 bool XclImpChChart::IsManualPlotArea() const
3919 // there is no real automatic mode in BIFF5 charts
3920 return (GetBiff() <= EXC_BIFF5) || ::get_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3923 void XclImpChChart::Convert( const Reference<XChartDocument>& xChartDoc,
3924 XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
3926 // initialize conversion (locks the model to suppress any internal updates)
3927 InitConversion( xChartDoc, rChartRect );
3929 // chart frame formatting
3930 if( mxFrame )
3932 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3933 mxFrame->Convert( aFrameProp );
3936 // chart title
3937 if( mxTitle ) try
3939 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY_THROW );
3940 Reference< XTitle > xTitle( mxTitle->CreateTitle(), UNO_SET_THROW );
3941 xTitled->setTitleObject( xTitle );
3943 catch( Exception& )
3947 /* Create the diagram object and attach it to the chart document. Currently,
3948 one diagram is used to carry all coordinate systems and data series. */
3949 Reference< XDiagram > xDiagram = CreateDiagram();
3950 xChartDoc->setFirstDiagram( xDiagram );
3952 // coordinate systems and chart types, convert axis settings
3953 mxPrimAxesSet->Convert( xDiagram );
3954 mxSecnAxesSet->Convert( xDiagram );
3956 // legend
3957 if( xDiagram.is() && mxLegend )
3958 xDiagram->setLegend( mxLegend->CreateLegend() );
3960 /* Following all conversions needing the old Chart1 API that involves full
3961 initialization of the chart view. */
3962 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY );
3963 if( xChart1Doc.is() )
3965 Reference< cssc::XDiagram > xDiagram1 = xChart1Doc->getDiagram();
3967 /* Set the 'IncludeHiddenCells' property via the old API as only this
3968 ensures that the data provider and all created sequences get this
3969 flag correctly. */
3970 ScfPropertySet aDiaProp( xDiagram1 );
3971 bool bShowVisCells = ::get_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY );
3972 aDiaProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells );
3974 // plot area position and size (there is no real automatic mode in BIFF5 charts)
3975 XclImpChFramePosRef xPlotAreaPos = mxPrimAxesSet->GetPlotAreaFramePos();
3976 if( IsManualPlotArea() && xPlotAreaPos ) try
3978 const XclChFramePos& rFramePos = xPlotAreaPos->GetFramePosData();
3979 if( (rFramePos.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rFramePos.mnBRMode == EXC_CHFRAMEPOS_PARENT) )
3981 Reference< cssc::XDiagramPositioning > xPositioning( xDiagram1, UNO_QUERY_THROW );
3982 ::com::sun::star::awt::Rectangle aDiagramRect = CalcHmmFromChartRect( rFramePos.maRect );
3983 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
3984 const XclImpChTypeGroup* pFirstTypeGroup = mxPrimAxesSet->GetFirstTypeGroup().get();
3985 if( pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE) )
3986 xPositioning->setDiagramPositionExcludingAxes( aDiagramRect );
3987 else if( pFirstTypeGroup && pFirstTypeGroup->Is3dChart() )
3988 xPositioning->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect );
3989 else
3990 xPositioning->setDiagramPositionIncludingAxes( aDiagramRect );
3993 catch( Exception& )
3997 // positions of all title objects
3998 if( mxTitle )
3999 mxTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE ) );
4000 mxPrimAxesSet->ConvertTitlePositions();
4001 mxSecnAxesSet->ConvertTitlePositions();
4004 // unlock the model
4005 FinishConversion( rDffConv );
4007 // start listening to this chart
4008 ScDocument& rDoc = GetRoot().GetDoc();
4009 if( ScChartListenerCollection* pChartCollection = rDoc.GetChartListenerCollection() )
4011 SAL_WNODEPRECATED_DECLARATIONS_PUSH
4012 ::std::auto_ptr< ::std::vector< ScTokenRef > > xRefTokens( new ::std::vector< ScTokenRef > );
4013 SAL_WNODEPRECATED_DECLARATIONS_POP
4014 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
4015 (*aIt)->FillAllSourceLinks( *xRefTokens );
4016 if( !xRefTokens->empty() )
4018 SAL_WNODEPRECATED_DECLARATIONS_PUSH
4019 ::std::auto_ptr< ScChartListener > xListener( new ScChartListener( rObjName, &rDoc, xRefTokens.release() ) );
4020 SAL_WNODEPRECATED_DECLARATIONS_POP
4021 xListener->SetUsed( true );
4022 xListener->StartListeningTo();
4023 pChartCollection->insert( xListener.release() );
4028 void XclImpChChart::ReadChSeries( XclImpStream& rStrm )
4030 sal_uInt16 nNewSeriesIdx = static_cast< sal_uInt16 >( maSeries.size() );
4031 XclImpChSeriesRef xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx ) );
4032 xSeries->ReadRecordGroup( rStrm );
4033 maSeries.push_back( xSeries );
4036 void XclImpChChart::ReadChProperties( XclImpStream& rStrm )
4038 rStrm >> maProps.mnFlags >> maProps.mnEmptyMode;
4041 void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm )
4043 XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) );
4044 xAxesSet->ReadRecordGroup( rStrm );
4045 switch( xAxesSet->GetAxesSetId() )
4047 case EXC_CHAXESSET_PRIMARY: mxPrimAxesSet = xAxesSet; break;
4048 case EXC_CHAXESSET_SECONDARY: mxSecnAxesSet = xAxesSet; break;
4052 void XclImpChChart::ReadChText( XclImpStream& rStrm )
4054 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
4055 xText->ReadRecordGroup( rStrm );
4056 switch( xText->GetLinkTarget() )
4058 case EXC_CHOBJLINK_TITLE:
4059 mxTitle = xText;
4060 break;
4061 case EXC_CHOBJLINK_DATA:
4063 sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx;
4064 if( nSeriesIdx < maSeries.size() )
4065 maSeries[ nSeriesIdx ]->SetDataLabel( xText );
4067 break;
4071 void XclImpChChart::Finalize()
4073 // finalize series (must be done first)
4074 FinalizeSeries();
4075 // #i49218# legend may be attached to primary or secondary axes set
4076 mxLegend = mxPrimAxesSet->GetLegend();
4077 if( !mxLegend )
4078 mxLegend = mxSecnAxesSet->GetLegend();
4079 if( mxLegend )
4080 mxLegend->Finalize();
4081 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
4082 mxPrimAxesSet->Finalize();
4083 mxSecnAxesSet->Finalize();
4084 // formatting of all series
4085 FinalizeDataFormats();
4086 // #i47745# missing frame -> invisible border and area
4087 if( !mxFrame )
4088 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
4089 // chart title
4090 FinalizeTitle();
4093 void XclImpChChart::FinalizeSeries()
4095 for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt )
4097 XclImpChSeriesRef xSeries = *aSIt;
4098 if( xSeries->HasParentSeries() )
4100 /* Process child series (trend lines and error bars). Data of
4101 child series will be set at the connected parent series. */
4102 if( xSeries->GetParentIdx() < maSeries.size() )
4103 maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries );
4105 else
4107 // insert the series into the related chart type group
4108 if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() )
4109 pTypeGroup->AddSeries( xSeries );
4114 void XclImpChChart::FinalizeDataFormats()
4116 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4117 Each CHDATAFORMAT group specifies the series and data point it is
4118 assigned to. This makes it possible to have a data format that is
4119 related to another series, e.g. a CHDATAFORMAT group for series 2 is
4120 part of a CHSERIES group that describes series 1. Therefore the chart
4121 itself has collected all CHDATAFORMAT groups to be able to store data
4122 format groups for series that have not been imported at that time. This
4123 loop finally assigns these groups to the related series. */
4124 for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt )
4126 sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx;
4127 if( nSeriesIdx < maSeries.size() )
4128 maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second );
4131 /* #i51639# (part 2): Finalize data formats of all series. This adds for
4132 example missing CHDATAFORMAT groups for entire series that are needed
4133 for automatic colors of lines and areas. */
4134 for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt )
4135 (*aVIt)->FinalizeDataFormats();
4138 void XclImpChChart::FinalizeTitle()
4140 // special handling for auto-generated title
4141 String aAutoTitle;
4142 if( !mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString()) )
4144 // automatic title from first series name (if there are no series on secondary axes set)
4145 if( !mxSecnAxesSet->IsValidAxesSet() )
4146 aAutoTitle = mxPrimAxesSet->GetSingleSeriesTitle();
4147 if( mxTitle || (aAutoTitle.Len() > 0) )
4149 if( !mxTitle )
4150 mxTitle.reset( new XclImpChText( GetChRoot() ) );
4151 if( aAutoTitle.Len() == 0 )
4152 aAutoTitle = "Chart Title";
4156 // will reset mxTitle, if it does not contain a string and no auto title exists
4157 lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ), aAutoTitle );
4160 Reference< XDiagram > XclImpChChart::CreateDiagram() const
4162 // create a diagram object
4163 Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY );
4165 // convert global chart settings
4166 ScfPropertySet aDiaProp( xDiagram );
4168 // treatment of missing values
4169 using namespace cssc::MissingValueTreatment;
4170 sal_Int32 nMissingValues = LEAVE_GAP;
4171 switch( maProps.mnEmptyMode )
4173 case EXC_CHPROPS_EMPTY_SKIP: nMissingValues = LEAVE_GAP; break;
4174 case EXC_CHPROPS_EMPTY_ZERO: nMissingValues = USE_ZERO; break;
4175 case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE; break;
4177 aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues );
4179 return xDiagram;
4182 // ----------------------------------------------------------------------------
4184 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot& rRoot, bool bOwnTab ) :
4185 XclImpDrawing( rRoot, bOwnTab ), // sheet charts may contain OLE objects
4186 mnScTab( rRoot.GetCurrScTab() ),
4187 mbOwnTab( bOwnTab )
4191 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter& rDffConv,
4192 const Reference< XModel >& rxModel, const Rectangle& rChartRect )
4194 maChartRect = rChartRect; // needed in CalcAnchorRect() callback
4196 SdrModel* pSdrModel = 0;
4197 SdrPage* pSdrPage = 0;
4198 if( mbOwnTab )
4200 // chart sheet: insert all shapes into the sheet, not into the chart object
4201 pSdrModel = GetDoc().GetDrawLayer();
4202 pSdrPage = GetSdrPage( mnScTab );
4204 else
4206 // embedded chart object: insert all shapes into the chart
4209 Reference< XDrawPageSupplier > xDrawPageSupp( rxModel, UNO_QUERY_THROW );
4210 Reference< XDrawPage > xDrawPage( xDrawPageSupp->getDrawPage(), UNO_SET_THROW );
4211 pSdrPage = ::GetSdrPageFromXDrawPage( xDrawPage );
4212 pSdrModel = pSdrPage ? pSdrPage->GetModel() : 0;
4214 catch( Exception& )
4219 if( pSdrModel && pSdrPage )
4220 ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
4223 Rectangle XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool bDffAnchor ) const
4225 /* In objects with DFF client anchor, the position of the shape is stored
4226 in the cell address components of the client anchor. In old BIFF3-BIFF5
4227 objects, the position is stored in the offset components of the anchor. */
4228 Rectangle aRect(
4229 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnCol : rAnchor.mnLX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
4230 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnRow : rAnchor.mnTY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ),
4231 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnCol : rAnchor.mnRX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
4232 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnRow : rAnchor.mnBY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ) );
4233 aRect.Justify();
4234 // move shapes into chart area for sheet charts
4235 if( mbOwnTab )
4236 aRect.Move( maChartRect.Left(), maChartRect.Top() );
4237 return aRect;
4240 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase& )
4244 // ----------------------------------------------------------------------------
4246 XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) :
4247 XclImpRoot( rRoot ),
4248 mbOwnTab( bOwnTab ),
4249 mbIsPivotChart( false )
4253 XclImpChart::~XclImpChart()
4257 void XclImpChart::ReadChartSubStream( XclImpStream& rStrm )
4259 XclImpPageSettings& rPageSett = GetPageSettings();
4260 XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
4262 bool bLoop = true;
4263 while( bLoop && rStrm.StartNextRecord() )
4265 // page settings - only for charts in entire sheet
4266 if( mbOwnTab ) switch( rStrm.GetRecId() )
4268 case EXC_ID_HORPAGEBREAKS:
4269 case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( rStrm ); break;
4270 case EXC_ID_HEADER:
4271 case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( rStrm ); break;
4272 case EXC_ID_LEFTMARGIN:
4273 case EXC_ID_RIGHTMARGIN:
4274 case EXC_ID_TOPMARGIN:
4275 case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( rStrm ); break;
4276 case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( rStrm ); break;
4277 case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm ); break;
4278 case EXC_ID_HCENTER:
4279 case EXC_ID_VCENTER: rPageSett.ReadCenter( rStrm ); break;
4280 case EXC_ID_SETUP: rPageSett.ReadSetup( rStrm ); break;
4281 case EXC_ID8_IMGDATA: rPageSett.ReadImgData( rStrm ); break;
4283 case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( rStrm, true );break;
4284 case EXC_ID_SCL: rTabViewSett.ReadScl( rStrm ); break;
4286 case EXC_ID_SHEETEXT: //0x0862
4288 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4289 XclImpPalette& rPal = GetPalette();
4290 rTabViewSett.ReadTabBgColor( rStrm, rPal);
4292 break;
4294 case EXC_ID_CODENAME: ReadCodeName( rStrm, false ); break;
4297 // common records
4298 switch( rStrm.GetRecId() )
4300 case EXC_ID_EOF: bLoop = false; break;
4302 // #i31882# ignore embedded chart objects
4303 case EXC_ID2_BOF:
4304 case EXC_ID3_BOF:
4305 case EXC_ID4_BOF:
4306 case EXC_ID5_BOF: XclTools::SkipSubStream( rStrm ); break;
4308 case EXC_ID_CHCHART: ReadChChart( rStrm ); break;
4310 case EXC_ID8_CHPIVOTREF:
4311 GetTracer().TracePivotChartExists();
4312 mbIsPivotChart = true;
4313 break;
4315 // BIFF specific records
4316 default: switch( GetBiff() )
4318 case EXC_BIFF5: switch( rStrm.GetRecId() )
4320 case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
4322 break;
4323 case EXC_BIFF8: switch( rStrm.GetRecId() )
4325 case EXC_ID_MSODRAWING: GetChartDrawing().ReadMsoDrawing( rStrm ); break;
4326 // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4327 case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
4329 break;
4330 default:;
4336 void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
4338 if( !mxChartData )
4339 mxChartData.reset( new XclImpChChart( GetRoot() ) );
4340 mxChartData->UpdateObjFrame( rLineData, rFillData );
4343 sal_Size XclImpChart::GetProgressSize() const
4345 return
4346 (mxChartData ? mxChartData->GetProgressSize() : 0) +
4347 (mxChartDrawing ? mxChartDrawing->GetProgressSize() : 0);
4350 void XclImpChart::Convert( Reference< XModel > xModel, XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
4352 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
4353 if( xChartDoc.is() )
4355 if( mxChartData )
4356 mxChartData->Convert( xChartDoc, rDffConv, rObjName, rChartRect );
4357 if( mxChartDrawing )
4358 mxChartDrawing->ConvertObjects( rDffConv, xModel, rChartRect );
4362 XclImpChartDrawing& XclImpChart::GetChartDrawing()
4364 if( !mxChartDrawing )
4365 mxChartDrawing.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab ) );
4366 return *mxChartDrawing;
4369 void XclImpChart::ReadChChart( XclImpStream& rStrm )
4371 mxChartData.reset( new XclImpChChart( GetRoot() ) );
4372 mxChartData->ReadRecordGroup( rStrm );
4375 // ============================================================================
4377 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */