fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xichart.cxx
blob4444dc0edc7b9fd926255cbcd6c69fc430633c71
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>
24 #include <utility>
26 #include <com/sun/star/frame/XModel.hpp>
27 #include <com/sun/star/drawing/Direction3D.hpp>
28 #include <com/sun/star/drawing/ProjectionMode.hpp>
29 #include <com/sun/star/drawing/ShadeMode.hpp>
30 #include <com/sun/star/drawing/XShape.hpp>
31 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
32 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
33 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
34 #include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
35 #include <com/sun/star/chart/ChartAxisPosition.hpp>
36 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
37 #include <com/sun/star/chart/TimeInterval.hpp>
38 #include <com/sun/star/chart/TimeUnit.hpp>
39 #include <com/sun/star/chart/XChartDocument.hpp>
40 #include <com/sun/star/chart/XDiagramPositioning.hpp>
41 #include <com/sun/star/chart/DataLabelPlacement.hpp>
42 #include <com/sun/star/chart/ErrorBarStyle.hpp>
43 #include <com/sun/star/chart/MissingValueTreatment.hpp>
44 #include <com/sun/star/chart2/LinearRegressionCurve.hpp>
45 #include <com/sun/star/chart2/ExponentialRegressionCurve.hpp>
46 #include <com/sun/star/chart2/LogarithmicRegressionCurve.hpp>
47 #include <com/sun/star/chart2/PotentialRegressionCurve.hpp>
48 #include <com/sun/star/chart2/PolynomialRegressionCurve.hpp>
49 #include <com/sun/star/chart2/MovingAverageRegressionCurve.hpp>
50 #include <com/sun/star/chart2/CartesianCoordinateSystem2d.hpp>
51 #include <com/sun/star/chart2/CartesianCoordinateSystem3d.hpp>
52 #include <com/sun/star/chart2/FormattedString.hpp>
53 #include <com/sun/star/chart2/LogarithmicScaling.hpp>
54 #include <com/sun/star/chart2/LinearScaling.hpp>
55 #include <com/sun/star/chart2/PolarCoordinateSystem2d.hpp>
56 #include <com/sun/star/chart2/PolarCoordinateSystem3d.hpp>
57 #include <com/sun/star/chart2/XChartDocument.hpp>
58 #include <com/sun/star/chart2/XDiagram.hpp>
59 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
60 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
61 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
62 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
63 #include <com/sun/star/chart2/XTitled.hpp>
64 #include <com/sun/star/chart2/AxisType.hpp>
65 #include <com/sun/star/chart2/CurveStyle.hpp>
66 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
67 #include <com/sun/star/chart2/DataPointLabel.hpp>
68 #include <com/sun/star/chart2/LegendPosition.hpp>
69 #include <com/sun/star/chart2/StackingDirection.hpp>
70 #include <com/sun/star/chart2/TickmarkStyle.hpp>
71 #include <com/sun/star/chart2/RelativePosition.hpp>
72 #include <com/sun/star/chart2/RelativeSize.hpp>
73 #include <com/sun/star/chart2/data/XDataProvider.hpp>
74 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
75 #include <com/sun/star/chart2/data/XDataSink.hpp>
76 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
77 #include <o3tl/numeric.hxx>
78 #include <o3tl/ptr_container.hxx>
79 #include <sfx2/objsh.hxx>
80 #include <svx/svdpage.hxx>
81 #include <svx/unoapi.hxx>
83 #include "document.hxx"
84 #include "drwlayer.hxx"
85 #include "rangeutl.hxx"
86 #include "tokenarray.hxx"
87 #include "token.hxx"
88 #include "compiler.hxx"
89 #include "reftokenhelper.hxx"
90 #include "chartlis.hxx"
91 #include "fprogressbar.hxx"
92 #include "xltracer.hxx"
93 #include "xistream.hxx"
94 #include "xiformula.hxx"
95 #include "xistyle.hxx"
96 #include "xipage.hxx"
97 #include "xiview.hxx"
99 using ::com::sun::star::uno::Any;
100 using ::com::sun::star::uno::Reference;
101 using ::com::sun::star::uno::Sequence;
102 using ::com::sun::star::uno::UNO_QUERY;
103 using ::com::sun::star::uno::UNO_QUERY_THROW;
104 using ::com::sun::star::uno::UNO_SET_THROW;
105 using ::com::sun::star::uno::Exception;
106 using ::com::sun::star::beans::XPropertySet;
107 using ::com::sun::star::lang::XMultiServiceFactory;
108 using ::com::sun::star::frame::XModel;
109 using ::com::sun::star::util::XNumberFormatsSupplier;
110 using ::com::sun::star::drawing::XDrawPage;
111 using ::com::sun::star::drawing::XDrawPageSupplier;
112 using ::com::sun::star::drawing::XShape;
114 using namespace ::com::sun::star::chart2;
116 using ::com::sun::star::chart2::data::XDataProvider;
117 using ::com::sun::star::chart2::data::XDataReceiver;
118 using ::com::sun::star::chart2::data::XDataSequence;
119 using ::com::sun::star::chart2::data::XDataSink;
120 using ::com::sun::star::chart2::data::XLabeledDataSequence;
121 using ::com::sun::star::chart2::data::LabeledDataSequence;
123 using ::formula::FormulaToken;
124 using ::formula::StackVar;
125 using ::boost::shared_ptr;
126 using ::std::pair;
127 using ::std::unique_ptr;
129 namespace cssc = ::com::sun::star::chart;
130 namespace cssc2 = ::com::sun::star::chart2;
132 // Helpers ====================================================================
134 namespace {
136 XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect )
138 rRect.mnX = rStrm.ReadInt32();
139 rRect.mnY = rStrm.ReadInt32();
140 rRect.mnWidth = rStrm.ReadInt32();
141 rRect.mnHeight = rStrm.ReadInt32();
142 return rStrm;
145 inline void lclSetValueOrClearAny( Any& rAny, double fValue, bool bClear )
147 if( bClear )
148 rAny.clear();
149 else
150 rAny <<= fValue;
153 void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear )
155 if( !bClear && bLogScale )
156 fValue = pow( 10.0, fValue );
157 lclSetValueOrClearAny( rAny, fValue, bClear );
160 double lclGetSerialDay( const XclImpRoot& rRoot, sal_uInt16 nValue, sal_uInt16 nTimeUnit )
162 switch( nTimeUnit )
164 case EXC_CHDATERANGE_DAYS:
165 return nValue;
166 case EXC_CHDATERANGE_MONTHS:
167 return rRoot.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16 >( 1 + nValue % 12 ), static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue / 12 ) ) );
168 case EXC_CHDATERANGE_YEARS:
169 return rRoot.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue ) ) );
170 default:
171 OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
173 return nValue;
176 void lclConvertTimeValue( const XclImpRoot& rRoot, Any& rAny, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
178 if( bAuto )
179 rAny.clear();
180 else
181 rAny <<= lclGetSerialDay( rRoot, nValue, nTimeUnit );
184 sal_Int32 lclGetApiTimeUnit( sal_uInt16 nTimeUnit )
186 switch( nTimeUnit )
188 case EXC_CHDATERANGE_DAYS: return cssc::TimeUnit::DAY;
189 case EXC_CHDATERANGE_MONTHS: return cssc::TimeUnit::MONTH;
190 case EXC_CHDATERANGE_YEARS: return cssc::TimeUnit::YEAR;
191 default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
193 return cssc::TimeUnit::DAY;
196 void lclConvertTimeInterval( Any& rInterval, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
198 if( bAuto || (nValue == 0) )
199 rInterval.clear();
200 else
201 rInterval <<= cssc::TimeInterval( nValue, lclGetApiTimeUnit( nTimeUnit ) );
204 } // namespace
206 // Common =====================================================================
208 /** Stores global data needed in various classes of the Chart import filter. */
209 struct XclImpChRootData : public XclChRootData
211 XclImpChChart& mrChartData; /// The chart data object.
213 inline explicit XclImpChRootData( XclImpChChart& rChartData ) : mrChartData( rChartData ) {}
216 XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart& rChartData ) :
217 XclImpRoot( rRoot ),
218 mxChData( new XclImpChRootData( rChartData ) )
222 XclImpChRoot::~XclImpChRoot()
226 XclImpChChart& XclImpChRoot::GetChartData() const
228 return mxChData->mrChartData;
231 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
233 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
236 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const
238 return mxChData->mxTypeInfoProv->GetTypeInfoFromRecId( nRecId );
241 const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
243 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
246 Color XclImpChRoot::GetFontAutoColor() const
248 return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT );
251 Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const
253 return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) );
256 Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const
258 const XclImpPalette& rPal = GetPalette();
259 Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) );
260 sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx );
261 return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans );
264 void XclImpChRoot::InitConversion( const Reference<XChartDocument>& xChartDoc, const Rectangle& rChartRect ) const
266 // create formatting object tables
267 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
269 // lock the model to suppress any internal updates
270 if( xChartDoc.is() )
271 xChartDoc->lockControllers();
273 SfxObjectShell* pDocShell = GetDocShell();
274 Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
275 if( pDocShell && xDataRec.is() )
277 // create and register a data provider
278 Reference< XDataProvider > xDataProv(
279 ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY );
280 if( xDataProv.is() )
281 xDataRec->attachDataProvider( xDataProv );
282 // attach the number formatter
283 Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY );
284 if( xNumFmtSupp.is() )
285 xDataRec->attachNumberFormatsSupplier( xNumFmtSupp );
289 void XclImpChRoot::FinishConversion( XclImpDffConverter& rDffConv ) const
291 rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
292 // unlock the model
293 Reference< XModel > xModel( mxChData->mxChartDoc, UNO_QUERY );
294 if( xModel.is() )
295 xModel->unlockControllers();
296 rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
298 mxChData->FinishConversion();
301 Reference< XDataProvider > XclImpChRoot::GetDataProvider() const
303 return mxChData->mxChartDoc->getDataProvider();
306 Reference< XShape > XclImpChRoot::GetTitleShape( const XclChTextKey& rTitleKey ) const
308 return mxChData->GetTitleShape( rTitleKey );
311 sal_Int32 XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX ) const
313 return static_cast< sal_Int32 >( mxChData->mfUnitSizeX * nPosX + mxChData->mnBorderGapX + 0.5 );
316 sal_Int32 XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY ) const
318 return static_cast< sal_Int32 >( mxChData->mfUnitSizeY * nPosY + mxChData->mnBorderGapY + 0.5 );
321 ::com::sun::star::awt::Rectangle XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle& rRect ) const
323 return ::com::sun::star::awt::Rectangle(
324 CalcHmmFromChartX( rRect.mnX ),
325 CalcHmmFromChartY( rRect.mnY ),
326 CalcHmmFromChartX( rRect.mnWidth ),
327 CalcHmmFromChartY( rRect.mnHeight ) );
330 double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX ) const
332 const long nWidth = mxChData->maChartRect.GetWidth();
333 if (!nWidth)
334 throw o3tl::divide_by_zero();
335 return static_cast<double>(nPosX) / nWidth;
338 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY ) const
340 const long nHeight = mxChData->maChartRect.GetHeight();
341 if (!nHeight)
342 throw o3tl::divide_by_zero();
343 return static_cast<double >(nPosY) / nHeight;
346 double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX ) const
348 return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX ) );
351 double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY ) const
353 return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY ) );
356 void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet,
357 const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const
359 GetChartPropSetHelper().WriteLineProperties(
360 rPropSet, *mxChData->mxLineDashTable, rLineFmt, ePropMode );
363 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet,
364 const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const
366 GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode );
369 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet,
370 const XclChEscherFormat& rEscherFmt, const XclChPicFormat* pPicFmt,
371 sal_uInt32 nDffFillType, XclChPropertyMode ePropMode ) const
373 GetChartPropSetHelper().WriteEscherProperties( rPropSet,
374 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable,
375 rEscherFmt, pPicFmt, nDffFillType, ePropMode );
378 void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet,
379 sal_uInt16 nFontIdx, const Color* pFontColor ) const
381 GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor );
384 void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle )
386 sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360;
387 rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot );
390 XclImpChGroupBase::~XclImpChGroupBase()
394 void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm )
396 // read contents of the header record
397 ReadHeaderRecord( rStrm );
399 // only read sub records, if the next record is a CHBEGIN
400 if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN )
402 // read the CHBEGIN record, may be used for special initial processing
403 rStrm.StartNextRecord();
404 ReadSubRecord( rStrm );
406 // read the nested records
407 bool bLoop = true;
408 while( bLoop && rStrm.StartNextRecord() )
410 sal_uInt16 nRecId = rStrm.GetRecId();
411 bLoop = nRecId != EXC_ID_CHEND;
412 // skip unsupported nested blocks
413 if( nRecId == EXC_ID_CHBEGIN )
414 SkipBlock( rStrm );
415 else
416 ReadSubRecord( rStrm );
419 /* Returns with current CHEND record or unchanged stream, if no record
420 group present. In every case another call to StartNextRecord() will go
421 to next record of interest. */
424 void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm )
426 OSL_ENSURE( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
427 // do nothing if current record is not CHBEGIN
428 bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN;
429 while( bLoop && rStrm.StartNextRecord() )
431 sal_uInt16 nRecId = rStrm.GetRecId();
432 bLoop = nRecId != EXC_ID_CHEND;
433 // skip nested record groups
434 if( nRecId == EXC_ID_CHBEGIN )
435 SkipBlock( rStrm );
439 // Frame formatting ===========================================================
441 void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm )
443 maData.mnTLMode = rStrm.ReaduInt16();
444 maData.mnBRMode = rStrm.ReaduInt16();
445 /* According to the spec, the upper 16 bits of all members in the
446 rectangle are unused and may contain garbage. */
447 maData.maRect.mnX = rStrm.ReadInt16(); rStrm.Ignore( 2 );
448 maData.maRect.mnY = rStrm.ReadInt16(); rStrm.Ignore( 2 );
449 maData.maRect.mnWidth = rStrm.ReadInt16(); rStrm.Ignore( 2 );
450 maData.maRect.mnHeight = rStrm.ReadInt16(); rStrm.Ignore( 2 );
453 void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm )
455 rStrm >> maData.maColor;
456 maData.mnPattern = rStrm.ReaduInt16();
457 maData.mnWeight = rStrm.ReadInt16();
458 maData.mnFlags = rStrm.ReaduInt16();
460 const XclImpRoot& rRoot = rStrm.GetRoot();
461 if( rRoot.GetBiff() == EXC_BIFF8 )
462 // BIFF8: index into palette used instead of RGB data
463 maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() );
466 void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot,
467 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
469 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
470 if( IsAuto() )
472 XclChLineFormat aLineFmt;
473 aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ?
474 rRoot.GetSeriesLineAutoColor( nFormatIdx ) :
475 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx );
476 aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
477 aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight;
478 rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode );
480 else
482 rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode );
486 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm )
488 rStrm >> maData.maPattColor >> maData.maBackColor;
489 maData.mnPattern = rStrm.ReaduInt16();
490 maData.mnFlags = rStrm.ReaduInt16();
492 const XclImpRoot& rRoot = rStrm.GetRoot();
493 if( rRoot.GetBiff() == EXC_BIFF8 )
495 // BIFF8: index into palette used instead of RGB data
496 const XclImpPalette& rPal = rRoot.GetPalette();
497 maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() );
498 maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16());
502 void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot,
503 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
505 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
506 if( IsAuto() )
508 XclChAreaFormat aAreaFmt;
509 aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ?
510 rRoot.GetSeriesFillAutoColor( nFormatIdx ) :
511 rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx );
512 aAreaFmt.mnPattern = EXC_PATT_SOLID;
513 rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode );
515 else
517 rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode );
521 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot ) :
522 mnDffFillType( mso_fillSolid )
524 maData.mxItemSet.reset(
525 new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) );
528 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm )
530 // read from stream - CHESCHERFORMAT uses own ID for record continuation
531 XclImpDffPropSet aPropSet( rStrm.GetRoot() );
532 rStrm.ResetRecord( true, rStrm.GetRecId() );
533 rStrm >> aPropSet;
534 // get the data
535 aPropSet.FillToItemSet( *maData.mxItemSet );
536 // get fill type from DFF property set
537 mnDffFillType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid );
540 void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm )
542 switch( rStrm.GetRecId() )
544 case EXC_ID_CHPICFORMAT:
545 maPicFmt.mnBmpMode = rStrm.ReaduInt16();
546 rStrm.Ignore( 2 );
547 maPicFmt.mnFlags = rStrm.ReaduInt16();
548 maPicFmt.mfScale = rStrm.ReadDouble();
549 break;
553 void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot,
554 ScfPropertySet& rPropSet, XclChObjectType eObjType, bool bUsePicFmt ) const
556 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
557 rRoot.ConvertEscherFormat( rPropSet, maData, bUsePicFmt ? &maPicFmt : 0, mnDffFillType, rFmtInfo.mePropMode );
560 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo )
562 if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType )
564 case EXC_CHFRAMETYPE_AUTO:
565 mxLineFmt.reset( new XclImpChLineFormat );
566 if( rFmtInfo.mbIsFrame )
567 mxAreaFmt.reset( new XclImpChAreaFormat );
568 break;
569 case EXC_CHFRAMETYPE_INVISIBLE:
571 XclChLineFormat aLineFmt;
572 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
573 aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
574 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
575 if( rFmtInfo.mbIsFrame )
577 XclChAreaFormat aAreaFmt;
578 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
579 aAreaFmt.mnPattern = EXC_PATT_NONE;
580 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
583 break;
584 default:
585 OSL_FAIL( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
589 void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm )
591 switch( rStrm.GetRecId() )
593 case EXC_ID_CHLINEFORMAT:
594 mxLineFmt.reset( new XclImpChLineFormat );
595 mxLineFmt->ReadChLineFormat( rStrm );
596 break;
597 case EXC_ID_CHAREAFORMAT:
598 mxAreaFmt.reset( new XclImpChAreaFormat );
599 mxAreaFmt->ReadChAreaFormat( rStrm );
600 break;
601 case EXC_ID_CHESCHERFORMAT:
602 mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) );
603 mxEscherFmt->ReadRecordGroup( rStrm );
604 break;
608 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot,
609 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
611 if( mxLineFmt )
612 mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
615 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot,
616 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
618 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
620 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
621 if( mxEscherFmt )
622 mxEscherFmt->Convert( rRoot, rPropSet, eObjType, bUsePicFmt );
623 else if( mxAreaFmt )
624 mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
628 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot,
629 ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
631 ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx );
632 ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx, bUsePicFmt );
635 XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) :
636 XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ),
637 XclImpChRoot( rRoot ),
638 meObjType( eObjType )
642 void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm )
644 maData.mnFormat = rStrm.ReaduInt16();
645 maData.mnFlags = rStrm.ReaduInt16();
648 void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
650 const XclImpPalette& rPal = GetPalette();
652 if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) )
654 // line formatting
655 XclChLineFormat aLineFmt;
656 aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx );
657 switch( rLineData.mnStyle )
659 case EXC_OBJ_LINE_SOLID: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; break;
660 case EXC_OBJ_LINE_DASH: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH; break;
661 case EXC_OBJ_LINE_DOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT; break;
662 case EXC_OBJ_LINE_DASHDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT; break;
663 case EXC_OBJ_LINE_DASHDOTDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT; break;
664 case EXC_OBJ_LINE_MEDTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS; break;
665 case EXC_OBJ_LINE_DARKTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS; break;
666 case EXC_OBJ_LINE_LIGHTTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS; break;
667 case EXC_OBJ_LINE_NONE: aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; break;
668 default: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
670 switch( rLineData.mnWidth )
672 case EXC_OBJ_LINE_HAIR: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; break;
673 case EXC_OBJ_LINE_THIN: aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE; break;
674 case EXC_OBJ_LINE_MEDIUM: aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE; break;
675 case EXC_OBJ_LINE_THICK: aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE; break;
676 default: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
678 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() );
679 mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
682 if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt )
684 // area formatting
685 XclChAreaFormat aAreaFmt;
686 aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx );
687 aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx );
688 aAreaFmt.mnPattern = rFillData.mnPattern;
689 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() );
690 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
694 void XclImpChFrame::Convert( ScfPropertySet& rPropSet, bool bUsePicFmt ) const
696 ConvertFrameBase( GetChRoot(), rPropSet, meObjType, EXC_CHDATAFORMAT_UNKNOWN, bUsePicFmt );
699 // Source links ===============================================================
701 namespace {
703 /** Creates a labeled data sequence object, adds link for series title if present. */
704 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
705 const XclImpChSourceLinkRef& xValueLink, const OUString& rValueRole,
706 const XclImpChSourceLink* pTitleLink = 0 )
708 // create data sequence for values and title
709 Reference< XDataSequence > xValueSeq;
710 if( xValueLink )
711 xValueSeq = xValueLink->CreateDataSequence( rValueRole );
712 Reference< XDataSequence > xTitleSeq;
713 if( pTitleLink )
714 xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL );
716 // create the labeled data sequence, if values or title are present
717 Reference< XLabeledDataSequence > xLabeledSeq;
718 if( xValueSeq.is() || xTitleSeq.is() )
719 xLabeledSeq.set( LabeledDataSequence::create(comphelper::getProcessComponentContext()), UNO_QUERY );
720 if( xLabeledSeq.is() )
722 if( xValueSeq.is() )
723 xLabeledSeq->setValues( xValueSeq );
724 if( xTitleSeq.is() )
725 xLabeledSeq->setLabel( xTitleSeq );
727 return xLabeledSeq;
730 } // namespace
732 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
733 XclImpChRoot( rRoot )
737 XclImpChSourceLink::~XclImpChSourceLink()
741 void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
743 maData.mnDestType = rStrm.ReaduInt8();
744 maData.mnLinkType = rStrm.ReaduInt8();
745 maData.mnFlags = rStrm.ReaduInt16();
746 maData.mnNumFmtIdx = rStrm.ReaduInt16();
748 mxTokenArray.reset();
749 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
751 // read token array
752 XclTokenArray aXclTokArr;
753 rStrm >> aXclTokArr;
755 // convert BIFF formula tokens to Calc token array
756 if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) )
757 mxTokenArray.reset( pTokens->Clone() );
760 // try to read a following CHSTRING record
761 if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() )
763 mxString.reset( new XclImpString );
764 rStrm.Ignore( 2 );
765 mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
769 void XclImpChSourceLink::SetString( const OUString& rString )
771 if( !mxString )
772 mxString.reset( new XclImpString );
773 mxString->SetText( rString );
776 void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
778 if( mxString )
779 mxString->SetFormats( rFormats );
782 sal_uInt16 XclImpChSourceLink::GetCellCount() const
784 sal_uInt32 nCellCount = 0;
785 if( mxTokenArray )
787 mxTokenArray->Reset();
788 for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() )
790 switch( pToken->GetType() )
792 case ::formula::svSingleRef:
793 case ::formula::svExternalSingleRef:
794 // single cell
795 ++nCellCount;
796 break;
797 case ::formula::svDoubleRef:
798 case ::formula::svExternalDoubleRef:
800 // cell range
801 const ScComplexRefData& rComplexRef = *pToken->GetDoubleRef();
802 ScAddress aAbs1 = rComplexRef.Ref1.toAbs(ScAddress());
803 ScAddress aAbs2 = rComplexRef.Ref2.toAbs(ScAddress());
804 sal_uInt32 nTabs = static_cast<sal_uInt32>(aAbs2.Tab() - aAbs1.Tab() + 1);
805 sal_uInt32 nCols = static_cast<sal_uInt32>(aAbs2.Col() - aAbs1.Col() + 1);
806 sal_uInt32 nRows = static_cast<sal_uInt32>(aAbs2.Row() - aAbs1.Row() + 1);
807 nCellCount += nCols * nRows * nTabs;
809 break;
810 default: ;
814 return limit_cast< sal_uInt16 >( nCellCount );
817 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
819 bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
820 sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND;
821 OUString aPropName = bPercent ? OUString( EXC_CHPROP_PERCENTAGENUMFMT ) : OUString( EXC_CHPROP_NUMBERFORMAT );
822 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
823 rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) );
824 else
825 // restore 'link to source' at data point (series may contain manual number format)
826 rPropSet.SetAnyProperty( aPropName, Any() );
829 Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const
831 Reference< XDataSequence > xDataSeq;
832 Reference< XDataProvider > xDataProv = GetDataProvider();
833 if( xDataProv.is() )
835 if ( mxTokenArray )
837 ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray );
838 aComp.SetGrammar(GetDoc().GetGrammar());
839 OUStringBuffer aRangeRep;
840 aComp.CreateStringFromTokenArray( aRangeRep );
843 xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() );
844 // set sequence role
845 ScfPropertySet aSeqProp( xDataSeq );
846 aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
848 catch( Exception& )
850 // OSL_FAIL( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
853 else if( rRole == EXC_CHPROP_ROLE_LABEL && mxString && !mxString->GetText().isEmpty() )
857 OUString aString("\"");
858 xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aString + mxString->GetText() + aString );
859 // set sequence role
860 ScfPropertySet aSeqProp( xDataSeq );
861 aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
863 catch( Exception& ) { }
866 return xDataSeq;
869 Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence(
870 const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const
872 ::std::vector< Reference< XFormattedString > > aStringVec;
873 if( mxString )
875 for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt )
877 Reference< css::chart2::XFormattedString2 > xFmtStr = css::chart2::FormattedString::create( comphelper::getProcessComponentContext() );
878 // set text data
879 xFmtStr->setString( aIt.GetPortionText() );
881 // set font formatting and font color
882 ScfPropertySet aStringProp( xFmtStr );
883 sal_uInt16 nFontIdx = aIt.GetPortionFont();
884 if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) )
885 // leading unformatted portion - use passed font settings
886 rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor );
887 else
888 rRoot.ConvertFont( aStringProp, nFontIdx );
890 // add string to vector of strings
891 aStringVec.push_back( xFmtStr );
894 return ScfApiHelper::VectorToSequence( aStringVec );
897 void XclImpChSourceLink::FillSourceLink( ::std::vector< ScTokenRef >& rTokens ) const
899 if( !mxTokenArray )
900 // no links to fill.
901 return;
903 mxTokenArray->Reset();
904 for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next())
906 ScTokenRef pToken(p->Clone());
907 if (ScRefTokenHelper::isRef(pToken))
908 // This is a reference token. Store it.
909 ScRefTokenHelper::join(rTokens, pToken, ScAddress());
913 // Text =======================================================================
915 XclImpChFontBase::~XclImpChFontBase()
919 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
921 Color aFontColor = GetFontColor();
922 rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor );
925 void XclImpChFontBase::ConvertRotationBase( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
927 XclChPropSetHelper::WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked );
930 XclImpChFont::XclImpChFont() :
931 mnFontIdx( EXC_FONT_NOTFOUND )
935 void XclImpChFont::ReadChFont( XclImpStream& rStrm )
937 mnFontIdx = rStrm.ReaduInt16();
940 XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) :
941 XclImpChRoot( rRoot )
945 void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm )
947 maData.mnHAlign = rStrm.ReaduInt8();
948 maData.mnVAlign = rStrm.ReaduInt8();
949 maData.mnBackMode = rStrm.ReaduInt16();
950 rStrm >> maData.maTextColor
951 >> maData.maRect;
952 maData.mnFlags = rStrm.ReaduInt16();
954 if( GetBiff() == EXC_BIFF8 )
956 // BIFF8: index into palette used instead of RGB data
957 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
958 // placement and rotation
959 maData.mnFlags2 = rStrm.ReaduInt16();
960 maData.mnRotation = rStrm.ReaduInt16();
962 else
964 // BIFF2-BIFF7: get rotation from text orientation
965 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 );
966 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
970 void XclImpChText::ReadSubRecord( XclImpStream& rStrm )
972 switch( rStrm.GetRecId() )
974 case EXC_ID_CHFRAMEPOS:
975 mxFramePos.reset( new XclImpChFramePos );
976 mxFramePos->ReadChFramePos( rStrm );
977 break;
978 case EXC_ID_CHFONT:
979 mxFont.reset( new XclImpChFont );
980 mxFont->ReadChFont( rStrm );
981 break;
982 case EXC_ID_CHFORMATRUNS:
983 if( GetBiff() == EXC_BIFF8 )
984 XclImpString::ReadFormats( rStrm, maFormats );
985 break;
986 case EXC_ID_CHSOURCELINK:
987 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
988 mxSrcLink->ReadChSourceLink( rStrm );
989 break;
990 case EXC_ID_CHFRAME:
991 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) );
992 mxFrame->ReadRecordGroup( rStrm );
993 break;
994 case EXC_ID_CHOBJECTLINK:
995 maObjLink.mnTarget = rStrm.ReaduInt16();
996 maObjLink.maPointPos.mnSeriesIdx = rStrm.ReaduInt16();
997 maObjLink.maPointPos.mnPointIdx = rStrm.ReaduInt16();
998 break;
999 case EXC_ID_CHFRLABELPROPS:
1000 ReadChFrLabelProps( rStrm );
1001 break;
1002 case EXC_ID_CHEND:
1003 if( mxSrcLink && !maFormats.empty() )
1004 mxSrcLink->SetTextFormats( maFormats );
1005 break;
1009 sal_uInt16 XclImpChText::GetFontIndex() const
1011 return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
1014 Color XclImpChText::GetFontColor() const
1016 return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
1019 sal_uInt16 XclImpChText::GetRotation() const
1021 return maData.mnRotation;
1024 void XclImpChText::SetString( const OUString& rString )
1026 if( !mxSrcLink )
1027 mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
1028 mxSrcLink->SetString( rString );
1031 void XclImpChText::UpdateText( const XclImpChText* pParentText )
1033 if( pParentText )
1035 // update missing members
1036 if( !mxFrame )
1037 mxFrame = pParentText->mxFrame;
1038 if( !mxFont )
1040 mxFont = pParentText->mxFont;
1041 // text color is taken from CHTEXT record, not from font in CHFONT
1042 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) );
1043 maData.maTextColor = pParentText->maData.maTextColor;
1048 void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent )
1050 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bCateg );
1051 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bValue );
1052 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bPercent );
1053 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent );
1054 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bCateg && !bValue && !bPercent );
1057 void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const
1059 ConvertFontBase( GetChRoot(), rPropSet );
1062 void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
1064 ConvertRotationBase( rPropSet, bSupportsStacked );
1067 void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const
1069 if( mxFrame )
1070 mxFrame->Convert( rPropSet );
1073 void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
1075 if( mxSrcLink )
1076 mxSrcLink->ConvertNumFmt( rPropSet, bPercent );
1079 void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const
1081 // existing CHFRLABELPROPS record wins over flags from CHTEXT
1082 sal_uInt16 nShowFlags = mxLabelProps ? mxLabelProps->mnFlags : maData.mnFlags;
1083 sal_uInt16 SHOWANYCATEG = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG);
1084 sal_uInt16 SHOWANYVALUE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE;
1085 sal_uInt16 SHOWANYPERCENT = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC);
1086 sal_uInt16 SHOWANYBUBBLE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE;
1088 // get raw flags for label values
1089 bool bShowNone = IsDeleted();
1090 bool bShowCateg = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG );
1091 bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT );
1092 bool bShowValue = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE );
1093 bool bShowBubble = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE );
1095 // adjust to Chart2 behaviour
1096 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
1097 bShowValue = bShowBubble; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1099 // other flags
1100 bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1101 bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL );
1103 // create API struct for label values, set API label separator
1104 cssc2::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
1105 rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel );
1106 OUString aSep = mxLabelProps ? mxLabelProps->maSeparator : OUString('\n');
1107 if( aSep.isEmpty() )
1108 aSep = "; ";
1109 rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep );
1111 // text properties of attached label
1112 if( bShowAny )
1114 ConvertFont( rPropSet );
1115 ConvertRotation( rPropSet, false );
1116 // label placement
1117 using namespace cssc::DataLabelPlacement;
1118 sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos;
1119 switch( ::extract_value< sal_uInt16 >( maData.mnFlags2, 0, 4 ) )
1121 case EXC_CHTEXT_POS_DEFAULT: nPlacement = rTypeInfo.mnDefaultLabelPos; break;
1122 case EXC_CHTEXT_POS_OUTSIDE: nPlacement = OUTSIDE; break;
1123 case EXC_CHTEXT_POS_INSIDE: nPlacement = INSIDE; break;
1124 case EXC_CHTEXT_POS_CENTER: nPlacement = CENTER; break;
1125 case EXC_CHTEXT_POS_AXIS: nPlacement = NEAR_ORIGIN; break;
1126 case EXC_CHTEXT_POS_ABOVE: nPlacement = TOP; break;
1127 case EXC_CHTEXT_POS_BELOW: nPlacement = BOTTOM; break;
1128 case EXC_CHTEXT_POS_LEFT: nPlacement = LEFT; break;
1129 case EXC_CHTEXT_POS_RIGHT: nPlacement = RIGHT; break;
1130 case EXC_CHTEXT_POS_AUTO: nPlacement = AVOID_OVERLAP; break;
1132 rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement );
1133 // label number format (percentage format wins over value format)
1134 if( bShowPercent || bShowValue )
1135 ConvertNumFmt( rPropSet, bShowPercent );
1139 Reference< XTitle > XclImpChText::CreateTitle() const
1141 Reference< XTitle > xTitle;
1142 if( mxSrcLink && mxSrcLink->HasString() )
1144 // create the formatted strings
1145 Sequence< Reference< XFormattedString > > aStringSeq(
1146 mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1147 if( aStringSeq.hasElements() )
1149 // create the title object
1150 xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY );
1151 if( xTitle.is() )
1153 // set the formatted strings
1154 xTitle->setText( aStringSeq );
1155 // more title formatting properties
1156 ScfPropertySet aTitleProp( xTitle );
1157 ConvertFrame( aTitleProp );
1158 ConvertRotation( aTitleProp, true );
1162 return xTitle;
1165 void XclImpChText::ConvertTitlePosition( const XclChTextKey& rTitleKey ) const
1167 if( !mxFramePos ) return;
1169 const XclChFramePos& rPosData = mxFramePos->GetFramePosData();
1170 OSL_ENSURE( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rPosData.mnBRMode == EXC_CHFRAMEPOS_PARENT),
1171 "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1173 /* Check if title is moved manually. To get the actual position of the
1174 title, we do some kind of hack and use the values from the CHTEXT
1175 record, effectively ignoring the contents of the CHFRAMEPOS record
1176 which contains the position relative to the default title position
1177 (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1178 Especially when it comes to axis titles, things would become very
1179 complicated here, because the relative title position is stored in a
1180 measurement unit that is dependent on the size of the inner plot area,
1181 the interpretation of the X and Y coordinate is dependent on the
1182 direction of the axis, and in 3D charts, and the title default
1183 positions are dependent on the 3D view settings (rotation, elevation,
1184 and perspective). Thus, it is easier to assume that the creator has
1185 written out the correct absolute position and size of the title in the
1186 CHTEXT record. This is assured by checking that the shape size stored
1187 in the CHTEXT record is non-zero. */
1188 if( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) &&
1189 ((rPosData.maRect.mnX != 0) || (rPosData.maRect.mnY != 0)) &&
1190 (maData.maRect.mnWidth > 0) && (maData.maRect.mnHeight > 0) ) try
1192 Reference< XShape > xTitleShape( GetTitleShape( rTitleKey ), UNO_SET_THROW );
1193 // the call to XShape.getSize() may recalc the chart view
1194 ::com::sun::star::awt::Size aTitleSize = xTitleShape->getSize();
1195 // rotated titles need special handling...
1196 sal_Int32 nScRot = XclTools::GetScRotation( GetRotation(), 0 );
1197 double fRad = nScRot * F_PI18000;
1198 double fSin = fabs( sin( fRad ) );
1199 double fCos = fabs( cos( fRad ) );
1200 ::com::sun::star::awt::Size aBoundSize(
1201 static_cast< sal_Int32 >( fCos * aTitleSize.Width + fSin * aTitleSize.Height + 0.5 ),
1202 static_cast< sal_Int32 >( fSin * aTitleSize.Width + fCos * aTitleSize.Height + 0.5 ) );
1203 // calculate the title position from the values in the CHTEXT record
1204 ::com::sun::star::awt::Point aTitlePos(
1205 CalcHmmFromChartX( maData.maRect.mnX ),
1206 CalcHmmFromChartY( maData.maRect.mnY ) );
1207 // add part of height to X direction, if title is rotated down (clockwise)
1208 if( nScRot > 18000 )
1209 aTitlePos.X += static_cast< sal_Int32 >( fSin * aTitleSize.Height + 0.5 );
1210 // add part of width to Y direction, if title is rotated up (counterclockwise)
1211 else if( nScRot > 0 )
1212 aTitlePos.Y += static_cast< sal_Int32 >( fSin * aTitleSize.Width + 0.5 );
1213 // set the resulting position at the title shape
1214 xTitleShape->setPosition( aTitlePos );
1216 catch( Exception& )
1221 void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm )
1223 if( GetBiff() == EXC_BIFF8 )
1225 mxLabelProps.reset( new XclChFrLabelProps );
1226 sal_uInt16 nSepLen;
1227 rStrm.Ignore( 12 );
1228 mxLabelProps->mnFlags = rStrm.ReaduInt16();
1229 nSepLen = rStrm.ReaduInt16();
1230 if( nSepLen > 0 )
1231 mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen );
1235 namespace {
1237 void lclUpdateText( XclImpChTextRef& rxText, const XclImpChText* xDefText )
1239 if( rxText )
1240 rxText->UpdateText( xDefText );
1241 else
1243 XclImpChTextRef xNew(new XclImpChText(*xDefText));
1244 rxText = xNew;
1248 void lclFinalizeTitle( XclImpChTextRef& rxTitle, const XclImpChText* pDefText, const OUString& rAutoTitle )
1250 /* Do not update a title, if it is not visible (if rxTitle is null).
1251 Existing reference indicates enabled title. */
1252 if( rxTitle )
1254 if( !rxTitle->HasString() )
1255 rxTitle->SetString( rAutoTitle );
1256 if( rxTitle->HasString() )
1257 rxTitle->UpdateText(pDefText);
1258 else
1259 rxTitle.reset();
1263 } // namespace
1265 // Data series ================================================================
1267 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm )
1269 rStrm >> maData.maLineColor >> maData.maFillColor;
1270 maData.mnMarkerType = rStrm.ReaduInt16();
1271 maData.mnFlags = rStrm.ReaduInt16();
1273 const XclImpRoot& rRoot = rStrm.GetRoot();
1274 if( rRoot.GetBiff() == EXC_BIFF8 )
1276 // BIFF8: index into palette used instead of RGB data
1277 const XclImpPalette& rPal = rRoot.GetPalette();
1278 maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() );
1279 maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() );
1280 // marker size
1281 maData.mnMarkerSize = rStrm.ReaduInt32();
1285 void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot,
1286 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const
1288 if( IsAuto() )
1290 XclChMarkerFormat aMarkerFmt;
1291 // line and fill color of the symbol are equal to series line color
1292 //TODO: Excel sets no fill color for specific symbols (e.g. cross)
1293 aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx );
1294 switch( nLineWeight )
1296 case EXC_CHLINEFORMAT_HAIR: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE; break;
1297 case EXC_CHLINEFORMAT_SINGLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; break;
1298 case EXC_CHLINEFORMAT_DOUBLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; break;
1299 case EXC_CHLINEFORMAT_TRIPLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE; break;
1300 default: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;
1302 aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
1303 XclChPropSetHelper::WriteMarkerProperties( rPropSet, aMarkerFmt );
1305 else
1307 XclChPropSetHelper::WriteMarkerProperties( rPropSet, maData );
1311 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot,
1312 ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
1314 Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor;
1315 rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor );
1318 XclImpChPieFormat::XclImpChPieFormat() :
1319 mnPieDist( 0 )
1323 void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm )
1325 mnPieDist = rStrm.ReaduInt16();
1328 void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const
1330 double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 );
1331 rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist );
1334 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1335 mnFlags( 0 )
1339 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm )
1341 mnFlags = rStrm.ReaduInt16();
1344 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm )
1346 maData.mnBase = rStrm.ReaduInt8();
1347 maData.mnTop = rStrm.ReaduInt8();
1350 void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const
1352 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1353 sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ?
1354 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) :
1355 ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE);
1356 rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType );
1359 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) :
1360 XclImpChRoot( rRoot ),
1361 mnFlags( 0 )
1365 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm )
1367 mnFlags = rStrm.ReaduInt16();
1370 XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( const XclImpChText* pParent ) const
1372 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE;
1373 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC;
1374 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC;
1376 XclImpChTextRef xLabel( pParent ? new XclImpChText( *pParent ) : new XclImpChText( GetChRoot() ) );
1377 xLabel->UpdateDataLabel(
1378 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ),
1379 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ),
1380 ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) );
1381 return xLabel;
1384 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) :
1385 XclImpChRoot( rRoot )
1389 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm )
1391 maData.maPointPos.mnPointIdx = rStrm.ReaduInt16();
1392 maData.maPointPos.mnSeriesIdx = rStrm.ReaduInt16();
1393 maData.mnFormatIdx = rStrm.ReaduInt16();
1394 maData.mnFlags = rStrm.ReaduInt16();
1397 void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm )
1399 switch( rStrm.GetRecId() )
1401 case EXC_ID_CHMARKERFORMAT:
1402 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1403 mxMarkerFmt->ReadChMarkerFormat( rStrm );
1404 break;
1405 case EXC_ID_CHPIEFORMAT:
1406 mxPieFmt.reset( new XclImpChPieFormat );
1407 mxPieFmt->ReadChPieFormat( rStrm );
1408 break;
1409 case EXC_ID_CHSERIESFORMAT:
1410 mxSeriesFmt.reset( new XclImpChSeriesFormat );
1411 mxSeriesFmt->ReadChSeriesFormat( rStrm );
1412 break;
1413 case EXC_ID_CH3DDATAFORMAT:
1414 mx3dDataFmt.reset( new XclImpCh3dDataFormat );
1415 mx3dDataFmt->ReadCh3dDataFormat( rStrm );
1416 break;
1417 case EXC_ID_CHATTACHEDLABEL:
1418 mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) );
1419 mxAttLabel->ReadChAttachedLabel( rStrm );
1420 break;
1421 default:
1422 XclImpChFrameBase::ReadSubRecord( rStrm );
1426 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx )
1428 maData.maPointPos = rPointPos;
1429 maData.mnFormatIdx = nFormatIdx;
1432 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo )
1434 // remove formats not used for the current chart type
1435 RemoveUnusedFormats( rTypeInfo );
1438 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt )
1440 // update missing formats from passed chart type group format
1441 if( pGroupFmt )
1443 if( !mxLineFmt )
1444 mxLineFmt = pGroupFmt->mxLineFmt;
1445 if( !mxAreaFmt && !mxEscherFmt )
1447 mxAreaFmt = pGroupFmt->mxAreaFmt;
1448 mxEscherFmt = pGroupFmt->mxEscherFmt;
1450 if( !mxMarkerFmt )
1451 mxMarkerFmt = pGroupFmt->mxMarkerFmt;
1452 if( !mxPieFmt )
1453 mxPieFmt = pGroupFmt->mxPieFmt;
1454 if( !mxSeriesFmt )
1455 mxSeriesFmt = pGroupFmt->mxSeriesFmt;
1456 if( !mx3dDataFmt )
1457 mx3dDataFmt = pGroupFmt->mx3dDataFmt;
1458 if( !mxAttLabel )
1459 mxAttLabel = pGroupFmt->mxAttLabel;
1462 /* Create missing but required formats. Existing line, area, and marker
1463 format objects are needed to create automatic series formatting. */
1464 if( !mxLineFmt )
1465 mxLineFmt.reset( new XclImpChLineFormat );
1466 if( !mxAreaFmt && !mxEscherFmt )
1467 mxAreaFmt.reset( new XclImpChAreaFormat );
1468 if( !mxMarkerFmt )
1469 mxMarkerFmt.reset( new XclImpChMarkerFormat );
1471 // remove formats not used for the current chart type
1472 RemoveUnusedFormats( rTypeInfo );
1473 // update data label
1474 UpdateDataLabel( pGroupFmt );
1477 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt )
1479 // remove formats if they are automatic in this and in the passed series format
1480 if( pSeriesFmt )
1482 if( IsAutoLine() && pSeriesFmt->IsAutoLine() )
1483 mxLineFmt.reset();
1484 if( IsAutoArea() && pSeriesFmt->IsAutoArea() )
1485 mxAreaFmt.reset();
1486 if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() )
1487 mxMarkerFmt.reset();
1488 mxSeriesFmt.reset();
1491 // Excel ignores 3D bar format for single data points
1492 mx3dDataFmt.reset();
1493 // remove point line formats for linear chart types, TODO: implement in OOChart
1494 if( !rTypeInfo.IsSeriesFrameFormat() )
1495 mxLineFmt.reset();
1497 // remove formats not used for the current chart type
1498 RemoveUnusedFormats( rTypeInfo );
1499 // update data label
1500 UpdateDataLabel( pSeriesFmt );
1503 void XclImpChDataFormat::UpdateTrendLineFormat()
1505 if( !mxLineFmt )
1506 mxLineFmt.reset( new XclImpChLineFormat );
1507 mxAreaFmt.reset();
1508 mxEscherFmt.reset();
1509 mxMarkerFmt.reset();
1510 mxPieFmt.reset();
1511 mxSeriesFmt.reset();
1512 mx3dDataFmt.reset();
1513 mxAttLabel.reset();
1514 // update data label
1515 UpdateDataLabel( 0 );
1518 void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const
1520 /* Line and area format.
1521 #i71810# If the data points are filled with bitmaps, textures, or
1522 patterns, then only bar charts will use the CHPICFORMAT record to
1523 determine stacking/stretching mode. All other chart types ignore this
1524 record and always use the property 'fill-type' from the DFF property
1525 set (stretched for bitmaps, and stacked for textures and patterns). */
1526 bool bUsePicFmt = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR;
1527 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx, bUsePicFmt );
1529 #if EXC_CHART2_3DBAR_HAIRLINES_ONLY
1530 // #i83151# only hair lines in 3D charts with filled data points
1531 if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt && mxLineFmt->HasLine() )
1532 rPropSet.SetProperty< sal_Int32 >( "BorderWidth", 0 );
1533 #endif
1535 // other formatting
1536 if( mxMarkerFmt )
1537 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() );
1538 if( mxPieFmt )
1539 mxPieFmt->Convert( rPropSet );
1540 if( mx3dDataFmt )
1541 mx3dDataFmt->Convert( rPropSet );
1542 if( mxLabel )
1543 mxLabel->ConvertDataLabel( rPropSet, rTypeInfo );
1545 // 3D settings
1546 rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 );
1548 /* Special case: set marker color as line color, if series line is not
1549 visible. This makes the color visible in the marker area.
1550 TODO: remove this if OOChart supports own colors in markers. */
1551 if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt )
1552 mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx );
1555 void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
1557 ConvertLineBase( GetChRoot(), rPropSet, eObjType );
1560 void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
1562 ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx, bUsePicFmt );
1565 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo )
1567 // data point marker only in linear 2D charts
1568 if( rTypeInfo.IsSeriesFrameFormat() )
1569 mxMarkerFmt.reset();
1570 // pie format only in pie/donut charts
1571 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
1572 mxPieFmt.reset();
1573 // 3D format only in 3D bar charts
1574 if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
1575 mx3dDataFmt.reset();
1578 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt )
1580 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1581 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1582 group, the contents of the CHATTACHEDLABEL record are used. In this
1583 case a new CHTEXT group is created and filled with the settings from
1584 the CHATTACHEDLABEL record. */
1585 const XclImpChText* pDefText = NULL;
1586 if (pParentFmt)
1587 pDefText = pParentFmt->GetDataLabel();
1588 if (!pDefText)
1589 pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL );
1590 if (mxLabel)
1591 mxLabel->UpdateText(pDefText);
1592 else if (mxAttLabel)
1593 mxLabel = mxAttLabel->CreateDataLabel( pDefText );
1596 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) :
1597 XclImpChRoot( rRoot )
1601 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm )
1603 maData.mnLineType = rStrm.ReaduInt8();
1604 maData.mnOrder = rStrm.ReaduInt8();
1605 maData.mfIntercept = rStrm.ReadDouble();
1606 maData.mnShowEquation = rStrm.ReaduInt8();
1607 maData.mnShowRSquared = rStrm.ReaduInt8();
1608 maData.mfForecastFor = rStrm.ReadDouble();
1609 maData.mfForecastBack = rStrm.ReadDouble();
1612 Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const
1614 // trend line type
1615 Reference< XRegressionCurve > xRegCurve;
1616 switch( maData.mnLineType )
1618 case EXC_CHSERTREND_POLYNOMIAL:
1619 if( maData.mnOrder == 1 )
1621 xRegCurve = LinearRegressionCurve::create( comphelper::getProcessComponentContext() );
1622 } else {
1623 xRegCurve = PolynomialRegressionCurve::create( comphelper::getProcessComponentContext() );
1625 break;
1626 case EXC_CHSERTREND_EXPONENTIAL:
1627 xRegCurve = ExponentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1628 break;
1629 case EXC_CHSERTREND_LOGARITHMIC:
1630 xRegCurve = LogarithmicRegressionCurve::create( comphelper::getProcessComponentContext() );
1631 break;
1632 case EXC_CHSERTREND_POWER:
1633 xRegCurve = PotentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1634 break;
1635 case EXC_CHSERTREND_MOVING_AVG:
1636 xRegCurve = MovingAverageRegressionCurve::create( comphelper::getProcessComponentContext() );
1637 break;
1640 // trend line formatting
1641 if( xRegCurve.is() && mxDataFmt )
1643 ScfPropertySet aPropSet( xRegCurve );
1644 mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE );
1646 aPropSet.SetProperty(EXC_CHPROP_CURVENAME, maTrendLineName);
1647 aPropSet.SetProperty(EXC_CHPROP_POLYNOMIAL_DEGREE, static_cast<sal_Int32> (maData.mnOrder) );
1648 aPropSet.SetProperty(EXC_CHPROP_MOVING_AVERAGE_PERIOD, static_cast<sal_Int32> (maData.mnOrder) );
1649 aPropSet.SetProperty(EXC_CHPROP_EXTRAPOLATE_FORWARD, maData.mfForecastFor);
1650 aPropSet.SetProperty(EXC_CHPROP_EXTRAPOLATE_BACKWARD, maData.mfForecastBack);
1652 bool bForceIntercept = !rtl::math::isNan(maData.mfIntercept);
1653 aPropSet.SetProperty(EXC_CHPROP_FORCE_INTERCEPT, bForceIntercept);
1654 if (bForceIntercept)
1656 aPropSet.SetProperty(EXC_CHPROP_INTERCEPT_VALUE, maData.mfIntercept);
1659 // #i83100# show equation and correlation coefficient
1660 ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() );
1661 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 );
1662 aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 );
1664 // #i83100# formatting of the equation text box
1665 if (const XclImpChText* pLabel = mxDataFmt->GetDataLabel())
1667 pLabel->ConvertFont( aLabelProp );
1668 pLabel->ConvertFrame( aLabelProp );
1669 pLabel->ConvertNumFmt( aLabelProp, false );
1673 // missing features
1674 // #i20819# polynomial trend lines
1675 // #i66819# moving average trend lines
1676 // #i5085# manual trend line size
1677 // #i34093# manual crossing point
1679 return xRegCurve;
1682 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) :
1683 XclImpChRoot( rRoot )
1687 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm )
1689 maData.mnBarType = rStrm.ReaduInt8();
1690 maData.mnSourceType = rStrm.ReaduInt8();
1691 maData.mnLineEnd = rStrm.ReaduInt8();
1692 rStrm.Ignore( 1 );
1693 maData.mfValue = rStrm.ReadDouble();
1694 maData.mnValueCount = rStrm.ReaduInt16();
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 XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1785 XclImpChRoot( rRoot ),
1786 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1787 mnSeriesIdx( nSeriesIdx ),
1788 mnParentIdx( EXC_CHSERIES_INVALID )
1792 void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm )
1794 maData.mnCategType = rStrm.ReaduInt16();
1795 maData.mnValueType = rStrm.ReaduInt16();
1796 maData.mnCategCount = rStrm.ReaduInt16();
1797 maData.mnValueCount = rStrm.ReaduInt16();
1798 if( GetBiff() == EXC_BIFF8 )
1800 maData.mnBubbleType = rStrm.ReaduInt16();
1801 maData.mnBubbleCount = rStrm.ReaduInt16();
1805 void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm )
1807 switch( rStrm.GetRecId() )
1809 case EXC_ID_CHSOURCELINK:
1810 ReadChSourceLink( rStrm );
1811 break;
1812 case EXC_ID_CHDATAFORMAT:
1813 ReadChDataFormat( rStrm );
1814 break;
1815 case EXC_ID_CHSERGROUP:
1816 mnGroupIdx = rStrm.ReaduInt16();
1817 break;
1818 case EXC_ID_CHSERPARENT:
1819 ReadChSerParent( rStrm );
1820 break;
1821 case EXC_ID_CHSERTRENDLINE:
1822 ReadChSerTrendLine( rStrm );
1823 break;
1824 case EXC_ID_CHSERERRORBAR:
1825 ReadChSerErrorBar( rStrm );
1826 break;
1830 void XclImpChSeries::SetDataFormat( const XclImpChDataFormatRef& xDataFmt )
1832 if (!xDataFmt)
1833 return;
1835 sal_uInt16 nPointIdx = xDataFmt->GetPointPos().mnPointIdx;
1836 if (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS)
1838 if (mxSeriesFmt)
1839 // Don't overwrite the existing format.
1840 return;
1842 mxSeriesFmt = xDataFmt;
1843 if (HasParentSeries())
1844 return;
1846 XclImpChTypeGroupRef pTypeGroup = GetChartData().GetTypeGroup(mnGroupIdx);
1847 if (pTypeGroup)
1848 pTypeGroup->SetUsedFormatIndex(xDataFmt->GetFormatIdx());
1850 return;
1853 if (nPointIdx >= EXC_CHDATAFORMAT_MAXPOINTCOUNT)
1854 // Above the max point count. Bail out.
1855 return;
1857 XclImpChDataFormatMap::iterator itr = maPointFmts.lower_bound(nPointIdx);
1858 if (itr == maPointFmts.end() || maPointFmts.key_comp()(nPointIdx, itr->first))
1860 // No object exists at this point index position. Insert it.
1861 itr = maPointFmts.insert(itr, XclImpChDataFormatMap::value_type(nPointIdx, xDataFmt));
1865 void XclImpChSeries::SetDataLabel( const XclImpChTextRef& xLabel )
1867 if (!xLabel)
1868 return;
1870 sal_uInt16 nPointIdx = xLabel->GetPointPos().mnPointIdx;
1871 if ((nPointIdx != EXC_CHDATAFORMAT_ALLPOINTS) && (nPointIdx >= EXC_CHDATAFORMAT_MAXPOINTCOUNT))
1872 // Above the maximum allowed data points. Bail out.
1873 return;
1875 XclImpChTextMap::iterator itr = maLabels.lower_bound(nPointIdx);
1876 if (itr == maLabels.end() || maLabels.key_comp()(nPointIdx, itr->first))
1878 // No object exists at this point index position. Insert it.
1879 itr = maLabels.insert(itr, XclImpChTextMap::value_type(nPointIdx, xLabel));
1883 void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries )
1885 OSL_ENSURE( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1887 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1888 these are properties of the parent series. This function adds the
1889 settings of the passed series to this series. */
1890 maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() );
1891 maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() );
1894 void XclImpChSeries::FinalizeDataFormats()
1896 if( HasParentSeries() )
1898 // *** series is a child series, e.g. trend line or error bar ***
1900 // create missing series format
1901 if( !mxSeriesFmt )
1902 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 );
1904 if( mxSeriesFmt )
1906 // #i83100# set text label format, e.g. for trend line equations
1907 XclImpChTextRef xLabel;
1908 XclImpChTextMap::iterator itr = maLabels.find(EXC_CHDATAFORMAT_ALLPOINTS);
1909 if (itr != maLabels.end())
1910 xLabel = itr->second;
1911 mxSeriesFmt->SetDataLabel(xLabel);
1912 // create missing automatic formats
1913 mxSeriesFmt->UpdateTrendLineFormat();
1916 // copy series formatting to child objects
1917 for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt )
1919 (*aLIt)->SetDataFormat(mxSeriesFmt);
1920 if (mxTitleLink->HasString())
1922 (*aLIt)->SetTrendlineName(mxTitleLink->GetString());
1925 for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt )
1927 aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt );
1930 else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1932 // *** series is a regular data series ***
1934 // create missing series format
1935 if( !mxSeriesFmt )
1937 // #i51639# use a new unused format index to create series default format
1938 sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex();
1939 mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx );
1942 // set text labels to data formats
1943 for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt )
1945 sal_uInt16 nPointIdx = aTIt->first;
1946 if (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS)
1948 if (!mxSeriesFmt)
1949 mxSeriesFmt = CreateDataFormat(nPointIdx, EXC_CHDATAFORMAT_DEFAULT);
1950 mxSeriesFmt->SetDataLabel(aTIt->second);
1952 else if (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT)
1954 XclImpChDataFormatRef p;
1955 XclImpChDataFormatMap::iterator itr = maPointFmts.lower_bound(nPointIdx);
1956 if (itr == maPointFmts.end() || maPointFmts.key_comp()(nPointIdx, itr->first))
1958 // No object exists at this point index position. Insert
1959 // a new one.
1960 p = CreateDataFormat(nPointIdx, EXC_CHDATAFORMAT_DEFAULT);
1961 itr = maPointFmts.insert(
1962 itr, XclImpChDataFormatMap::value_type(nPointIdx, p));
1964 else
1965 p = itr->second;
1966 p->SetDataLabel(aTIt->second);
1970 // update series format (copy missing formatting from group default format)
1971 if( mxSeriesFmt )
1972 mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() );
1974 // update data point formats (removes unchanged automatic formatting)
1975 for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt )
1976 aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() );
1980 namespace {
1982 /** Returns the property set of the specified data point. */
1983 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx )
1985 ScfPropertySet aPropSet;
1988 aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) );
1990 catch( Exception& )
1992 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1994 return aPropSet;
1997 } // namespace
1999 Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const
2001 return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() );
2004 Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const
2006 return lclCreateLabeledDataSequence( mxCategLink, rCategRole );
2009 Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const
2011 Reference< XDataSeries > xDataSeries;
2012 if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
2014 const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo();
2016 // create the data series object
2017 xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2019 // attach data and title sequences to series
2020 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2021 if( xDataSink.is() )
2023 // create vector of all value sequences
2024 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2025 // add Y values
2026 Reference< XLabeledDataSequence > xYValueSeq =
2027 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES );
2028 if( xYValueSeq.is() )
2029 aLabeledSeqVec.push_back( xYValueSeq );
2030 // add X values
2031 if( !rTypeInfo.mbCategoryAxis )
2033 Reference< XLabeledDataSequence > xXValueSeq =
2034 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES );
2035 if( xXValueSeq.is() )
2036 aLabeledSeqVec.push_back( xXValueSeq );
2037 // add size values of bubble charts
2038 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
2040 Reference< XLabeledDataSequence > xSizeValueSeq =
2041 lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() );
2042 if( xSizeValueSeq.is() )
2043 aLabeledSeqVec.push_back( xSizeValueSeq );
2046 // attach labeled data sequences to series
2047 if( !aLabeledSeqVec.empty() )
2048 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2051 // series formatting
2052 ScfPropertySet aSeriesProp( xDataSeries );
2053 if( mxSeriesFmt )
2054 mxSeriesFmt->Convert( aSeriesProp, rTypeInfo );
2056 // trend lines
2057 ConvertTrendLines( xDataSeries );
2059 // error bars
2060 Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
2061 if( xErrorBarX.is() )
2062 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX );
2063 Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
2064 if( xErrorBarY.is() )
2065 aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY );
2067 // own area formatting for every data point (TODO: varying line color not supported)
2068 bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat();
2069 #if EXC_CHART2_VARYCOLORSBY_PROP
2070 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt );
2071 #else
2072 aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
2073 #endif
2074 // #i91271# always set area formatting for every point in pie/doughnut charts
2075 if (mxSeriesFmt && mxValueLink && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)))
2077 for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx )
2079 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
2080 mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx, false );
2084 // data point formatting
2085 for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt )
2087 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first );
2088 aIt->second->Convert( aPointProp, rTypeInfo );
2091 return xDataSeries;
2094 void XclImpChSeries::FillAllSourceLinks( ::std::vector< ScTokenRef >& rTokens ) const
2096 if( mxValueLink )
2097 mxValueLink->FillSourceLink( rTokens );
2098 if( mxCategLink )
2099 mxCategLink->FillSourceLink( rTokens );
2100 if( mxTitleLink )
2101 mxTitleLink->FillSourceLink( rTokens );
2102 if( mxBubbleLink )
2103 mxBubbleLink->FillSourceLink( rTokens );
2106 void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm )
2108 XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
2109 xSrcLink->ReadChSourceLink( rStrm );
2110 switch( xSrcLink->GetDestType() )
2112 case EXC_CHSRCLINK_TITLE: mxTitleLink = xSrcLink; break;
2113 case EXC_CHSRCLINK_VALUES: mxValueLink = xSrcLink; break;
2114 case EXC_CHSRCLINK_CATEGORY: mxCategLink = xSrcLink; break;
2115 case EXC_CHSRCLINK_BUBBLES: mxBubbleLink = xSrcLink; break;
2119 void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm )
2121 // #i51639# chart stores all data formats and assigns them later to the series
2122 GetChartData().ReadChDataFormat( rStrm );
2125 void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm )
2127 mnParentIdx = rStrm.ReaduInt16();
2128 // index to parent series is 1-based, convert it to 0-based
2129 if( mnParentIdx > 0 )
2130 --mnParentIdx;
2131 else
2132 mnParentIdx = EXC_CHSERIES_INVALID;
2135 void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm )
2137 XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
2138 xTrendLine->ReadChSerTrendLine( rStrm );
2139 maTrendLines.push_back( xTrendLine );
2142 void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm )
2144 unique_ptr<XclImpChSerErrorBar> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
2145 pErrorBar->ReadChSerErrorBar(rStrm);
2146 sal_uInt8 nBarType = pErrorBar->GetBarType();
2147 o3tl::ptr_container::insert(maErrorBars, nBarType, std::move(pErrorBar));
2150 XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx )
2152 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2153 xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx );
2154 return xDataFmt;
2157 void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const
2159 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2160 if( xRegCurveCont.is() )
2162 for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt )
2166 Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve();
2167 if( xRegCurve.is() )
2169 xRegCurveCont->addRegressionCurve( xRegCurve );
2172 catch( Exception& )
2174 OSL_FAIL( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2180 Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const
2182 XclImpChSerErrorBarMap::const_iterator itrPosBar = maErrorBars.find(nPosBarId);
2183 XclImpChSerErrorBarMap::const_iterator itrNegBar = maErrorBars.find(nNegBarId);
2184 XclImpChSerErrorBarMap::const_iterator itrEnd = maErrorBars.end();
2185 if (itrPosBar == itrEnd || itrNegBar == itrEnd)
2186 return Reference<XPropertySet>();
2188 return XclImpChSerErrorBar::CreateErrorBar(itrPosBar->second, itrNegBar->second);
2191 // Chart type groups ==========================================================
2193 XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) :
2194 XclImpChRoot( rRoot ),
2195 mnRecId( EXC_ID_CHUNKNOWN ),
2196 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2200 void XclImpChType::ReadChType( XclImpStream& rStrm )
2202 sal_uInt16 nRecId = rStrm.GetRecId();
2203 bool bKnownType = true;
2205 switch( nRecId )
2207 case EXC_ID_CHBAR:
2208 maData.mnOverlap = rStrm.ReadInt16();
2209 maData.mnGap = rStrm.ReadInt16();
2210 maData.mnFlags = rStrm.ReaduInt16();
2211 break;
2213 case EXC_ID_CHLINE:
2214 case EXC_ID_CHAREA:
2215 case EXC_ID_CHRADARLINE:
2216 case EXC_ID_CHRADARAREA:
2217 maData.mnFlags = rStrm.ReaduInt16();
2218 break;
2220 case EXC_ID_CHPIE:
2221 maData.mnRotation = rStrm.ReaduInt16();
2222 maData.mnPieHole = rStrm.ReaduInt16();
2223 if( GetBiff() == EXC_BIFF8 )
2224 maData.mnFlags = rStrm.ReaduInt16();
2225 else
2226 maData.mnFlags = 0;
2227 break;
2229 case EXC_ID_CHPIEEXT:
2230 maData.mnRotation = 0;
2231 maData.mnPieHole = 0;
2232 maData.mnFlags = 0;
2233 break;
2235 case EXC_ID_CHSCATTER:
2236 if( GetBiff() == EXC_BIFF8 )
2238 maData.mnBubbleSize = rStrm.ReaduInt16();
2239 maData.mnBubbleType = rStrm.ReaduInt16();
2240 maData.mnFlags = rStrm.ReaduInt16();
2242 else
2243 maData.mnFlags = 0;
2244 break;
2246 case EXC_ID_CHSURFACE:
2247 maData.mnFlags = rStrm.ReaduInt16();
2248 break;
2250 default:
2251 bKnownType = false;
2254 if( bKnownType )
2255 mnRecId = nRecId;
2258 void XclImpChType::Finalize( bool bStockChart )
2260 switch( mnRecId )
2262 case EXC_ID_CHLINE:
2263 maTypeInfo = GetChartTypeInfo( bStockChart ?
2264 EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE );
2265 break;
2266 case EXC_ID_CHBAR:
2267 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2268 maData.mnFlags, EXC_CHBAR_HORIZONTAL,
2269 EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) );
2270 break;
2271 case EXC_ID_CHPIE:
2272 maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ?
2273 EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2274 break;
2275 case EXC_ID_CHSCATTER:
2276 maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2277 maData.mnFlags, EXC_CHSCATTER_BUBBLES,
2278 EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) );
2279 break;
2280 default:
2281 maTypeInfo = GetChartTypeInfo( mnRecId );
2284 switch( maTypeInfo.meTypeId )
2286 case EXC_CHTYPEID_PIEEXT:
2287 case EXC_CHTYPEID_BUBBLES:
2288 case EXC_CHTYPEID_SURFACE:
2289 case EXC_CHTYPEID_UNKNOWN:
2290 GetTracer().TraceChartUnKnownType();
2291 break;
2292 default:;
2296 bool XclImpChType::IsStacked() const
2298 bool bStacked = false;
2299 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2301 case EXC_CHTYPECATEG_LINE:
2302 bStacked =
2303 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2304 !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2305 break;
2306 case EXC_CHTYPECATEG_BAR:
2307 bStacked =
2308 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2309 !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2310 break;
2311 default:;
2313 return bStacked;
2316 bool XclImpChType::IsPercent() const
2318 bool bPercent = false;
2319 if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2321 case EXC_CHTYPECATEG_LINE:
2322 bPercent =
2323 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2324 ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2325 break;
2326 case EXC_CHTYPECATEG_BAR:
2327 bPercent =
2328 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2329 ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2330 break;
2331 default:;
2333 return bPercent;
2336 bool XclImpChType::HasCategoryLabels() const
2338 // radar charts disable category labels in chart type, not in CHTICK of X axis
2339 return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS );
2342 Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const
2344 // create the coordinate system object
2345 Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
2346 Reference< XCoordinateSystem > xCoordSystem;
2347 if( maTypeInfo.mbPolarCoordSystem )
2349 if( b3dChart )
2350 xCoordSystem = css::chart2::PolarCoordinateSystem3d::create(xContext);
2351 else
2352 xCoordSystem = css::chart2::PolarCoordinateSystem2d::create(xContext);
2354 else
2356 if( b3dChart )
2357 xCoordSystem = css::chart2::CartesianCoordinateSystem3d::create(xContext);
2358 else
2359 xCoordSystem = css::chart2::CartesianCoordinateSystem2d::create(xContext);
2362 // swap X and Y axis
2363 if( maTypeInfo.mbSwappedAxesSet )
2365 ScfPropertySet aCoordSysProp( xCoordSystem );
2366 aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true );
2369 return xCoordSystem;
2372 Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const
2374 OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
2375 Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
2377 // additional properties
2378 switch( maTypeInfo.meTypeCateg )
2380 case EXC_CHTYPECATEG_BAR:
2382 ScfPropertySet aTypeProp( xChartType );
2383 Sequence< sal_Int32 > aInt32Seq( 2 );
2384 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap;
2385 aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq );
2386 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap;
2387 aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq );
2389 break;
2390 case EXC_CHTYPECATEG_PIE:
2392 ScfPropertySet aTypeProp( xChartType );
2393 aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT );
2394 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2395 rotation setting in view3D element. Of-pie charts do not
2396 support pie rotation. */
2397 if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) )
2399 ScfPropertySet aDiaProp( xDiagram );
2400 XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation );
2403 break;
2404 default:;
2407 return xChartType;
2410 void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm )
2412 maData.mnRotation = rStrm.ReaduInt16();
2413 maData.mnElevation = rStrm.ReadInt16();
2414 maData.mnEyeDist = rStrm.ReaduInt16();
2415 maData.mnRelHeight = rStrm.ReaduInt16();
2416 maData.mnRelDepth = rStrm.ReaduInt16();
2417 maData.mnDepthGap = rStrm.ReaduInt16();
2418 maData.mnFlags = rStrm.ReaduInt16();
2421 void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const
2423 namespace cssd = ::com::sun::star::drawing;
2425 // #i104057# do not assert this, written by broken external generators
2426 // OSL_ENSURE( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2428 sal_Int32 nRotationY = 0;
2429 sal_Int32 nRotationX = 0;
2430 sal_Int32 nPerspective = 15;
2431 bool bRightAngled = false;
2432 cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE;
2433 Color aAmbientColor, aLightColor;
2435 if( b3dWallChart )
2437 // Y rotation (Excel [0..359], Chart2 [-179,180])
2438 nRotationY = maData.mnRotation % 360;
2439 if( nRotationY > 180 ) nRotationY -= 360;
2440 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2441 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 );
2442 // perspective (Excel and Chart2 [0,100])
2443 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2444 // right-angled axes
2445 bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D );
2446 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2447 bool bParallel = bRightAngled || (nPerspective == 0);
2448 eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
2449 // ambient color (Gray 20%)
2450 aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) );
2451 // light color (Gray 60%)
2452 aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) );
2454 else
2456 // Y rotation not used in pie charts, but 'first pie slice angle'
2457 nRotationY = 0;
2458 XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation );
2459 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2460 nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90;
2461 // perspective (Excel and Chart2 [0,100])
2462 nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2463 // no right-angled axes in pie charts, but parallel projection
2464 bRightAngled = false;
2465 eProjMode = cssd::ProjectionMode_PARALLEL;
2466 // ambient color (Gray 30%)
2467 aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) );
2468 // light color (Gray 70%)
2469 aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) );
2472 // properties
2473 rPropSet.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT, (sal_Int32)(maData.mnRelHeight / 2)); // seems to be 200%, cange to 100%
2474 rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY );
2475 rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX );
2476 rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective );
2477 rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled );
2478 rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode );
2480 // light settings
2481 rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT );
2482 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor );
2483 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false );
2484 rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true );
2485 rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor );
2486 rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2489 XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) :
2490 XclImpChRoot( rRoot )
2494 void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm )
2496 rStrm >> maData.maRect;
2497 maData.mnDockMode = rStrm.ReaduInt8();
2498 maData.mnSpacing = rStrm.ReaduInt8();
2499 maData.mnFlags = rStrm.ReaduInt16();
2501 // trace unsupported features
2502 if( GetTracer().IsEnabled() )
2504 if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED )
2505 GetTracer().TraceChartLegendPosition();
2506 if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) )
2507 GetTracer().TraceChartDataTable();
2511 void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm )
2513 switch( rStrm.GetRecId() )
2515 case EXC_ID_CHFRAMEPOS:
2516 mxFramePos.reset( new XclImpChFramePos );
2517 mxFramePos->ReadChFramePos( rStrm );
2518 break;
2519 case EXC_ID_CHTEXT:
2520 mxText.reset( new XclImpChText( GetChRoot() ) );
2521 mxText->ReadRecordGroup( rStrm );
2522 break;
2523 case EXC_ID_CHFRAME:
2524 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2525 mxFrame->ReadRecordGroup( rStrm );
2526 break;
2530 void XclImpChLegend::Finalize()
2532 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2533 if( !mxFrame )
2534 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2535 // Update text formatting. If mxText is empty, the passed default text is used.
2536 lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) );
2539 Reference< XLegend > XclImpChLegend::CreateLegend() const
2541 Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY );
2542 if( xLegend.is() )
2544 ScfPropertySet aLegendProp( xLegend );
2545 aLegendProp.SetBoolProperty( EXC_CHPROP_SHOW, true );
2547 // frame properties
2548 if( mxFrame )
2549 mxFrame->Convert( aLegendProp );
2550 // text properties
2551 if( mxText )
2552 mxText->ConvertFont( aLegendProp );
2554 /* Legend position and size. Default positions are used only if the
2555 plot area is positioned automatically (Excel sets the plot area to
2556 manual mode, if the legend is moved or resized). With manual plot
2557 areas, Excel ignores the value in maData.mnDockMode completely. */
2558 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2559 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2560 if( !GetChartData().IsManualPlotArea() ) switch( maData.mnDockMode )
2562 case EXC_CHLEGEND_LEFT:
2563 eApiPos = cssc2::LegendPosition_LINE_START;
2564 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2565 break;
2566 case EXC_CHLEGEND_RIGHT:
2567 // top-right not supported
2568 case EXC_CHLEGEND_CORNER:
2569 eApiPos = cssc2::LegendPosition_LINE_END;
2570 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2571 break;
2572 case EXC_CHLEGEND_TOP:
2573 eApiPos = cssc2::LegendPosition_PAGE_START;
2574 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2575 break;
2576 case EXC_CHLEGEND_BOTTOM:
2577 eApiPos = cssc2::LegendPosition_PAGE_END;
2578 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2579 break;
2582 // no automatic position/size: try to find the correct position and size
2583 if( eApiPos == cssc2::LegendPosition_CUSTOM )
2585 const XclChFramePos* pFramePos = mxFramePos ? &mxFramePos->GetFramePosData() : 0;
2587 /* Legend position. Only the settings from the CHFRAMEPOS record
2588 are used by Excel, the position in the CHLEGEND record will be
2589 ignored. */
2590 if( pFramePos )
2592 RelativePosition aRelPos(
2593 CalcRelativeFromChartX( pFramePos->maRect.mnX ),
2594 CalcRelativeFromChartY( pFramePos->maRect.mnY ),
2595 ::com::sun::star::drawing::Alignment_TOP_LEFT );
2596 aLegendProp.SetProperty( EXC_CHPROP_RELATIVEPOSITION, aRelPos );
2598 else
2600 // no manual position/size found, just go for the default
2601 eApiPos = cssc2::LegendPosition_LINE_END;
2604 /* Legend size. The member mnBRMode specifies whether size is
2605 automatic or changes manually. Manual size is given in points,
2606 not in chart units. */
2607 if( pFramePos && (pFramePos->mnBRMode == EXC_CHFRAMEPOS_ABSSIZE_POINTS) &&
2608 (pFramePos->maRect.mnWidth > 0) && (pFramePos->maRect.mnHeight > 0) )
2610 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2611 sal_Int32 nWidthHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnWidth / EXC_POINTS_PER_HMM );
2612 sal_Int32 nHeightHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnHeight / EXC_POINTS_PER_HMM );
2613 RelativeSize aRelSize( CalcRelativeFromHmmX( nWidthHmm ), CalcRelativeFromHmmY( nHeightHmm ) );
2614 aLegendProp.SetProperty( EXC_CHPROP_RELATIVESIZE, aRelSize );
2616 else
2618 // automatic size: determine entry direction from flags
2619 eApiExpand = ::get_flagvalue( maData.mnFlags, EXC_CHLEGEND_STACKED,
2620 cssc::ChartLegendExpansion_HIGH, cssc::ChartLegendExpansion_WIDE );
2623 aLegendProp.SetProperty( EXC_CHPROP_ANCHORPOSITION, eApiPos );
2624 aLegendProp.SetProperty( EXC_CHPROP_EXPANSION, eApiExpand );
2626 return xLegend;
2629 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) :
2630 mnDropBar( nDropBar ),
2631 mnBarDist( 0 )
2635 void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm )
2637 mnBarDist = rStrm.ReaduInt16();
2640 void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
2642 XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND;
2643 switch( mnDropBar )
2645 case EXC_CHDROPBAR_UP: eObjType = EXC_CHOBJTYPE_WHITEDROPBAR; break;
2646 case EXC_CHDROPBAR_DOWN: eObjType = EXC_CHOBJTYPE_BLACKDROPBAR; break;
2648 ConvertFrameBase( rRoot, rPropSet, eObjType );
2651 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) :
2652 XclImpChRoot( rRoot ),
2653 maType( rRoot ),
2654 maTypeInfo( maType.GetTypeInfo() )
2656 // Initialize unused format indexes set. At this time, all formats are unused.
2657 for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx )
2658 maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx );
2661 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm )
2663 rStrm.Ignore( 16 );
2664 maData.mnFlags = rStrm.ReaduInt16();
2665 maData.mnGroupIdx = rStrm.ReaduInt16();
2668 void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm )
2670 switch( rStrm.GetRecId() )
2672 case EXC_ID_CHCHART3D:
2673 mxChart3d.reset( new XclImpChChart3d );
2674 mxChart3d->ReadChChart3d( rStrm );
2675 break;
2676 case EXC_ID_CHLEGEND:
2677 mxLegend.reset( new XclImpChLegend( GetChRoot() ) );
2678 mxLegend->ReadRecordGroup( rStrm );
2679 break;
2680 case EXC_ID_CHDEFAULTTEXT:
2681 GetChartData().ReadChDefaultText( rStrm );
2682 break;
2683 case EXC_ID_CHDROPBAR:
2684 ReadChDropBar( rStrm );
2685 break;
2686 case EXC_ID_CHCHARTLINE:
2687 ReadChChartLine( rStrm );
2688 break;
2689 case EXC_ID_CHDATAFORMAT:
2690 ReadChDataFormat( rStrm );
2691 break;
2692 default:
2693 maType.ReadChType( rStrm );
2697 void XclImpChTypeGroup::Finalize()
2699 // check and set valid chart type
2700 bool bStockChart =
2701 (maType.GetRecId() == EXC_ID_CHLINE) && // must be a line chart
2702 !mxChart3d && // must be a 2d chart
2703 HasHiLoLine() && // must contain hi-lo lines
2704 (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3)); // correct series count
2705 maType.Finalize( bStockChart );
2707 // extended type info
2708 maTypeInfo.Set( maType.GetTypeInfo(), static_cast< bool >(mxChart3d), false );
2710 // reverse series order for some unstacked 2D chart types
2711 if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() )
2712 ::std::reverse( maSeries.begin(), maSeries.end() );
2714 // update chart type group format, may depend on chart type finalized above
2715 if( mxGroupFmt )
2716 mxGroupFmt->UpdateGroupFormat( maTypeInfo );
2719 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries )
2721 if( xSeries )
2722 maSeries.push_back( xSeries );
2723 // store first inserted series separately, series order may be reversed later
2724 if( !mxFirstSeries )
2725 mxFirstSeries = xSeries;
2728 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx )
2730 maUnusedFormats.erase( nFormatIdx );
2733 sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex()
2735 OSL_ENSURE( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2736 sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin();
2737 SetUsedFormatIndex( nFormatIdx );
2738 return nFormatIdx;
2741 bool XclImpChTypeGroup::HasVarPointFormat() const
2743 return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) &&
2744 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) || // multiple series allowed
2745 ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) && // or exactly 1 series?
2746 (maSeries.size() == 1)));
2749 bool XclImpChTypeGroup::HasConnectorLines() const
2751 // existence of connector lines (only in stacked bar charts)
2752 if ( !(maType.IsStacked() || maType.IsPercent()) || (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
2753 return false;
2754 XclImpChLineFormatMap::const_iterator xConLine = maChartLines.find( EXC_CHCHARTLINE_CONNECT );
2755 return ( xConLine != maChartLines.end() && xConLine->second->HasLine() );
2758 OUString XclImpChTypeGroup::GetSingleSeriesTitle() const
2760 // no automatic title for series with trendlines or error bars
2761 // pie charts always show an automatic title, even if more series exist
2762 return (mxFirstSeries && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ?
2763 mxFirstSeries->GetTitle() : OUString();
2766 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const
2768 if( mxChart3d )
2769 mxChart3d->Convert( rPropSet, Is3dWallChart() );
2772 Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const
2774 return maType.CreateCoordSystem( Is3dChart() );
2777 Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const
2779 OSL_ENSURE( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2781 // create the chart type object
2782 Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() );
2784 // bar chart connector lines
2785 if( HasConnectorLines() )
2787 ScfPropertySet aDiaProp( xDiagram );
2788 aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true );
2791 /* Stock chart needs special processing. Create one 'big' series with
2792 data sequences of different roles. */
2793 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2794 CreateStockSeries( xChartType, nApiAxesSetIdx );
2795 else
2796 CreateDataSeries( xChartType, nApiAxesSetIdx );
2798 return xChartType;
2801 Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const
2803 Reference< XLabeledDataSequence > xLabeledSeq;
2804 // create category sequence from first visible series
2805 if( mxFirstSeries )
2806 xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG );
2807 return xLabeledSeq;
2810 void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm )
2812 if (maDropBars.find(EXC_CHDROPBAR_UP) == maDropBars.end())
2814 unique_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_UP));
2815 p->ReadRecordGroup(rStrm);
2816 o3tl::ptr_container::insert(maDropBars, EXC_CHDROPBAR_UP, std::move(p));
2818 else if(maDropBars.find(EXC_CHDROPBAR_DOWN) == maDropBars.end())
2820 unique_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN));
2821 p->ReadRecordGroup(rStrm);
2822 o3tl::ptr_container::insert(maDropBars, EXC_CHDROPBAR_DOWN, std::move(p));
2826 void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm )
2828 sal_uInt16 nLineId = rStrm.ReaduInt16();
2829 if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() )
2831 XclImpChLineFormat xLineFmt;
2832 xLineFmt.ReadChLineFormat( rStrm );
2833 maChartLines[ nLineId ] = xLineFmt;
2837 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm )
2839 // global series and data point format
2840 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2841 xDataFmt->ReadRecordGroup( rStrm );
2842 const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
2843 if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) &&
2844 (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) )
2845 mxGroupFmt = xDataFmt;
2848 void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType,
2849 Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const
2851 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2852 if( xSeriesCont.is() && xSeries.is() )
2854 // series stacking mode
2855 cssc2::StackingDirection eStacking = cssc2::StackingDirection_NO_STACKING;
2856 // stacked overrides deep-3d
2857 if( maType.IsStacked() || maType.IsPercent() )
2858 eStacking = cssc2::StackingDirection_Y_STACKING;
2859 else if( Is3dDeepChart() )
2860 eStacking = cssc2::StackingDirection_Z_STACKING;
2862 // additional series properties
2863 ScfPropertySet aSeriesProp( xSeries );
2864 aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking );
2865 aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx );
2867 // insert series into container
2870 xSeriesCont->addDataSeries( xSeries );
2872 catch( Exception& )
2874 OSL_FAIL( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2879 void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2881 bool bSpline = false;
2882 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
2884 Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries();
2885 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2886 bSpline |= (*aIt)->HasSpline();
2888 // spline - TODO: set at single series (#i66858#)
2889 if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) )
2891 ScfPropertySet aTypeProp( xChartType );
2892 aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES );
2896 void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2898 // create the data series object
2899 Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2900 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2901 if( xDataSink.is() )
2903 // create a list of data sequences from all series
2904 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2905 OSL_ENSURE( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2906 int nRoleIdx = (maSeries.size() == 3) ? 1 : 0;
2907 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end();
2908 (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
2910 // create a data sequence with a specific role
2911 OUString aRole;
2912 switch( nRoleIdx )
2914 case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES; break;
2915 case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES; break;
2916 case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES; break;
2917 case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES; break;
2919 Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole );
2920 if( xDataSeq.is() )
2921 aLabeledSeqVec.push_back( xDataSeq );
2924 // attach labeled data sequences to series and insert series into chart type
2925 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2927 // formatting of special stock chart elements
2928 ScfPropertySet aTypeProp( xChartType );
2929 aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() );
2930 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() );
2931 aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true );
2932 // hi-lo line format
2933 XclImpChLineFormatMap::const_iterator xHiLoLine = maChartLines.find( EXC_CHCHARTLINE_HILO );
2934 if ( xHiLoLine != maChartLines.end() )
2936 ScfPropertySet aSeriesProp( xDataSeries );
2937 xHiLoLine->second->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2939 // white dropbar format
2940 XclImpChDropBarMap::const_iterator itr = maDropBars.find(EXC_CHDROPBAR_UP);
2941 Reference<XPropertySet> xWhitePropSet;
2942 if (itr != maDropBars.end() && aTypeProp.GetProperty(xWhitePropSet, EXC_CHPROP_WHITEDAY))
2944 ScfPropertySet aBarProp( xWhitePropSet );
2945 itr->second->Convert(GetChRoot(), aBarProp);
2947 // black dropbar format
2948 itr = maDropBars.find(EXC_CHDROPBAR_DOWN);
2949 Reference<XPropertySet> xBlackPropSet;
2950 if (itr != maDropBars.end() && aTypeProp.GetProperty(xBlackPropSet, EXC_CHPROP_BLACKDAY))
2952 ScfPropertySet aBarProp( xBlackPropSet );
2953 itr->second->Convert(GetChRoot(), aBarProp);
2956 // insert the series into the chart type object
2957 InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2961 // Axes =======================================================================
2963 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) :
2964 XclImpChRoot( rRoot )
2968 void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm )
2970 maLabelData.mnCross = rStrm.ReaduInt16();
2971 maLabelData.mnLabelFreq = rStrm.ReaduInt16();
2972 maLabelData.mnTickFreq = rStrm.ReaduInt16();
2973 maLabelData.mnFlags = rStrm.ReaduInt16();
2976 void XclImpChLabelRange::ReadChDateRange( XclImpStream& rStrm )
2978 maDateData.mnMinDate = rStrm.ReaduInt16();
2979 maDateData.mnMaxDate = rStrm.ReaduInt16();
2980 maDateData.mnMajorStep = rStrm.ReaduInt16();
2981 maDateData.mnMajorUnit = rStrm.ReaduInt16();
2982 maDateData.mnMinorStep = rStrm.ReaduInt16();
2983 maDateData.mnMinorUnit = rStrm.ReaduInt16();
2984 maDateData.mnBaseUnit = rStrm.ReaduInt16();
2985 maDateData.mnCross = rStrm.ReaduInt16();
2986 maDateData.mnFlags = rStrm.ReaduInt16();
2989 void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const
2991 // automatic axis type detection
2992 rScaleData.AutoDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE );
2994 // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
2995 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
2997 /* Chart2 requires axis type CATEGORY for automatic category/date axis
2998 (even if it is a date axis currently). */
2999 rScaleData.AxisType = rScaleData.AutoDateAxis ? cssc2::AxisType::CATEGORY : cssc2::AxisType::DATE;
3000 rScaleData.Scaling = css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3001 /* Min/max values depend on base time unit, they specify the number of
3002 days, months, or years starting from null date. */
3003 lclConvertTimeValue( GetRoot(), rScaleData.Minimum, maDateData.mnMinDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN ), maDateData.mnBaseUnit );
3004 lclConvertTimeValue( GetRoot(), rScaleData.Maximum, maDateData.mnMaxDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX ), maDateData.mnBaseUnit );
3005 // increment
3006 cssc::TimeIncrement& rTimeIncrement = rScaleData.TimeIncrement;
3007 lclConvertTimeInterval( rTimeIncrement.MajorTimeInterval, maDateData.mnMajorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR ), maDateData.mnMajorUnit );
3008 lclConvertTimeInterval( rTimeIncrement.MinorTimeInterval, maDateData.mnMinorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR ), maDateData.mnMinorUnit );
3009 // base unit
3010 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE ) )
3011 rTimeIncrement.TimeResolution.clear();
3012 else
3013 rTimeIncrement.TimeResolution <<= lclGetApiTimeUnit( maDateData.mnBaseUnit );
3015 else
3017 // do not overlap text unless all labels are visible
3018 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maLabelData.mnLabelFreq == 1 );
3019 // do not break text into several lines unless all labels are visible
3020 rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maLabelData.mnLabelFreq == 1 );
3021 // do not stagger labels in two lines
3022 rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE );
3025 // reverse order
3026 bool bReverse = ::get_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient;
3027 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
3029 //TODO #i58731# show n-th category
3032 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const
3034 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
3035 does not move the Y axis in 3D charts, regardless of actual settings.
3036 But: the Y axis has to be moved to "end", if the X axis is mirrored,
3037 to keep it at the left end of the chart. */
3038 bool bMaxCross = ::get_flag( maLabelData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS );
3039 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
3040 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
3042 // crossing position (depending on axis type text/date)
3043 if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
3045 bool bAutoCross = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
3046 /* Crossing position value depends on base time unit, it specifies the
3047 number of days, months, or years from null date. Note that Excel
3048 2007/2010 write broken BIFF8 files, they always stores the number
3049 of days cregardless of the base time unit (and they are reading it
3050 the same way, thus wrongly displaying files written by Excel
3051 97-2003). This filter sticks to the correct behaviour of Excel
3052 97-2003. */
3053 double fCrossingPos = bAutoCross ? 1.0 : lclGetSerialDay( GetRoot(), maDateData.mnCross, maDateData.mnBaseUnit );
3054 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3056 else
3058 double fCrossingPos = b3dChart ? 1.0 : maLabelData.mnCross;
3059 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3063 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) :
3064 XclImpChRoot( rRoot )
3068 void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm )
3070 maData.mfMin = rStrm.ReadDouble();
3071 maData.mfMax = rStrm.ReadDouble();
3072 maData.mfMajorStep = rStrm.ReadDouble();
3073 maData.mfMinorStep = rStrm.ReadDouble();
3074 maData.mfCross = rStrm.ReadDouble();
3075 maData.mnFlags = rStrm.ReaduInt16();
3078 void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const
3080 // scaling algorithm
3081 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3082 if( bLogScale )
3083 rScaleData.Scaling = css::chart2::LogarithmicScaling::create( comphelper::getProcessComponentContext() );
3084 else
3085 rScaleData.Scaling = css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3087 // min/max
3088 lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) );
3089 lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) );
3091 // increment
3092 bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR );
3093 bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR );
3094 // major increment
3095 IncrementData& rIncrementData = rScaleData.IncrementData;
3096 lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor );
3097 // minor increment
3098 Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
3099 rSubIncrementSeq.realloc( 1 );
3100 Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount;
3101 rIntervalCount.clear();
3102 if( bLogScale )
3104 if( !bAutoMinor )
3105 rIntervalCount <<= sal_Int32( 9 );
3107 else
3109 if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) )
3111 double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5;
3112 if( (1.0 <= fCount) && (fCount < 1001.0) )
3113 rIntervalCount <<= static_cast< sal_Int32 >( fCount );
3117 // reverse order
3118 bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient;
3119 rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
3122 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const
3124 bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
3125 bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
3126 bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3128 // crossing mode (max-cross flag overrides other crossing settings)
3129 cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
3130 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
3132 // crossing position
3133 double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross;
3134 if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos );
3135 rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3138 namespace {
3140 sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos )
3142 using namespace ::com::sun::star::chart2::TickmarkStyle;
3143 sal_Int32 nApiTickmarks = css::chart2::TickmarkStyle::NONE;
3144 ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) );
3145 ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) );
3146 return nApiTickmarks;
3149 cssc::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos )
3151 using namespace ::com::sun::star::chart;
3152 switch( nXclLabelPos )
3154 case EXC_CHTICK_LOW: return ChartAxisLabelPosition_OUTSIDE_START;
3155 case EXC_CHTICK_HIGH: return ChartAxisLabelPosition_OUTSIDE_END;
3156 case EXC_CHTICK_NEXT: return ChartAxisLabelPosition_NEAR_AXIS;
3158 return ChartAxisLabelPosition_NEAR_AXIS;
3161 } // namespace
3163 XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) :
3164 XclImpChRoot( rRoot )
3168 void XclImpChTick::ReadChTick( XclImpStream& rStrm )
3170 maData.mnMajor = rStrm.ReaduInt8();
3171 maData.mnMinor = rStrm.ReaduInt8();
3172 maData.mnLabelPos = rStrm.ReaduInt8();
3173 maData.mnBackMode = rStrm.ReaduInt8();
3174 rStrm.Ignore( 16 );
3175 rStrm >> maData.maTextColor;
3176 maData.mnFlags = rStrm.ReaduInt16();
3178 if( GetBiff() == EXC_BIFF8 )
3180 // BIFF8: index into palette used instead of RGB data
3181 maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
3182 // rotation
3183 maData.mnRotation = rStrm.ReaduInt16();
3185 else
3187 // BIFF2-BIFF7: get rotation from text orientation
3188 sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 );
3189 maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
3193 Color XclImpChTick::GetFontColor() const
3195 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
3198 sal_uInt16 XclImpChTick::GetRotation() const
3200 /* n#720443: Ignore auto-rotation if there is a suggested rotation.
3201 * Better fix would be to improve our axis auto rotation algorithm.
3203 if( maData.mnRotation != EXC_ROT_NONE )
3204 return maData.mnRotation;
3205 return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation;
3208 void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const
3210 rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) );
3211 rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) );
3212 rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) );
3213 rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, cssc::ChartAxisMarkPosition_AT_AXIS );
3216 XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) :
3217 XclImpChRoot( rRoot ),
3218 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
3220 maData.mnType = nAxisType;
3223 void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm )
3225 maData.mnType = rStrm.ReaduInt16();
3228 void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm )
3230 switch( rStrm.GetRecId() )
3232 case EXC_ID_CHLABELRANGE:
3233 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3234 mxLabelRange->ReadChLabelRange( rStrm );
3235 break;
3236 case EXC_ID_CHDATERANGE:
3237 if( !mxLabelRange )
3238 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3239 mxLabelRange->ReadChDateRange( rStrm );
3240 break;
3241 case EXC_ID_CHVALUERANGE:
3242 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3243 mxValueRange->ReadChValueRange( rStrm );
3244 break;
3245 case EXC_ID_CHFORMAT:
3246 mnNumFmtIdx = rStrm.ReaduInt16();
3247 break;
3248 case EXC_ID_CHTICK:
3249 mxTick.reset( new XclImpChTick( GetChRoot() ) );
3250 mxTick->ReadChTick( rStrm );
3251 break;
3252 case EXC_ID_CHFONT:
3253 mxFont.reset( new XclImpChFont );
3254 mxFont->ReadChFont( rStrm );
3255 break;
3256 case EXC_ID_CHAXISLINE:
3257 ReadChAxisLine( rStrm );
3258 break;
3262 void XclImpChAxis::Finalize()
3264 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3265 if( !mxLabelRange )
3266 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3267 if( !mxValueRange )
3268 mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3269 // remove invisible grid lines completely
3270 if( mxMajorGrid && !mxMajorGrid->HasLine() )
3271 mxMajorGrid.reset();
3272 if( mxMinorGrid && !mxMinorGrid->HasLine() )
3273 mxMinorGrid.reset();
3274 // default tick settings different in OOChart and Excel
3275 if( !mxTick )
3276 mxTick.reset( new XclImpChTick( GetChRoot() ) );
3277 // #i4140# different default axis line color
3278 if( !mxAxisLine )
3280 XclChLineFormat aLineFmt;
3281 // set "show axis" flag, default if line format record is missing
3282 ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS );
3283 mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) );
3285 // add wall/floor frame for 3d charts
3286 if( !mxWallFrame )
3287 CreateWallFrame();
3290 sal_uInt16 XclImpChAxis::GetFontIndex() const
3292 return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
3295 Color XclImpChAxis::GetFontColor() const
3297 return mxTick ? mxTick->GetFontColor() : GetFontAutoColor();
3300 sal_uInt16 XclImpChAxis::GetRotation() const
3302 return mxTick ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION;
3305 Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const
3307 // create the axis object (always)
3308 Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY );
3309 if( xAxis.is() )
3311 ScfPropertySet aAxisProp( xAxis );
3312 // #i58688# axis enabled
3313 aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() );
3315 // axis line properties
3316 if( mxAxisLine )
3317 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
3318 // axis ticks properties
3319 if( mxTick )
3320 mxTick->Convert( aAxisProp );
3322 // axis caption text --------------------------------------------------
3324 // radar charts disable their category labels via chart type, not via axis
3325 bool bHasLabels = HasLabels() &&
3326 ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels());
3327 aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels );
3328 if( bHasLabels )
3330 // font settings from CHFONT record or from default text
3331 if( mxFont )
3332 ConvertFontBase( GetChRoot(), aAxisProp );
3333 else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ) )
3334 pDefText->ConvertFont( aAxisProp );
3335 // label text rotation
3336 ConvertRotationBase( aAxisProp, true );
3337 // number format
3338 sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx );
3339 if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
3340 aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) );
3343 // axis scaling and increment -----------------------------------------
3345 const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo();
3346 ScaleData aScaleData = xAxis->getScaleData();
3347 // set axis type
3348 switch( GetAxisType() )
3350 case EXC_CHAXIS_X:
3351 if( rTypeInfo.mbCategoryAxis )
3353 aScaleData.AxisType = cssc2::AxisType::CATEGORY;
3354 aScaleData.Categories = rTypeGroup.CreateCategSequence();
3356 else
3357 aScaleData.AxisType = cssc2::AxisType::REALNUMBER;
3358 break;
3359 case EXC_CHAXIS_Y:
3360 aScaleData.AxisType = rTypeGroup.IsPercent() ?
3361 cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER;
3362 break;
3363 case EXC_CHAXIS_Z:
3364 aScaleData.AxisType = cssc2::AxisType::SERIES;
3365 break;
3367 // axis scaling settings, dependent on axis type
3368 switch( aScaleData.AxisType )
3370 case cssc2::AxisType::CATEGORY:
3371 case cssc2::AxisType::SERIES:
3372 OSL_ENSURE( mxLabelRange, "Missing Label Range" );
3373 // #i71684# radar charts have reversed rotation direction
3374 if (mxLabelRange)
3375 mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR );
3376 break;
3377 case cssc2::AxisType::REALNUMBER:
3378 case cssc2::AxisType::PERCENT:
3379 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3380 mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
3381 break;
3382 default:
3383 OSL_FAIL( "XclImpChAxis::CreateAxis - unknown axis type" );
3386 /* Do not set a value to the Origin member anymore (will be done via
3387 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3388 aScaleData.Origin.clear();
3390 // write back
3391 xAxis->setScaleData( aScaleData );
3393 // grid ---------------------------------------------------------------
3395 // main grid
3396 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3397 aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() );
3398 if( mxMajorGrid )
3399 mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3400 // sub grid
3401 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3402 if( aSubGridPropSeq.hasElements() )
3404 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3405 aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() );
3406 if( mxMinorGrid )
3407 mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3410 // position of crossing axis ------------------------------------------
3412 if( pCrossingAxis )
3413 pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup );
3415 return xAxis;
3418 void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const
3420 // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3421 if( mxWallFrame )
3422 mxWallFrame->Convert( rPropSet, true );
3425 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const
3427 if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) )
3429 OSL_ENSURE( mxLabelRange, "Missing Label Range" );
3430 if (mxLabelRange)
3431 mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() );
3433 else
3434 mxValueRange->ConvertAxisPosition( rPropSet );
3437 void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm )
3439 XclImpChLineFormatRef* pxLineFmt = 0;
3440 bool bWallFrame = false;
3441 switch( rStrm.ReaduInt16() )
3443 case EXC_CHAXISLINE_AXISLINE: pxLineFmt = &mxAxisLine; break;
3444 case EXC_CHAXISLINE_MAJORGRID: pxLineFmt = &mxMajorGrid; break;
3445 case EXC_CHAXISLINE_MINORGRID: pxLineFmt = &mxMinorGrid; break;
3446 case EXC_CHAXISLINE_WALLS: bWallFrame = true; break;
3448 if( bWallFrame )
3449 CreateWallFrame();
3451 bool bLoop = pxLineFmt || bWallFrame;
3452 while( bLoop )
3454 sal_uInt16 nRecId = rStrm.GetNextRecId();
3455 bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) ||
3456 (nRecId == EXC_ID_CHAREAFORMAT) ||
3457 (nRecId == EXC_ID_CHESCHERFORMAT))
3458 && rStrm.StartNextRecord();
3459 if( bLoop )
3461 if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) )
3463 pxLineFmt->reset( new XclImpChLineFormat );
3464 (*pxLineFmt)->ReadChLineFormat( rStrm );
3466 else if( bWallFrame && mxWallFrame )
3468 mxWallFrame->ReadSubRecord( rStrm );
3474 void XclImpChAxis::CreateWallFrame()
3476 switch( GetAxisType() )
3478 case EXC_CHAXIS_X:
3479 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) );
3480 break;
3481 case EXC_CHAXIS_Y:
3482 mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) );
3483 break;
3484 default:
3485 mxWallFrame.reset();
3489 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3490 XclImpChRoot( rRoot )
3492 maData.mnAxesSetId = nAxesSetId;
3495 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm )
3497 maData.mnAxesSetId = rStrm.ReaduInt16();
3498 rStrm >> maData.maRect;
3501 void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm )
3503 switch( rStrm.GetRecId() )
3505 case EXC_ID_CHFRAMEPOS:
3506 mxFramePos.reset( new XclImpChFramePos );
3507 mxFramePos->ReadChFramePos( rStrm );
3508 break;
3509 case EXC_ID_CHAXIS:
3510 ReadChAxis( rStrm );
3511 break;
3512 case EXC_ID_CHTEXT:
3513 ReadChText( rStrm );
3514 break;
3515 case EXC_ID_CHPLOTFRAME:
3516 ReadChPlotFrame( rStrm );
3517 break;
3518 case EXC_ID_CHTYPEGROUP:
3519 ReadChTypeGroup( rStrm );
3520 break;
3524 void XclImpChAxesSet::Finalize()
3526 if( IsValidAxesSet() )
3528 // finalize chart type groups, erase empty groups without series
3529 XclImpChTypeGroupMap aValidGroups;
3530 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3532 XclImpChTypeGroupRef xTypeGroup = aIt->second;
3533 xTypeGroup->Finalize();
3534 if( xTypeGroup->IsValidGroup() )
3535 aValidGroups.insert(
3536 XclImpChTypeGroupMap::value_type(aIt->first, xTypeGroup));
3538 maTypeGroups.swap( aValidGroups );
3541 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3542 if( IsValidAxesSet() )
3544 // always create missing axis objects
3545 if( !mxXAxis )
3546 mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) );
3547 if( !mxYAxis )
3548 mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) );
3549 if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() )
3550 mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) );
3552 // finalize axes
3553 if( mxXAxis ) mxXAxis->Finalize();
3554 if( mxYAxis ) mxYAxis->Finalize();
3555 if( mxZAxis ) mxZAxis->Finalize();
3557 // finalize axis titles
3558 const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE );
3559 OUString aAutoTitle("Axis Title");
3560 lclFinalizeTitle( mxXAxisTitle, pDefText, aAutoTitle );
3561 lclFinalizeTitle( mxYAxisTitle, pDefText, aAutoTitle );
3562 lclFinalizeTitle( mxZAxisTitle, pDefText, aAutoTitle );
3564 // #i47745# missing plot frame -> invisible border and area
3565 if( !mxPlotFrame )
3566 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3570 XclImpChTypeGroupRef XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3572 XclImpChTypeGroupMap::const_iterator itr = maTypeGroups.find(nGroupIdx);
3573 return itr == maTypeGroups.end() ? XclImpChTypeGroupRef() : itr->second;
3576 XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const
3578 XclImpChTypeGroupRef xTypeGroup;
3579 if( !maTypeGroups.empty() )
3580 xTypeGroup = maTypeGroups.begin()->second;
3581 return xTypeGroup;
3584 XclImpChLegendRef XclImpChAxesSet::GetLegend() const
3586 XclImpChLegendRef xLegend;
3587 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt )
3588 xLegend = aIt->second->GetLegend();
3589 return xLegend;
3592 OUString XclImpChAxesSet::GetSingleSeriesTitle() const
3594 return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : OUString();
3597 void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const
3599 if( IsValidAxesSet() && xDiagram.is() )
3601 // diagram background formatting
3602 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY )
3603 ConvertBackground( xDiagram );
3605 // create the coordinate system, this inserts all chart types and series
3606 Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram );
3607 if( xCoordSystem.is() )
3609 // insert coordinate system, if not already done
3612 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW );
3613 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3614 if( aCoordSystems.getLength() == 0 )
3615 xCoordSystemCont->addCoordinateSystem( xCoordSystem );
3617 catch( Exception& )
3619 OSL_FAIL( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3622 // create the axes with grids and axis titles and insert them into the diagram
3623 ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() );
3624 ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() );
3625 ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 );
3630 void XclImpChAxesSet::ConvertTitlePositions() const
3632 if( mxXAxisTitle )
3633 mxXAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_X ) );
3634 if( mxYAxisTitle )
3635 mxYAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Y ) );
3636 if( mxZAxisTitle )
3637 mxZAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Z ) );
3640 void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm )
3642 XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) );
3643 xAxis->ReadRecordGroup( rStrm );
3645 switch( xAxis->GetAxisType() )
3647 case EXC_CHAXIS_X: mxXAxis = xAxis; break;
3648 case EXC_CHAXIS_Y: mxYAxis = xAxis; break;
3649 case EXC_CHAXIS_Z: mxZAxis = xAxis; break;
3653 void XclImpChAxesSet::ReadChText( XclImpStream& rStrm )
3655 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3656 xText->ReadRecordGroup( rStrm );
3658 switch( xText->GetLinkTarget() )
3660 case EXC_CHOBJLINK_XAXIS: mxXAxisTitle = xText; break;
3661 case EXC_CHOBJLINK_YAXIS: mxYAxisTitle = xText; break;
3662 case EXC_CHOBJLINK_ZAXIS: mxZAxisTitle = xText; break;
3666 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm )
3668 if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() )
3670 mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3671 mxPlotFrame->ReadRecordGroup( rStrm );
3675 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm )
3677 XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
3678 xTypeGroup->ReadRecordGroup( rStrm );
3679 sal_uInt16 nGroupIdx = xTypeGroup->GetGroupIdx();
3680 XclImpChTypeGroupMap::iterator itr = maTypeGroups.lower_bound(nGroupIdx);
3681 if (itr != maTypeGroups.end() && !maTypeGroups.key_comp()(nGroupIdx, itr->first))
3682 // Overwrite the existing element.
3683 itr->second = xTypeGroup;
3684 else
3685 maTypeGroups.insert(
3686 itr, XclImpChTypeGroupMap::value_type(nGroupIdx, xTypeGroup));
3689 Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const
3691 Reference< XCoordinateSystem > xCoordSystem;
3693 /* Try to get existing coordinate system. For now, all series from primary
3694 and secondary axes sets are inserted into one coordinate system. Later,
3695 this should be changed to use one coordinate system for each axes set. */
3696 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY );
3697 if( xCoordSystemCont.is() )
3699 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3700 OSL_ENSURE( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3701 if( aCoordSystems.getLength() > 0 )
3702 xCoordSystem = aCoordSystems[ 0 ];
3705 // create the coordinate system according to the first chart type
3706 if( !xCoordSystem.is() )
3708 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3709 if( xTypeGroup )
3711 xCoordSystem = xTypeGroup->CreateCoordSystem();
3712 // convert 3d chart settings
3713 ScfPropertySet aDiaProp( xDiagram );
3714 xTypeGroup->ConvertChart3d( aDiaProp );
3718 /* Create XChartType objects for all chart type groups. Each group will
3719 add its series to the data provider attached to the chart document. */
3720 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3721 if( xChartTypeCont.is() )
3723 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3724 for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3728 Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx );
3729 if( xChartType.is() )
3730 xChartTypeCont->addChartType( xChartType );
3732 catch( Exception& )
3734 OSL_FAIL( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3739 return xCoordSystem;
3742 void XclImpChAxesSet::ConvertAxis(
3743 XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle,
3744 Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const
3746 if( xChAxis )
3748 // create and attach the axis object
3749 Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis );
3750 if( xAxis.is() )
3752 // create and attach the axis title
3753 if( xChAxisTitle ) try
3755 Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW );
3756 Reference< XTitle > xTitle( xChAxisTitle->CreateTitle(), UNO_SET_THROW );
3757 xTitled->setTitleObject( xTitle );
3759 catch( Exception& )
3761 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3764 // insert axis into coordinate system
3767 sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension();
3768 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3769 xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx );
3771 catch( Exception& )
3773 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3779 Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const
3781 Reference< XAxis > xAxis;
3782 if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() )
3783 xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis );
3784 return xAxis;
3787 void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const
3789 XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3790 if( xTypeGroup && xTypeGroup->Is3dWallChart() )
3792 // wall/floor formatting (3D charts)
3793 if( mxXAxis )
3795 ScfPropertySet aWallProp( xDiagram->getWall() );
3796 mxXAxis->ConvertWall( aWallProp );
3798 if( mxYAxis )
3800 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3801 mxYAxis->ConvertWall( aFloorProp );
3804 else if( mxPlotFrame )
3806 // diagram background formatting
3807 ScfPropertySet aWallProp( xDiagram->getWall() );
3808 mxPlotFrame->Convert( aWallProp );
3812 // The chart object ===========================================================
3814 XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) :
3815 XclImpChRoot( rRoot, *this )
3817 mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3818 mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3821 XclImpChChart::~XclImpChChart()
3825 void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm )
3827 // coordinates are stored as 16.16 fixed point
3828 rStrm >> maRect;
3831 void XclImpChChart::ReadSubRecord( XclImpStream& rStrm )
3833 switch( rStrm.GetRecId() )
3835 case EXC_ID_CHFRAME:
3836 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3837 mxFrame->ReadRecordGroup( rStrm );
3838 break;
3839 case EXC_ID_CHSERIES:
3840 ReadChSeries( rStrm );
3841 break;
3842 case EXC_ID_CHPROPERTIES:
3843 ReadChProperties( rStrm );
3844 break;
3845 case EXC_ID_CHDEFAULTTEXT:
3846 ReadChDefaultText( rStrm );
3847 break;
3848 case EXC_ID_CHAXESSET:
3849 ReadChAxesSet( rStrm );
3850 break;
3851 case EXC_ID_CHTEXT:
3852 ReadChText( rStrm );
3853 break;
3854 case EXC_ID_CHEND:
3855 Finalize(); // finalize the entire chart object
3856 break;
3860 void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm )
3862 sal_uInt16 nTextId = rStrm.ReaduInt16();
3863 if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() )
3865 unique_ptr<XclImpChText> pText(new XclImpChText(GetChRoot()));
3866 pText->ReadRecordGroup(rStrm);
3867 o3tl::ptr_container::insert(maDefTexts, nTextId, std::move(pText));
3871 void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm )
3873 XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
3874 xDataFmt->ReadRecordGroup( rStrm );
3875 if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3877 const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
3878 XclImpChDataFormatMap::iterator itr = maDataFmts.lower_bound(rPos);
3879 if (itr == maDataFmts.end() || maDataFmts.key_comp()(rPos, itr->first))
3880 // No element exists for this data point. Insert it.
3881 maDataFmts.insert(
3882 itr, XclImpChDataFormatMap::value_type(rPos, xDataFmt));
3884 /* Do not overwrite existing data format group, Excel always uses the
3885 first data format group occurring in any CHSERIES group. */
3889 void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
3891 if( !mxFrame )
3892 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3893 mxFrame->UpdateObjFrame( rLineData, rFillData );
3896 XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3898 XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx );
3899 if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx );
3900 if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup();
3901 return xTypeGroup;
3904 const XclImpChText* XclImpChChart::GetDefaultText( XclChTextType eTextType ) const
3906 sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL;
3907 bool bBiff8 = GetBiff() == EXC_BIFF8;
3908 switch( eTextType )
3910 case EXC_CHTEXTTYPE_TITLE: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3911 case EXC_CHTEXTTYPE_LEGEND: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
3912 case EXC_CHTEXTTYPE_AXISTITLE: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3913 case EXC_CHTEXTTYPE_AXISLABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3914 case EXC_CHTEXTTYPE_DATALABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3917 XclImpChTextMap::const_iterator itr = maDefTexts.find(nDefTextId);
3918 return itr == maDefTexts.end() ? NULL : itr->second;
3921 bool XclImpChChart::IsManualPlotArea() const
3923 // there is no real automatic mode in BIFF5 charts
3924 return (GetBiff() <= EXC_BIFF5) || ::get_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3927 void XclImpChChart::Convert( const Reference<XChartDocument>& xChartDoc,
3928 XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
3930 // initialize conversion (locks the model to suppress any internal updates)
3931 InitConversion( xChartDoc, rChartRect );
3933 // chart frame formatting
3934 if( mxFrame )
3936 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3937 mxFrame->Convert( aFrameProp );
3940 // chart title
3941 if( mxTitle ) try
3943 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY_THROW );
3944 Reference< XTitle > xTitle( mxTitle->CreateTitle(), UNO_SET_THROW );
3945 xTitled->setTitleObject( xTitle );
3947 catch( Exception& )
3951 /* Create the diagram object and attach it to the chart document. Currently,
3952 one diagram is used to carry all coordinate systems and data series. */
3953 Reference< XDiagram > xDiagram = CreateDiagram();
3954 xChartDoc->setFirstDiagram( xDiagram );
3956 // coordinate systems and chart types, convert axis settings
3957 mxPrimAxesSet->Convert( xDiagram );
3958 mxSecnAxesSet->Convert( xDiagram );
3960 // legend
3961 if( xDiagram.is() && mxLegend )
3962 xDiagram->setLegend( mxLegend->CreateLegend() );
3964 /* Following all conversions needing the old Chart1 API that involves full
3965 initialization of the chart view. */
3966 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY );
3967 if( xChart1Doc.is() )
3969 Reference< cssc::XDiagram > xDiagram1 = xChart1Doc->getDiagram();
3971 /* Set the 'IncludeHiddenCells' property via the old API as only this
3972 ensures that the data provider and all created sequences get this
3973 flag correctly. */
3974 ScfPropertySet aDiaProp( xDiagram1 );
3975 bool bShowVisCells = ::get_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY );
3976 aDiaProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells );
3978 // plot area position and size (there is no real automatic mode in BIFF5 charts)
3979 XclImpChFramePosRef xPlotAreaPos = mxPrimAxesSet->GetPlotAreaFramePos();
3980 if( IsManualPlotArea() && xPlotAreaPos ) try
3982 const XclChFramePos& rFramePos = xPlotAreaPos->GetFramePosData();
3983 if( (rFramePos.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rFramePos.mnBRMode == EXC_CHFRAMEPOS_PARENT) )
3985 Reference< cssc::XDiagramPositioning > xPositioning( xDiagram1, UNO_QUERY_THROW );
3986 ::com::sun::star::awt::Rectangle aDiagramRect = CalcHmmFromChartRect( rFramePos.maRect );
3987 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
3988 const XclImpChTypeGroup* pFirstTypeGroup = mxPrimAxesSet->GetFirstTypeGroup().get();
3989 if( pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE) )
3990 xPositioning->setDiagramPositionExcludingAxes( aDiagramRect );
3991 else if( pFirstTypeGroup && pFirstTypeGroup->Is3dChart() )
3992 xPositioning->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect );
3993 else
3994 xPositioning->setDiagramPositionIncludingAxes( aDiagramRect );
3997 catch( Exception& )
4001 // positions of all title objects
4002 if( mxTitle )
4003 mxTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE ) );
4004 mxPrimAxesSet->ConvertTitlePositions();
4005 mxSecnAxesSet->ConvertTitlePositions();
4008 // unlock the model
4009 FinishConversion( rDffConv );
4011 // start listening to this chart
4012 ScDocument& rDoc = GetRoot().GetDoc();
4013 if( ScChartListenerCollection* pChartCollection = rDoc.GetChartListenerCollection() )
4015 ::std::unique_ptr< ::std::vector< ScTokenRef > > xRefTokens( new ::std::vector< ScTokenRef > );
4016 for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
4017 (*aIt)->FillAllSourceLinks( *xRefTokens );
4018 if( !xRefTokens->empty() )
4020 ::std::unique_ptr< ScChartListener > xListener( new ScChartListener( rObjName, &rDoc, xRefTokens.release() ) );
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 maProps.mnFlags = rStrm.ReaduInt16();
4039 maProps.mnEmptyMode = rStrm.ReaduInt8();
4042 void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm )
4044 XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) );
4045 xAxesSet->ReadRecordGroup( rStrm );
4046 switch( xAxesSet->GetAxesSetId() )
4048 case EXC_CHAXESSET_PRIMARY: mxPrimAxesSet = xAxesSet; break;
4049 case EXC_CHAXESSET_SECONDARY: mxSecnAxesSet = xAxesSet; break;
4053 void XclImpChChart::ReadChText( XclImpStream& rStrm )
4055 XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
4056 xText->ReadRecordGroup( rStrm );
4057 switch( xText->GetLinkTarget() )
4059 case EXC_CHOBJLINK_TITLE:
4060 mxTitle = xText;
4061 break;
4062 case EXC_CHOBJLINK_DATA:
4064 sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx;
4065 if( nSeriesIdx < maSeries.size() )
4066 maSeries[ nSeriesIdx ]->SetDataLabel( xText );
4068 break;
4072 void XclImpChChart::Finalize()
4074 // finalize series (must be done first)
4075 FinalizeSeries();
4076 // #i49218# legend may be attached to primary or secondary axes set
4077 mxLegend = mxPrimAxesSet->GetLegend();
4078 if( !mxLegend )
4079 mxLegend = mxSecnAxesSet->GetLegend();
4080 if( mxLegend )
4081 mxLegend->Finalize();
4082 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
4083 mxPrimAxesSet->Finalize();
4084 mxSecnAxesSet->Finalize();
4085 // formatting of all series
4086 FinalizeDataFormats();
4087 // #i47745# missing frame -> invisible border and area
4088 if( !mxFrame )
4089 mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
4090 // chart title
4091 FinalizeTitle();
4094 void XclImpChChart::FinalizeSeries()
4096 for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt )
4098 XclImpChSeriesRef xSeries = *aSIt;
4099 if( xSeries->HasParentSeries() )
4101 /* Process child series (trend lines and error bars). Data of
4102 child series will be set at the connected parent series. */
4103 if( xSeries->GetParentIdx() < maSeries.size() )
4104 maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries );
4106 else
4108 // insert the series into the related chart type group
4109 if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() )
4110 pTypeGroup->AddSeries( xSeries );
4115 void XclImpChChart::FinalizeDataFormats()
4117 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4118 Each CHDATAFORMAT group specifies the series and data point it is
4119 assigned to. This makes it possible to have a data format that is
4120 related to another series, e.g. a CHDATAFORMAT group for series 2 is
4121 part of a CHSERIES group that describes series 1. Therefore the chart
4122 itself has collected all CHDATAFORMAT groups to be able to store data
4123 format groups for series that have not been imported at that time. This
4124 loop finally assigns these groups to the related series. */
4125 for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt )
4127 sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx;
4128 if( nSeriesIdx < maSeries.size() )
4129 maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second );
4132 /* #i51639# (part 2): Finalize data formats of all series. This adds for
4133 example missing CHDATAFORMAT groups for entire series that are needed
4134 for automatic colors of lines and areas. */
4135 for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt )
4136 (*aVIt)->FinalizeDataFormats();
4139 void XclImpChChart::FinalizeTitle()
4141 // special handling for auto-generated title
4142 OUString aAutoTitle;
4143 if( !mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString()) )
4145 // automatic title from first series name (if there are no series on secondary axes set)
4146 if( !mxSecnAxesSet->IsValidAxesSet() )
4147 aAutoTitle = mxPrimAxesSet->GetSingleSeriesTitle();
4148 if( mxTitle || (!aAutoTitle.isEmpty()) )
4150 if( !mxTitle )
4151 mxTitle.reset( new XclImpChText( GetChRoot() ) );
4152 if( aAutoTitle.isEmpty() )
4153 aAutoTitle = "Chart Title";
4157 // will reset mxTitle, if it does not contain a string and no auto title exists
4158 lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ), aAutoTitle );
4161 Reference< XDiagram > XclImpChChart::CreateDiagram() const
4163 // create a diagram object
4164 Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY );
4166 // convert global chart settings
4167 ScfPropertySet aDiaProp( xDiagram );
4169 // treatment of missing values
4170 using namespace cssc::MissingValueTreatment;
4171 sal_Int32 nMissingValues = LEAVE_GAP;
4172 switch( maProps.mnEmptyMode )
4174 case EXC_CHPROPS_EMPTY_SKIP: nMissingValues = LEAVE_GAP; break;
4175 case EXC_CHPROPS_EMPTY_ZERO: nMissingValues = USE_ZERO; break;
4176 case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE; break;
4178 aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues );
4180 return xDiagram;
4183 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot& rRoot, bool bOwnTab ) :
4184 XclImpDrawing( rRoot, bOwnTab ), // sheet charts may contain OLE objects
4185 mnScTab( rRoot.GetCurrScTab() ),
4186 mbOwnTab( bOwnTab )
4190 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter& rDffConv,
4191 const Reference< XModel >& rxModel, const Rectangle& rChartRect )
4193 maChartRect = rChartRect; // needed in CalcAnchorRect() callback
4195 SdrModel* pSdrModel = 0;
4196 SdrPage* pSdrPage = 0;
4197 if( mbOwnTab )
4199 // chart sheet: insert all shapes into the sheet, not into the chart object
4200 pSdrModel = GetDoc().GetDrawLayer();
4201 pSdrPage = GetSdrPage( mnScTab );
4203 else
4205 // embedded chart object: insert all shapes into the chart
4208 Reference< XDrawPageSupplier > xDrawPageSupp( rxModel, UNO_QUERY_THROW );
4209 Reference< XDrawPage > xDrawPage( xDrawPageSupp->getDrawPage(), UNO_SET_THROW );
4210 pSdrPage = ::GetSdrPageFromXDrawPage( xDrawPage );
4211 pSdrModel = pSdrPage ? pSdrPage->GetModel() : 0;
4213 catch( Exception& )
4218 if( pSdrModel && pSdrPage )
4219 ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
4222 Rectangle XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool bDffAnchor ) const
4224 /* In objects with DFF client anchor, the position of the shape is stored
4225 in the cell address components of the client anchor. In old BIFF3-BIFF5
4226 objects, the position is stored in the offset components of the anchor. */
4227 Rectangle aRect(
4228 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnCol : rAnchor.mnLX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
4229 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnRow : rAnchor.mnTY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ),
4230 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnCol : rAnchor.mnRX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
4231 static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnRow : rAnchor.mnBY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ) );
4232 aRect.Justify();
4233 // move shapes into chart area for sheet charts
4234 if( mbOwnTab )
4235 aRect.Move( maChartRect.Left(), maChartRect.Top() );
4236 return aRect;
4239 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase& )
4243 XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) :
4244 XclImpRoot( rRoot ),
4245 mbOwnTab( bOwnTab ),
4246 mbIsPivotChart( false )
4250 XclImpChart::~XclImpChart()
4254 void XclImpChart::ReadChartSubStream( XclImpStream& rStrm )
4256 XclImpPageSettings& rPageSett = GetPageSettings();
4257 XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
4259 bool bLoop = true;
4260 while( bLoop && rStrm.StartNextRecord() )
4262 // page settings - only for charts in entire sheet
4263 if( mbOwnTab ) switch( rStrm.GetRecId() )
4265 case EXC_ID_HORPAGEBREAKS:
4266 case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( rStrm ); break;
4267 case EXC_ID_HEADER:
4268 case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( rStrm ); break;
4269 case EXC_ID_LEFTMARGIN:
4270 case EXC_ID_RIGHTMARGIN:
4271 case EXC_ID_TOPMARGIN:
4272 case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( rStrm ); break;
4273 case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( rStrm ); break;
4274 case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm ); break;
4275 case EXC_ID_HCENTER:
4276 case EXC_ID_VCENTER: rPageSett.ReadCenter( rStrm ); break;
4277 case EXC_ID_SETUP: rPageSett.ReadSetup( rStrm ); break;
4278 case EXC_ID8_IMGDATA: rPageSett.ReadImgData( rStrm ); break;
4280 case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( rStrm, true );break;
4281 case EXC_ID_SCL: rTabViewSett.ReadScl( rStrm ); break;
4283 case EXC_ID_SHEETEXT: //0x0862
4285 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4286 XclImpPalette& rPal = GetPalette();
4287 rTabViewSett.ReadTabBgColor( rStrm, rPal);
4289 break;
4291 case EXC_ID_CODENAME: ReadCodeName( rStrm, false ); break;
4294 // common records
4295 switch( rStrm.GetRecId() )
4297 case EXC_ID_EOF: bLoop = false; break;
4299 // #i31882# ignore embedded chart objects
4300 case EXC_ID2_BOF:
4301 case EXC_ID3_BOF:
4302 case EXC_ID4_BOF:
4303 case EXC_ID5_BOF: XclTools::SkipSubStream( rStrm ); break;
4305 case EXC_ID_CHCHART: ReadChChart( rStrm ); break;
4307 case EXC_ID8_CHPIVOTREF:
4308 GetTracer().TracePivotChartExists();
4309 mbIsPivotChart = true;
4310 break;
4312 // BIFF specific records
4313 default: switch( GetBiff() )
4315 case EXC_BIFF5: switch( rStrm.GetRecId() )
4317 case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
4319 break;
4320 case EXC_BIFF8: switch( rStrm.GetRecId() )
4322 case EXC_ID_MSODRAWING: GetChartDrawing().ReadMsoDrawing( rStrm ); break;
4323 // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4324 case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
4326 break;
4327 default:;
4333 void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
4335 if( !mxChartData )
4336 mxChartData.reset( new XclImpChChart( GetRoot() ) );
4337 mxChartData->UpdateObjFrame( rLineData, rFillData );
4340 sal_Size XclImpChart::GetProgressSize() const
4342 return
4343 (mxChartData ? XclImpChChart::GetProgressSize() : 0) +
4344 (mxChartDrawing ? mxChartDrawing->GetProgressSize() : 0);
4347 void XclImpChart::Convert( Reference< XModel > xModel, XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
4349 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
4350 if( xChartDoc.is() )
4352 if( mxChartData )
4353 mxChartData->Convert( xChartDoc, rDffConv, rObjName, rChartRect );
4354 if( mxChartDrawing )
4355 mxChartDrawing->ConvertObjects( rDffConv, xModel, rChartRect );
4359 XclImpChartDrawing& XclImpChart::GetChartDrawing()
4361 if( !mxChartDrawing )
4362 mxChartDrawing.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab ) );
4363 return *mxChartDrawing;
4366 void XclImpChart::ReadChChart( XclImpStream& rStrm )
4368 mxChartData.reset( new XclImpChChart( GetRoot() ) );
4369 mxChartData->ReadRecordGroup( rStrm );
4372 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */