1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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 <comphelper/processfactory.hxx>
78 #include <o3tl/numeric.hxx>
79 #include <o3tl/unit_conversion.hxx>
80 #include <sfx2/objsh.hxx>
81 #include <svx/svdpage.hxx>
82 #include <svx/unoapi.hxx>
83 #include <sal/log.hxx>
84 #include <tools/helpers.hxx>
86 #include <document.hxx>
87 #include <drwlayer.hxx>
88 #include <tokenarray.hxx>
89 #include <compiler.hxx>
90 #include <reftokenhelper.hxx>
91 #include <chartlis.hxx>
92 #include <globstr.hrc>
93 #include <scresid.hxx>
94 #include <xltracer.hxx>
95 #include <xltools.hxx>
96 #include <xistream.hxx>
97 #include <xiformula.hxx>
98 #include <xistyle.hxx>
100 #include <xiview.hxx>
102 using ::com::sun::star::uno::Any
;
103 using ::com::sun::star::uno::Reference
;
104 using ::com::sun::star::uno::Sequence
;
105 using ::com::sun::star::uno::UNO_QUERY
;
106 using ::com::sun::star::uno::UNO_QUERY_THROW
;
107 using ::com::sun::star::uno::UNO_SET_THROW
;
108 using ::com::sun::star::uno::Exception
;
109 using ::com::sun::star::beans::XPropertySet
;
110 using ::com::sun::star::frame::XModel
;
111 using ::com::sun::star::util::XNumberFormatsSupplier
;
112 using ::com::sun::star::drawing::XDrawPage
;
113 using ::com::sun::star::drawing::XDrawPageSupplier
;
114 using ::com::sun::star::drawing::XShape
;
116 using namespace ::com::sun::star::chart2
;
118 using ::com::sun::star::chart2::data::XDataProvider
;
119 using ::com::sun::star::chart2::data::XDataReceiver
;
120 using ::com::sun::star::chart2::data::XDataSequence
;
121 using ::com::sun::star::chart2::data::XDataSink
;
122 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
123 using ::com::sun::star::chart2::data::LabeledDataSequence
;
125 using ::formula::FormulaToken
;
126 using ::formula::FormulaTokenArrayPlainIterator
;
127 using ::std::unique_ptr
;
129 namespace cssc
= ::com::sun::star::chart
;
130 namespace cssc2
= ::com::sun::star::chart2
;
132 // Helpers ====================================================================
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();
145 void lclSetValueOrClearAny( Any
& rAny
, double fValue
, bool bClear
)
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
)
164 case EXC_CHDATERANGE_DAYS
:
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
) ) );
171 OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
176 void lclConvertTimeValue( const XclImpRoot
& rRoot
, Any
& rAny
, sal_uInt16 nValue
, bool bAuto
, sal_uInt16 nTimeUnit
)
181 rAny
<<= lclGetSerialDay( rRoot
, nValue
, nTimeUnit
);
184 sal_Int32
lclGetApiTimeUnit( sal_uInt16 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) )
201 rInterval
<<= cssc::TimeInterval( nValue
, lclGetApiTimeUnit( nTimeUnit
) );
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 explicit XclImpChRootData( XclImpChChart
& rChartData
) : mrChartData( rChartData
) {}
216 XclImpChRoot::XclImpChRoot( const XclImpRoot
& rRoot
, XclImpChChart
& rChartData
) :
218 mxChData( std::make_shared
<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 tools::Rectangle
& rChartRect
) const
266 // create formatting object tables
267 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
269 // lock the model to suppress any internal updates
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
);
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
);
293 Reference
< XModel
> xModel
= mxChData
->mxChartDoc
;
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 css::awt::Rectangle
XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle
& rRect
) const
323 return css::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 tools::Long nWidth
= mxChData
->maChartRect
.GetWidth();
334 throw o3tl::divide_by_zero();
335 return static_cast<double>(nPosX
) / nWidth
;
338 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY
) const
340 const tools::Long nHeight
= mxChData
->maChartRect
.GetHeight();
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
->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
)
403 // read the CHBEGIN record, may be used for special initial processing
404 rStrm
.StartNextRecord();
405 ReadSubRecord( rStrm
);
407 // read the nested records
409 while( bLoop
&& rStrm
.StartNextRecord() )
411 sal_uInt16 nRecId
= rStrm
.GetRecId();
412 bLoop
= nRecId
!= EXC_ID_CHEND
;
413 // skip unsupported nested blocks
414 if( nRecId
== EXC_ID_CHBEGIN
)
417 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
)
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
);
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
);
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
);
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
);
517 rRoot
.ConvertAreaFormat( rPropSet
, maData
, rFmtInfo
.mePropMode
);
521 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot
& rRoot
) :
522 mnDffFillType( mso_fillSolid
)
525 std::make_shared
<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() );
535 aPropSet
.FillToItemSet( *maData
.mxItemSet
);
536 // get fill type from DFF property set
537 mnDffFillType
= aPropSet
.GetPropertyValue( DFF_Prop_fillType
);
540 void XclImpChEscherFormat::ReadSubRecord( XclImpStream
& rStrm
)
542 switch( rStrm
.GetRecId() )
544 case EXC_ID_CHPICFORMAT
:
545 maPicFmt
.mnBmpMode
= rStrm
.ReaduInt16();
547 maPicFmt
.mnFlags
= rStrm
.ReaduInt16();
548 maPicFmt
.mfScale
= rStrm
.ReadDouble();
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
: nullptr, mnDffFillType
, rFmtInfo
.mePropMode
);
560 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo
& rFmtInfo
)
562 if( !rFmtInfo
.mbCreateDefFrame
)
565 switch( rFmtInfo
.meDefFrameType
)
567 case EXC_CHFRAMETYPE_AUTO
:
568 mxLineFmt
= new XclImpChLineFormat();
569 if( rFmtInfo
.mbIsFrame
)
570 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
572 case EXC_CHFRAMETYPE_INVISIBLE
:
574 XclChLineFormat aLineFmt
;
575 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, false );
576 aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
577 mxLineFmt
= new XclImpChLineFormat( aLineFmt
);
578 if( rFmtInfo
.mbIsFrame
)
580 XclChAreaFormat aAreaFmt
;
581 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, false );
582 aAreaFmt
.mnPattern
= EXC_PATT_NONE
;
583 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>( aAreaFmt
);
588 OSL_FAIL( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
592 void XclImpChFrameBase::ReadSubRecord( XclImpStream
& rStrm
)
594 switch( rStrm
.GetRecId() )
596 case EXC_ID_CHLINEFORMAT
:
597 mxLineFmt
= new XclImpChLineFormat();
598 mxLineFmt
->ReadChLineFormat( rStrm
);
600 case EXC_ID_CHAREAFORMAT
:
601 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
602 mxAreaFmt
->ReadChAreaFormat( rStrm
);
604 case EXC_ID_CHESCHERFORMAT
:
605 mxEscherFmt
= std::make_shared
<XclImpChEscherFormat
>( rStrm
.GetRoot() );
606 mxEscherFmt
->ReadRecordGroup( rStrm
);
611 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot
& rRoot
,
612 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
615 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
618 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot
& rRoot
,
619 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
621 if( rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
623 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
625 mxEscherFmt
->Convert( rRoot
, rPropSet
, eObjType
, bUsePicFmt
);
627 mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
631 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot
& rRoot
,
632 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
634 ConvertLineBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
635 ConvertAreaBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
, bUsePicFmt
);
638 XclImpChFrame::XclImpChFrame( const XclImpChRoot
& rRoot
, XclChObjectType eObjType
) :
639 XclImpChFrameBase( rRoot
.GetFormatInfo( eObjType
) ),
640 XclImpChRoot( rRoot
),
641 meObjType( eObjType
)
645 void XclImpChFrame::ReadHeaderRecord( XclImpStream
& rStrm
)
647 maData
.mnFormat
= rStrm
.ReaduInt16();
648 maData
.mnFlags
= rStrm
.ReaduInt16();
651 void XclImpChFrame::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
653 const XclImpPalette
& rPal
= GetPalette();
655 if( rLineData
.IsVisible() && (!mxLineFmt
|| !mxLineFmt
->HasLine()) )
658 XclChLineFormat aLineFmt
;
659 aLineFmt
.maColor
= rPal
.GetColor( rLineData
.mnColorIdx
);
660 switch( rLineData
.mnStyle
)
662 case EXC_OBJ_LINE_SOLID
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
; break;
663 case EXC_OBJ_LINE_DASH
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASH
; break;
664 case EXC_OBJ_LINE_DOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DOT
; break;
665 case EXC_OBJ_LINE_DASHDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOT
; break;
666 case EXC_OBJ_LINE_DASHDOTDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOTDOT
; break;
667 case EXC_OBJ_LINE_MEDTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_MEDTRANS
; break;
668 case EXC_OBJ_LINE_DARKTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DARKTRANS
; break;
669 case EXC_OBJ_LINE_LIGHTTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_LIGHTTRANS
; break;
670 case EXC_OBJ_LINE_NONE
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
; break;
671 default: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
;
673 switch( rLineData
.mnWidth
)
675 case EXC_OBJ_LINE_HAIR
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
; break;
676 case EXC_OBJ_LINE_THIN
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_SINGLE
; break;
677 case EXC_OBJ_LINE_MEDIUM
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_DOUBLE
; break;
678 case EXC_OBJ_LINE_THICK
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_TRIPLE
; break;
679 default: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
;
681 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, rLineData
.IsAuto() );
682 mxLineFmt
= new XclImpChLineFormat( aLineFmt
);
685 if( rFillData
.IsFilled() && (!mxAreaFmt
|| !mxAreaFmt
->HasArea()) && !mxEscherFmt
)
688 XclChAreaFormat aAreaFmt
;
689 aAreaFmt
.maPattColor
= rPal
.GetColor( rFillData
.mnPattColorIdx
);
690 aAreaFmt
.maBackColor
= rPal
.GetColor( rFillData
.mnBackColorIdx
);
691 aAreaFmt
.mnPattern
= rFillData
.mnPattern
;
692 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, rFillData
.IsAuto() );
693 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>( aAreaFmt
);
697 void XclImpChFrame::Convert( ScfPropertySet
& rPropSet
, bool bUsePicFmt
) const
699 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
, EXC_CHDATAFORMAT_UNKNOWN
, bUsePicFmt
);
702 // Source links ===============================================================
706 /** Creates a labeled data sequence object, adds link for series title if present. */
707 Reference
< XLabeledDataSequence
> lclCreateLabeledDataSequence(
708 const XclImpChSourceLinkRef
& xValueLink
, const OUString
& rValueRole
,
709 const XclImpChSourceLink
* pTitleLink
= nullptr )
711 // create data sequence for values and title
712 Reference
< XDataSequence
> xValueSeq
;
714 xValueSeq
= xValueLink
->CreateDataSequence( rValueRole
);
715 Reference
< XDataSequence
> xTitleSeq
;
717 xTitleSeq
= pTitleLink
->CreateDataSequence( EXC_CHPROP_ROLE_LABEL
);
719 // create the labeled data sequence, if values or title are present
720 Reference
< XLabeledDataSequence
> xLabeledSeq
;
721 if( xValueSeq
.is() || xTitleSeq
.is() )
722 xLabeledSeq
= LabeledDataSequence::create(comphelper::getProcessComponentContext());
723 if( xLabeledSeq
.is() )
726 xLabeledSeq
->setValues( xValueSeq
);
728 xLabeledSeq
->setLabel( xTitleSeq
);
735 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot
& rRoot
) :
736 XclImpChRoot( rRoot
)
740 XclImpChSourceLink::~XclImpChSourceLink()
744 void XclImpChSourceLink::ReadChSourceLink( XclImpStream
& rStrm
)
746 maData
.mnDestType
= rStrm
.ReaduInt8();
747 maData
.mnLinkType
= rStrm
.ReaduInt8();
748 maData
.mnFlags
= rStrm
.ReaduInt16();
749 maData
.mnNumFmtIdx
= rStrm
.ReaduInt16();
751 mxTokenArray
.reset();
752 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET
)
755 XclTokenArray aXclTokArr
;
758 // convert BIFF formula tokens to Calc token array
759 if( std::unique_ptr
<ScTokenArray
> pTokens
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aXclTokArr
) )
760 mxTokenArray
= std::move( pTokens
);
763 // try to read a following CHSTRING record
764 if( (rStrm
.GetNextRecId() == EXC_ID_CHSTRING
) && rStrm
.StartNextRecord() )
766 mxString
= std::make_shared
<XclImpString
>();
768 mxString
->Read( rStrm
, XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
772 void XclImpChSourceLink::SetString( const OUString
& rString
)
775 mxString
= std::make_shared
<XclImpString
>();
776 mxString
->SetText( rString
);
779 void XclImpChSourceLink::SetTextFormats( XclFormatRunVec
&& rFormats
)
782 mxString
->SetFormats( std::move(rFormats
) );
785 sal_uInt16
XclImpChSourceLink::GetCellCount() const
787 sal_uInt32 nCellCount
= 0;
790 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
791 for( const FormulaToken
* pToken
= aIter
.First(); pToken
; pToken
= aIter
.Next() )
793 switch( pToken
->GetType() )
795 case ::formula::svSingleRef
:
796 case ::formula::svExternalSingleRef
:
800 case ::formula::svDoubleRef
:
801 case ::formula::svExternalDoubleRef
:
804 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
805 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(GetRoot().GetDoc(), ScAddress());
806 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(GetRoot().GetDoc(), ScAddress());
807 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
808 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
809 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
810 nCellCount
+= nCols
* nRows
* nTabs
;
817 return limit_cast
< sal_uInt16
>( nCellCount
);
820 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
822 bool bLinkToSource
= ::get_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
823 sal_uInt32 nScNumFmt
= bLinkToSource
? GetNumFmtBuffer().GetScFormat( maData
.mnNumFmtIdx
) : NUMBERFORMAT_ENTRY_NOT_FOUND
;
824 OUString aPropName
= bPercent
? OUString( EXC_CHPROP_PERCENTAGENUMFMT
) : OUString( EXC_CHPROP_NUMBERFORMAT
);
825 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
826 rPropSet
.SetProperty( aPropName
, static_cast< sal_Int32
>( nScNumFmt
) );
828 // restore 'link to source' at data point (series may contain manual number format)
829 rPropSet
.SetAnyProperty( aPropName
, Any() );
832 Reference
< XDataSequence
> XclImpChSourceLink::CreateDataSequence( const OUString
& rRole
) const
834 Reference
< XDataSequence
> xDataSeq
;
835 Reference
< XDataProvider
> xDataProv
= GetDataProvider();
840 ScCompiler
aComp( GetDoc(), ScAddress(), *mxTokenArray
, GetDoc().GetGrammar() );
841 OUStringBuffer aRangeRep
;
842 aComp
.CreateStringFromTokenArray( aRangeRep
);
845 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aRangeRep
.makeStringAndClear() );
847 ScfPropertySet
aSeqProp( xDataSeq
);
848 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
852 // OSL_FAIL( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
855 else if( rRole
== EXC_CHPROP_ROLE_LABEL
&& mxString
&& !mxString
->GetText().isEmpty() )
859 OUString
aString("\"");
860 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aString
+ mxString
->GetText() + aString
);
862 ScfPropertySet
aSeqProp( xDataSeq
);
863 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
865 catch( Exception
& ) { }
871 Sequence
< Reference
< XFormattedString
> > XclImpChSourceLink::CreateStringSequence(
872 const XclImpChRoot
& rRoot
, sal_uInt16 nLeadFontIdx
, const Color
& rLeadFontColor
) const
874 ::std::vector
< Reference
< XFormattedString
> > aStringVec
;
877 for( XclImpStringIterator
aIt( *mxString
); aIt
.Is(); ++aIt
)
879 Reference
< css::chart2::XFormattedString2
> xFmtStr
= css::chart2::FormattedString::create( comphelper::getProcessComponentContext() );
881 xFmtStr
->setString( aIt
.GetPortionText() );
883 // set font formatting and font color
884 ScfPropertySet
aStringProp( xFmtStr
);
885 sal_uInt16 nFontIdx
= aIt
.GetPortionFont();
886 if( (nFontIdx
== EXC_FONT_NOTFOUND
) && (aIt
.GetPortionIndex() == 0) )
887 // leading unformatted portion - use passed font settings
888 rRoot
.ConvertFont( aStringProp
, nLeadFontIdx
, &rLeadFontColor
);
890 rRoot
.ConvertFont( aStringProp
, nFontIdx
);
892 // add string to vector of strings
893 aStringVec
.emplace_back(xFmtStr
);
896 return ScfApiHelper::VectorToSequence( aStringVec
);
899 void XclImpChSourceLink::FillSourceLink( ::std::vector
< ScTokenRef
>& rTokens
) const
905 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
906 for (FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
908 ScTokenRef
pToken(p
->Clone());
909 if (ScRefTokenHelper::isRef(pToken
))
910 // This is a reference token. Store it.
911 ScRefTokenHelper::join(&GetRoot().GetDoc(), rTokens
, pToken
, ScAddress());
915 // Text =======================================================================
917 XclImpChFontBase::~XclImpChFontBase()
921 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
923 Color aFontColor
= GetFontColor();
924 rRoot
.ConvertFont( rPropSet
, GetFontIndex(), &aFontColor
);
927 void XclImpChFontBase::ConvertRotationBase( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
929 XclChPropSetHelper::WriteRotationProperties( rPropSet
, GetRotation(), bSupportsStacked
);
932 XclImpChFont::XclImpChFont() :
933 mnFontIdx( EXC_FONT_NOTFOUND
)
937 void XclImpChFont::ReadChFont( XclImpStream
& rStrm
)
939 mnFontIdx
= rStrm
.ReaduInt16();
942 XclImpChText::XclImpChText( const XclImpChRoot
& rRoot
) :
943 XclImpChRoot( rRoot
)
947 void XclImpChText::ReadHeaderRecord( XclImpStream
& rStrm
)
949 maData
.mnHAlign
= rStrm
.ReaduInt8();
950 maData
.mnVAlign
= rStrm
.ReaduInt8();
951 maData
.mnBackMode
= rStrm
.ReaduInt16();
952 rStrm
>> maData
.maTextColor
954 maData
.mnFlags
= rStrm
.ReaduInt16();
956 if( GetBiff() == EXC_BIFF8
)
958 // BIFF8: index into palette used instead of RGB data
959 maData
.maTextColor
= GetPalette().GetColor( rStrm
.ReaduInt16() );
960 // placement and rotation
961 maData
.mnFlags2
= rStrm
.ReaduInt16();
962 maData
.mnRotation
= rStrm
.ReaduInt16();
966 // BIFF2-BIFF7: get rotation from text orientation
967 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 8, 3 );
968 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
972 void XclImpChText::ReadSubRecord( XclImpStream
& rStrm
)
974 switch( rStrm
.GetRecId() )
976 case EXC_ID_CHFRAMEPOS
:
977 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
978 mxFramePos
->ReadChFramePos( rStrm
);
981 mxFont
= std::make_shared
<XclImpChFont
>();
982 mxFont
->ReadChFont( rStrm
);
984 case EXC_ID_CHFORMATRUNS
:
985 if( GetBiff() == EXC_BIFF8
)
986 XclImpString::ReadFormats( rStrm
, maFormats
);
988 case EXC_ID_CHSOURCELINK
:
989 mxSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
990 mxSrcLink
->ReadChSourceLink( rStrm
);
993 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_TEXT
);
994 mxFrame
->ReadRecordGroup( rStrm
);
996 case EXC_ID_CHOBJECTLINK
:
997 maObjLink
.mnTarget
= rStrm
.ReaduInt16();
998 maObjLink
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
999 maObjLink
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
1001 case EXC_ID_CHFRLABELPROPS
:
1002 ReadChFrLabelProps( rStrm
);
1005 if( mxSrcLink
&& !maFormats
.empty() )
1006 mxSrcLink
->SetTextFormats( std::vector(maFormats
) );
1011 sal_uInt16
XclImpChText::GetFontIndex() const
1013 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
1016 Color
XclImpChText::GetFontColor() const
1018 return ::get_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextColor
;
1021 sal_uInt16
XclImpChText::GetRotation() const
1023 return maData
.mnRotation
;
1026 void XclImpChText::SetString( const OUString
& rString
)
1029 mxSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
1030 mxSrcLink
->SetString( rString
);
1033 void XclImpChText::UpdateText( const XclImpChText
* pParentText
)
1038 // update missing members
1040 mxFrame
= pParentText
->mxFrame
;
1043 mxFont
= pParentText
->mxFont
;
1044 // text color is taken from CHTEXT record, not from font in CHFONT
1045 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, ::get_flag( pParentText
->maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
) );
1046 maData
.maTextColor
= pParentText
->maData
.maTextColor
;
1050 void XclImpChText::UpdateDataLabel( bool bCateg
, bool bValue
, bool bPercent
)
1052 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bCateg
);
1053 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bValue
);
1054 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bPercent
);
1055 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bCateg
&& bPercent
);
1056 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bCateg
&& !bValue
&& !bPercent
);
1059 void XclImpChText::ConvertFont( ScfPropertySet
& rPropSet
) const
1061 ConvertFontBase( GetChRoot(), rPropSet
);
1064 void XclImpChText::ConvertRotation( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
1066 ConvertRotationBase( rPropSet
, bSupportsStacked
);
1069 void XclImpChText::ConvertFrame( ScfPropertySet
& rPropSet
) const
1072 mxFrame
->Convert( rPropSet
);
1075 void XclImpChText::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
1078 mxSrcLink
->ConvertNumFmt( rPropSet
, bPercent
);
1081 void XclImpChText::ConvertDataLabel( ScfPropertySet
& rPropSet
, const XclChTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1083 // existing CHFRLABELPROPS record wins over flags from CHTEXT
1084 sal_uInt16 nShowFlags
= mxLabelProps
? mxLabelProps
->mnFlags
: maData
.mnFlags
;
1085 sal_uInt16 SHOWANYCATEG
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWCATEG
: (EXC_CHTEXT_SHOWCATEGPERC
| EXC_CHTEXT_SHOWCATEG
);
1086 sal_uInt16 SHOWANYVALUE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWVALUE
: EXC_CHTEXT_SHOWVALUE
;
1087 sal_uInt16 SHOWANYPERCENT
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWPERCENT
: (EXC_CHTEXT_SHOWPERCENT
| EXC_CHTEXT_SHOWCATEGPERC
);
1088 sal_uInt16 SHOWANYBUBBLE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWBUBBLE
: EXC_CHTEXT_SHOWBUBBLE
;
1090 // get raw flags for label values
1091 bool bShowNone
= IsDeleted();
1092 bool bShowCateg
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYCATEG
);
1093 bool bShowPercent
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYPERCENT
);
1094 bool bShowValue
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYVALUE
);
1095 bool bShowBubble
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYBUBBLE
);
1097 // adjust to Chart2 behaviour
1098 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
1099 bShowValue
= bShowBubble
; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1102 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
;
1103 bool bShowSymbol
= bShowAny
&& ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
);
1105 // create API struct for label values, set API label separator
1106 cssc2::DataPointLabel
aPointLabel( bShowValue
, bShowPercent
, bShowCateg
, bShowSymbol
, false, false );
1107 rPropSet
.SetProperty( EXC_CHPROP_LABEL
, aPointLabel
);
1108 OUString aSep
= mxLabelProps
? mxLabelProps
->maSeparator
: OUString('\n');
1109 if( aSep
.isEmpty() )
1111 rPropSet
.SetStringProperty( EXC_CHPROP_LABELSEPARATOR
, aSep
);
1113 // text properties of attached label
1117 ConvertFont( rPropSet
);
1118 ConvertRotation( rPropSet
, false );
1120 using namespace cssc::DataLabelPlacement
;
1121 sal_Int32 nPlacement
= rTypeInfo
.mnDefaultLabelPos
;
1122 switch( ::extract_value
< sal_uInt16
>( maData
.mnFlags2
, 0, 4 ) )
1124 case EXC_CHTEXT_POS_DEFAULT
: nPlacement
= rTypeInfo
.mnDefaultLabelPos
; break;
1125 case EXC_CHTEXT_POS_OUTSIDE
: nPlacement
= OUTSIDE
; break;
1126 case EXC_CHTEXT_POS_INSIDE
: nPlacement
= INSIDE
; break;
1127 case EXC_CHTEXT_POS_CENTER
: nPlacement
= CENTER
; break;
1128 case EXC_CHTEXT_POS_AXIS
: nPlacement
= NEAR_ORIGIN
; break;
1129 case EXC_CHTEXT_POS_ABOVE
: nPlacement
= TOP
; break;
1130 case EXC_CHTEXT_POS_BELOW
: nPlacement
= BOTTOM
; break;
1131 case EXC_CHTEXT_POS_LEFT
: nPlacement
= LEFT
; break;
1132 case EXC_CHTEXT_POS_RIGHT
: nPlacement
= RIGHT
; break;
1133 case EXC_CHTEXT_POS_AUTO
: nPlacement
= AVOID_OVERLAP
; break;
1135 sal_Int32 nGlobalPlacement
= 0;
1136 if ( ( nPlacement
== rTypeInfo
.mnDefaultLabelPos
) && pGlobalPropSet
&&
1137 pGlobalPropSet
->GetProperty( nGlobalPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1138 nPlacement
= nGlobalPlacement
;
1140 rPropSet
.SetProperty( EXC_CHPROP_LABELPLACEMENT
, nPlacement
);
1141 // label number format (percentage format wins over value format)
1142 if( bShowPercent
|| bShowValue
)
1143 ConvertNumFmt( rPropSet
, bShowPercent
);
1146 Reference
< XTitle
> XclImpChText::CreateTitle() const
1148 Reference
< XTitle
> xTitle
;
1149 if( mxSrcLink
&& mxSrcLink
->HasString() )
1151 // create the formatted strings
1152 Sequence
< Reference
< XFormattedString
> > aStringSeq(
1153 mxSrcLink
->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1154 if( aStringSeq
.hasElements() )
1156 // create the title object
1157 xTitle
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE
), UNO_QUERY
);
1160 // set the formatted strings
1161 xTitle
->setText( aStringSeq
);
1162 // more title formatting properties
1163 ScfPropertySet
aTitleProp( xTitle
);
1164 ConvertFrame( aTitleProp
);
1165 ConvertRotation( aTitleProp
, true );
1172 void XclImpChText::ConvertTitlePosition( const XclChTextKey
& rTitleKey
) const
1174 if( !mxFramePos
) return;
1176 const XclChFramePos
& rPosData
= mxFramePos
->GetFramePosData();
1177 OSL_ENSURE( (rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rPosData
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
),
1178 "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1180 /* Check if title is moved manually. To get the actual position of the
1181 title, we do some kind of hack and use the values from the CHTEXT
1182 record, effectively ignoring the contents of the CHFRAMEPOS record
1183 which contains the position relative to the default title position
1184 (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1185 Especially when it comes to axis titles, things would become very
1186 complicated here, because the relative title position is stored in a
1187 measurement unit that is dependent on the size of the inner plot area,
1188 the interpretation of the X and Y coordinate is dependent on the
1189 direction of the axis, and in 3D charts, and the title default
1190 positions are dependent on the 3D view settings (rotation, elevation,
1191 and perspective). Thus, it is easier to assume that the creator has
1192 written out the correct absolute position and size of the title in the
1193 CHTEXT record. This is assured by checking that the shape size stored
1194 in the CHTEXT record is non-zero. */
1195 if( !((rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) &&
1196 ((rPosData
.maRect
.mnX
!= 0) || (rPosData
.maRect
.mnY
!= 0)) &&
1197 (maData
.maRect
.mnWidth
> 0) && (maData
.maRect
.mnHeight
> 0)) )
1202 Reference
< XShape
> xTitleShape( GetTitleShape( rTitleKey
), UNO_SET_THROW
);
1203 // the call to XShape.getSize() may recalc the chart view
1204 css::awt::Size aTitleSize
= xTitleShape
->getSize();
1205 // rotated titles need special handling...
1206 Degree100 nScRot
= XclTools::GetScRotation( GetRotation(), 0_deg100
);
1207 double fRad
= toRadians(nScRot
);
1208 double fSin
= fabs( sin( fRad
) );
1209 // calculate the title position from the values in the CHTEXT record
1210 css::awt::Point
aTitlePos(
1211 CalcHmmFromChartX( maData
.maRect
.mnX
),
1212 CalcHmmFromChartY( maData
.maRect
.mnY
) );
1213 // add part of height to X direction, if title is rotated down (clockwise)
1214 if( nScRot
> 18000_deg100
)
1215 aTitlePos
.X
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Height
+ 0.5 );
1216 // add part of width to Y direction, if title is rotated up (counterclockwise)
1217 else if( nScRot
> 0_deg100
)
1218 aTitlePos
.Y
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Width
+ 0.5 );
1219 // set the resulting position at the title shape
1220 xTitleShape
->setPosition( aTitlePos
);
1227 void XclImpChText::ReadChFrLabelProps( XclImpStream
& rStrm
)
1229 if( GetBiff() == EXC_BIFF8
)
1231 mxLabelProps
= std::make_shared
<XclChFrLabelProps
>();
1234 mxLabelProps
->mnFlags
= rStrm
.ReaduInt16();
1235 nSepLen
= rStrm
.ReaduInt16();
1237 mxLabelProps
->maSeparator
= rStrm
.ReadUniString( nSepLen
);
1243 void lclUpdateText( XclImpChTextRef
& rxText
, const XclImpChText
* xDefText
)
1246 rxText
->UpdateText( xDefText
);
1249 rxText
= std::make_shared
<XclImpChText
>(*xDefText
);
1253 void lclFinalizeTitle( XclImpChTextRef
& rxTitle
, const XclImpChText
* pDefText
, const OUString
& rAutoTitle
)
1255 /* Do not update a title, if it is not visible (if rxTitle is null).
1256 Existing reference indicates enabled title. */
1259 if( !rxTitle
->HasString() )
1260 rxTitle
->SetString( rAutoTitle
);
1261 if( rxTitle
->HasString() )
1262 rxTitle
->UpdateText(pDefText
);
1270 // Data series ================================================================
1272 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream
& rStrm
)
1274 rStrm
>> maData
.maLineColor
>> maData
.maFillColor
;
1275 maData
.mnMarkerType
= rStrm
.ReaduInt16();
1276 maData
.mnFlags
= rStrm
.ReaduInt16();
1278 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
1279 if( rRoot
.GetBiff() == EXC_BIFF8
)
1281 // BIFF8: index into palette used instead of RGB data
1282 const XclImpPalette
& rPal
= rRoot
.GetPalette();
1283 maData
.maLineColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1284 maData
.maFillColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1286 maData
.mnMarkerSize
= rStrm
.ReaduInt32();
1290 void XclImpChMarkerFormat::Convert( const XclImpChRoot
& rRoot
,
1291 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
, sal_Int16 nLineWeight
) const
1295 XclChMarkerFormat aMarkerFmt
;
1296 // line and fill color of the symbol are equal to series line color
1297 //TODO: Excel sets no fill color for specific symbols (e.g. cross)
1298 aMarkerFmt
.maLineColor
= aMarkerFmt
.maFillColor
= rRoot
.GetSeriesLineAutoColor( nFormatIdx
);
1299 switch( nLineWeight
)
1301 case EXC_CHLINEFORMAT_HAIR
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_HAIRSIZE
; break;
1302 case EXC_CHLINEFORMAT_SINGLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
; break;
1303 case EXC_CHLINEFORMAT_DOUBLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
; break;
1304 case EXC_CHLINEFORMAT_TRIPLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_TRIPLESIZE
; break;
1305 default: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
;
1307 aMarkerFmt
.mnMarkerType
= XclChartHelper::GetAutoMarkerType( nFormatIdx
);
1308 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, aMarkerFmt
);
1312 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, maData
);
1316 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot
& rRoot
,
1317 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1319 Color aLineColor
= IsAuto() ? rRoot
.GetSeriesLineAutoColor( nFormatIdx
) : maData
.maFillColor
;
1320 rPropSet
.SetColorProperty( EXC_CHPROP_COLOR
, aLineColor
);
1323 XclImpChPieFormat::XclImpChPieFormat() :
1328 void XclImpChPieFormat::ReadChPieFormat( XclImpStream
& rStrm
)
1330 mnPieDist
= rStrm
.ReaduInt16();
1333 void XclImpChPieFormat::Convert( ScfPropertySet
& rPropSet
) const
1335 double fApiDist
= ::std::min
< double >( mnPieDist
/ 100.0, 1.0 );
1336 rPropSet
.SetProperty( EXC_CHPROP_OFFSET
, fApiDist
);
1339 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1344 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream
& rStrm
)
1346 mnFlags
= rStrm
.ReaduInt16();
1349 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream
& rStrm
)
1351 maData
.mnBase
= rStrm
.ReaduInt8();
1352 maData
.mnTop
= rStrm
.ReaduInt8();
1355 void XclImpCh3dDataFormat::Convert( ScfPropertySet
& rPropSet
) const
1357 using namespace ::com::sun::star::chart2::DataPointGeometry3D
;
1358 sal_Int32 nApiType
= (maData
.mnBase
== EXC_CH3DDATAFORMAT_RECT
) ?
1359 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CUBOID
: PYRAMID
) :
1360 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CYLINDER
: CONE
);
1361 rPropSet
.SetProperty( EXC_CHPROP_GEOMETRY3D
, nApiType
);
1364 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot
& rRoot
) :
1365 XclImpChRoot( rRoot
),
1370 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream
& rStrm
)
1372 mnFlags
= rStrm
.ReaduInt16();
1375 XclImpChTextRef
XclImpChAttachedLabel::CreateDataLabel( const XclImpChText
* pParent
) const
1377 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE
= EXC_CHATTLABEL_SHOWVALUE
;
1378 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT
= EXC_CHATTLABEL_SHOWPERCENT
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1379 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG
= EXC_CHATTLABEL_SHOWCATEG
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1381 XclImpChTextRef xLabel
;
1383 xLabel
= std::make_shared
<XclImpChText
>( *pParent
);
1385 xLabel
= std::make_shared
<XclImpChText
>( GetChRoot() );
1386 xLabel
->UpdateDataLabel(
1387 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYCATEG
),
1388 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYVALUE
),
1389 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYPERCENT
) );
1393 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot
& rRoot
) :
1394 XclImpChRoot( rRoot
)
1398 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream
& rStrm
)
1400 maData
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
1401 maData
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
1402 maData
.mnFormatIdx
= rStrm
.ReaduInt16();
1403 maData
.mnFlags
= rStrm
.ReaduInt16();
1406 void XclImpChDataFormat::ReadSubRecord( XclImpStream
& rStrm
)
1408 switch( rStrm
.GetRecId() )
1410 case EXC_ID_CHMARKERFORMAT
:
1411 mxMarkerFmt
= std::make_shared
<XclImpChMarkerFormat
>();
1412 mxMarkerFmt
->ReadChMarkerFormat( rStrm
);
1414 case EXC_ID_CHPIEFORMAT
:
1415 mxPieFmt
= std::make_shared
<XclImpChPieFormat
>();
1416 mxPieFmt
->ReadChPieFormat( rStrm
);
1418 case EXC_ID_CHSERIESFORMAT
:
1419 mxSeriesFmt
= std::make_shared
<XclImpChSeriesFormat
>();
1420 mxSeriesFmt
->ReadChSeriesFormat( rStrm
);
1422 case EXC_ID_CH3DDATAFORMAT
:
1423 mx3dDataFmt
= std::make_shared
<XclImpCh3dDataFormat
>();
1424 mx3dDataFmt
->ReadCh3dDataFormat( rStrm
);
1426 case EXC_ID_CHATTACHEDLABEL
:
1427 mxAttLabel
= std::make_shared
<XclImpChAttachedLabel
>( GetChRoot() );
1428 mxAttLabel
->ReadChAttachedLabel( rStrm
);
1431 XclImpChFrameBase::ReadSubRecord( rStrm
);
1435 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
)
1437 maData
.maPointPos
= rPointPos
;
1438 maData
.mnFormatIdx
= nFormatIdx
;
1441 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo
& rTypeInfo
)
1443 // remove formats not used for the current chart type
1444 RemoveUnusedFormats( rTypeInfo
);
1447 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pGroupFmt
)
1449 // update missing formats from passed chart type group format
1453 mxLineFmt
= pGroupFmt
->mxLineFmt
;
1454 if( !mxAreaFmt
&& !mxEscherFmt
)
1456 mxAreaFmt
= pGroupFmt
->mxAreaFmt
;
1457 mxEscherFmt
= pGroupFmt
->mxEscherFmt
;
1460 mxMarkerFmt
= pGroupFmt
->mxMarkerFmt
;
1462 mxPieFmt
= pGroupFmt
->mxPieFmt
;
1464 mxSeriesFmt
= pGroupFmt
->mxSeriesFmt
;
1466 mx3dDataFmt
= pGroupFmt
->mx3dDataFmt
;
1468 mxAttLabel
= pGroupFmt
->mxAttLabel
;
1471 /* Create missing but required formats. Existing line, area, and marker
1472 format objects are needed to create automatic series formatting. */
1474 mxLineFmt
= new XclImpChLineFormat();
1475 if( !mxAreaFmt
&& !mxEscherFmt
)
1476 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
1478 mxMarkerFmt
= std::make_shared
<XclImpChMarkerFormat
>();
1480 // remove formats not used for the current chart type
1481 RemoveUnusedFormats( rTypeInfo
);
1482 // update data label
1483 UpdateDataLabel( pGroupFmt
);
1486 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pSeriesFmt
)
1488 // remove formats if they are automatic in this and in the passed series format
1491 if( IsAutoLine() && pSeriesFmt
->IsAutoLine() )
1493 if( IsAutoArea() && pSeriesFmt
->IsAutoArea() )
1495 if( IsAutoMarker() && pSeriesFmt
->IsAutoMarker() )
1496 mxMarkerFmt
.reset();
1497 mxSeriesFmt
.reset();
1500 // Excel ignores 3D bar format for single data points
1501 mx3dDataFmt
.reset();
1502 // remove point line formats for linear chart types, TODO: implement in OOChart
1503 if( !rTypeInfo
.IsSeriesFrameFormat() )
1506 // remove formats not used for the current chart type
1507 RemoveUnusedFormats( rTypeInfo
);
1508 // update data label
1509 UpdateDataLabel( pSeriesFmt
);
1512 void XclImpChDataFormat::UpdateTrendLineFormat()
1515 mxLineFmt
= new XclImpChLineFormat();
1517 mxEscherFmt
.reset();
1518 mxMarkerFmt
.reset();
1520 mxSeriesFmt
.reset();
1521 mx3dDataFmt
.reset();
1523 // update data label
1524 UpdateDataLabel( nullptr );
1527 void XclImpChDataFormat::Convert( ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1529 /* Line and area format.
1530 #i71810# If the data points are filled with bitmaps, textures, or
1531 patterns, then only bar charts will use the CHPICFORMAT record to
1532 determine stacking/stretching mode. All other chart types ignore this
1533 record and always use the property 'fill-type' from the DFF property
1534 set (stretched for bitmaps, and stacked for textures and patterns). */
1535 bool bUsePicFmt
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
;
1536 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType(), maData
.mnFormatIdx
, bUsePicFmt
);
1538 // #i83151# only hair lines in 3D charts with filled data points
1539 if( rTypeInfo
.mb3dChart
&& rTypeInfo
.IsSeriesFrameFormat() && mxLineFmt
&& mxLineFmt
->HasLine() )
1540 rPropSet
.SetProperty
< sal_Int32
>( "BorderWidth", 0 );
1544 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
, GetLineWeight() );
1546 mxPieFmt
->Convert( rPropSet
);
1548 mx3dDataFmt
->Convert( rPropSet
);
1550 mxLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, pGlobalPropSet
);
1553 rPropSet
.SetProperty
< sal_Int16
>( EXC_CHPROP_PERCENTDIAGONAL
, 0 );
1555 /* Special case: set marker color as line color, if series line is not
1556 visible. This makes the color visible in the marker area.
1557 TODO: remove this if OOChart supports own colors in markers. */
1558 if( !rTypeInfo
.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt
)
1559 mxMarkerFmt
->ConvertColor( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1562 void XclImpChDataFormat::ConvertLine( ScfPropertySet
& rPropSet
, XclChObjectType eObjType
) const
1564 ConvertLineBase( GetChRoot(), rPropSet
, eObjType
);
1567 void XclImpChDataFormat::ConvertArea( ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1569 ConvertAreaBase( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_FILLEDSERIES
, nFormatIdx
);
1572 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo
& rTypeInfo
)
1574 // data point marker only in linear 2D charts
1575 if( rTypeInfo
.IsSeriesFrameFormat() )
1576 mxMarkerFmt
.reset();
1577 // pie format only in pie/donut charts
1578 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
1580 // 3D format only in 3D bar charts
1581 if( !rTypeInfo
.mb3dChart
|| (rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
1582 mx3dDataFmt
.reset();
1585 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat
* pParentFmt
)
1587 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1588 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1589 group, the contents of the CHATTACHEDLABEL record are used. In this
1590 case a new CHTEXT group is created and filled with the settings from
1591 the CHATTACHEDLABEL record. */
1592 const XclImpChText
* pDefText
= nullptr;
1594 pDefText
= pParentFmt
->GetDataLabel();
1596 pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL
);
1598 mxLabel
->UpdateText(pDefText
);
1599 else if (mxAttLabel
)
1600 mxLabel
= mxAttLabel
->CreateDataLabel( pDefText
);
1603 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot
& rRoot
) :
1604 XclImpChRoot( rRoot
)
1608 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream
& rStrm
)
1610 maData
.mnLineType
= rStrm
.ReaduInt8();
1611 maData
.mnOrder
= rStrm
.ReaduInt8();
1612 maData
.mfIntercept
= rStrm
.ReadDouble();
1613 maData
.mnShowEquation
= rStrm
.ReaduInt8();
1614 maData
.mnShowRSquared
= rStrm
.ReaduInt8();
1615 maData
.mfForecastFor
= rStrm
.ReadDouble();
1616 maData
.mfForecastBack
= rStrm
.ReadDouble();
1619 Reference
< XRegressionCurve
> XclImpChSerTrendLine::CreateRegressionCurve() const
1622 Reference
< XRegressionCurve
> xRegCurve
;
1623 switch( maData
.mnLineType
)
1625 case EXC_CHSERTREND_POLYNOMIAL
:
1626 if( maData
.mnOrder
== 1 )
1628 xRegCurve
= LinearRegressionCurve::create( comphelper::getProcessComponentContext() );
1630 xRegCurve
= PolynomialRegressionCurve::create( comphelper::getProcessComponentContext() );
1633 case EXC_CHSERTREND_EXPONENTIAL
:
1634 xRegCurve
= ExponentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1636 case EXC_CHSERTREND_LOGARITHMIC
:
1637 xRegCurve
= LogarithmicRegressionCurve::create( comphelper::getProcessComponentContext() );
1639 case EXC_CHSERTREND_POWER
:
1640 xRegCurve
= PotentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1642 case EXC_CHSERTREND_MOVING_AVG
:
1643 xRegCurve
= MovingAverageRegressionCurve::create( comphelper::getProcessComponentContext() );
1647 // trend line formatting
1648 if( xRegCurve
.is() && mxDataFmt
)
1650 ScfPropertySet
aPropSet( xRegCurve
);
1651 mxDataFmt
->ConvertLine( aPropSet
, EXC_CHOBJTYPE_TRENDLINE
);
1653 aPropSet
.SetProperty(EXC_CHPROP_CURVENAME
, maTrendLineName
);
1654 aPropSet
.SetProperty(EXC_CHPROP_POLYNOMIAL_DEGREE
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1655 aPropSet
.SetProperty(EXC_CHPROP_MOVING_AVERAGE_PERIOD
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1656 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_FORWARD
, maData
.mfForecastFor
);
1657 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_BACKWARD
, maData
.mfForecastBack
);
1659 bool bForceIntercept
= std::isfinite(maData
.mfIntercept
);
1660 aPropSet
.SetProperty(EXC_CHPROP_FORCE_INTERCEPT
, bForceIntercept
);
1661 if (bForceIntercept
)
1663 aPropSet
.SetProperty(EXC_CHPROP_INTERCEPT_VALUE
, maData
.mfIntercept
);
1666 // #i83100# show equation and correlation coefficient
1667 ScfPropertySet
aLabelProp( xRegCurve
->getEquationProperties() );
1668 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWEQUATION
, maData
.mnShowEquation
!= 0 );
1669 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION
, maData
.mnShowRSquared
!= 0 );
1671 // #i83100# formatting of the equation text box
1672 if (const XclImpChText
* pLabel
= mxDataFmt
->GetDataLabel())
1674 pLabel
->ConvertFont( aLabelProp
);
1675 pLabel
->ConvertFrame( aLabelProp
);
1676 pLabel
->ConvertNumFmt( aLabelProp
, false );
1683 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot
& rRoot
) :
1684 XclImpChRoot( rRoot
)
1688 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream
& rStrm
)
1690 maData
.mnBarType
= rStrm
.ReaduInt8();
1691 maData
.mnSourceType
= rStrm
.ReaduInt8();
1692 maData
.mnLineEnd
= rStrm
.ReaduInt8();
1694 maData
.mfValue
= rStrm
.ReadDouble();
1695 maData
.mnValueCount
= rStrm
.ReaduInt16();
1698 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef
const & xValueLink
, XclImpChDataFormatRef
const & xDataFmt
)
1700 mxValueLink
= xValueLink
;
1701 mxDataFmt
= xDataFmt
;
1704 Reference
< XLabeledDataSequence
> XclImpChSerErrorBar::CreateValueSequence() const
1706 return lclCreateLabeledDataSequence( mxValueLink
, XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
) );
1709 Reference
< XPropertySet
> XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar
* pPosBar
, const XclImpChSerErrorBar
* pNegBar
)
1711 Reference
< XPropertySet
> xErrorBar
;
1713 if( const XclImpChSerErrorBar
* pPrimaryBar
= pPosBar
? pPosBar
: pNegBar
)
1715 xErrorBar
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR
), UNO_QUERY
);
1716 ScfPropertySet
aBarProp( xErrorBar
);
1718 // plus/minus bars visible?
1719 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR
, pPosBar
!= nullptr );
1720 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR
, pNegBar
!= nullptr );
1722 // type of displayed error
1723 switch( pPrimaryBar
->maData
.mnSourceType
)
1725 case EXC_CHSERERR_PERCENT
:
1726 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::RELATIVE
);
1727 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1728 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1730 case EXC_CHSERERR_FIXED
:
1731 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::ABSOLUTE
);
1732 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1733 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1735 case EXC_CHSERERR_STDDEV
:
1736 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_DEVIATION
);
1737 aBarProp
.SetProperty( EXC_CHPROP_WEIGHT
, pPrimaryBar
->maData
.mfValue
);
1739 case EXC_CHSERERR_STDERR
:
1740 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_ERROR
);
1742 case EXC_CHSERERR_CUSTOM
:
1744 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::FROM_DATA
);
1745 // attach data sequences to error bar
1746 Reference
< XDataSink
> xDataSink( xErrorBar
, UNO_QUERY
);
1747 if( xDataSink
.is() )
1749 // create vector of all value sequences
1750 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
1751 // add positive values
1754 Reference
< XLabeledDataSequence
> xValueSeq
= pPosBar
->CreateValueSequence();
1755 if( xValueSeq
.is() )
1756 aLabeledSeqVec
.push_back( xValueSeq
);
1758 // add negative values
1761 Reference
< XLabeledDataSequence
> xValueSeq
= pNegBar
->CreateValueSequence();
1762 if( xValueSeq
.is() )
1763 aLabeledSeqVec
.push_back( xValueSeq
);
1765 // attach labeled data sequences to series
1766 if( aLabeledSeqVec
.empty() )
1769 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
1777 // error bar formatting
1778 if( pPrimaryBar
->mxDataFmt
&& xErrorBar
.is() )
1779 pPrimaryBar
->mxDataFmt
->ConvertLine( aBarProp
, EXC_CHOBJTYPE_ERRORBAR
);
1785 XclImpChSeries::XclImpChSeries( const XclImpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1786 XclImpChRoot( rRoot
),
1787 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1788 mnSeriesIdx( nSeriesIdx
),
1789 mnParentIdx( EXC_CHSERIES_INVALID
),
1790 mbLabelDeleted( false )
1794 void XclImpChSeries::ReadHeaderRecord( XclImpStream
& rStrm
)
1796 maData
.mnCategType
= rStrm
.ReaduInt16();
1797 maData
.mnValueType
= rStrm
.ReaduInt16();
1798 maData
.mnCategCount
= rStrm
.ReaduInt16();
1799 maData
.mnValueCount
= rStrm
.ReaduInt16();
1800 if( GetBiff() == EXC_BIFF8
)
1802 maData
.mnBubbleType
= rStrm
.ReaduInt16();
1803 maData
.mnBubbleCount
= rStrm
.ReaduInt16();
1807 void XclImpChSeries::ReadSubRecord( XclImpStream
& rStrm
)
1809 switch( rStrm
.GetRecId() )
1811 case EXC_ID_CHSOURCELINK
:
1812 ReadChSourceLink( rStrm
);
1814 case EXC_ID_CHDATAFORMAT
:
1815 ReadChDataFormat( rStrm
);
1817 case EXC_ID_CHSERGROUP
:
1818 mnGroupIdx
= rStrm
.ReaduInt16();
1820 case EXC_ID_CHSERPARENT
:
1821 ReadChSerParent( rStrm
);
1823 case EXC_ID_CHSERTRENDLINE
:
1824 ReadChSerTrendLine( rStrm
);
1826 case EXC_ID_CHSERERRORBAR
:
1827 ReadChSerErrorBar( rStrm
);
1829 case EXC_ID_CHLEGENDEXCEPTION
:
1830 ReadChLegendException( rStrm
);
1835 void XclImpChSeries::SetDataFormat( const XclImpChDataFormatRef
& xDataFmt
)
1840 sal_uInt16 nPointIdx
= xDataFmt
->GetPointPos().mnPointIdx
;
1841 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1844 // Don't overwrite the existing format.
1847 mxSeriesFmt
= xDataFmt
;
1848 if (HasParentSeries())
1851 XclImpChTypeGroupRef pTypeGroup
= GetChartData().GetTypeGroup(mnGroupIdx
);
1853 pTypeGroup
->SetUsedFormatIndex(xDataFmt
->GetFormatIdx());
1858 if (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1859 // Above the max point count. Bail out.
1862 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1863 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1865 // No object exists at this point index position. Insert it.
1866 itr
= maPointFmts
.insert(itr
, XclImpChDataFormatMap::value_type(nPointIdx
, xDataFmt
));
1870 void XclImpChSeries::SetDataLabel( const XclImpChTextRef
& xLabel
)
1875 sal_uInt16 nPointIdx
= xLabel
->GetPointPos().mnPointIdx
;
1876 if ((nPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
) && (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
))
1877 // Above the maximum allowed data points. Bail out.
1880 XclImpChTextMap::iterator itr
= maLabels
.lower_bound(nPointIdx
);
1881 if (itr
== maLabels
.end() || maLabels
.key_comp()(nPointIdx
, itr
->first
))
1883 // No object exists at this point index position. Insert it.
1884 itr
= maLabels
.insert(itr
, XclImpChTextMap::value_type(nPointIdx
, xLabel
));
1888 void XclImpChSeries::AddChildSeries( const XclImpChSeries
& rSeries
)
1890 OSL_ENSURE( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1891 if (&rSeries
== this)
1893 SAL_WARN("sc.filter", "self add attempt");
1897 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1898 these are properties of the parent series. This function adds the
1899 settings of the passed series to this series. */
1900 maTrendLines
.insert( maTrendLines
.end(), rSeries
.maTrendLines
.begin(), rSeries
.maTrendLines
.end() );
1901 for (auto const& it
: rSeries
.m_ErrorBars
)
1903 m_ErrorBars
.insert(std::make_pair(it
.first
, std::make_unique
<XclImpChSerErrorBar
>(*it
.second
)));
1907 void XclImpChSeries::FinalizeDataFormats()
1909 if( HasParentSeries() )
1911 // *** series is a child series, e.g. trend line or error bar ***
1913 // create missing series format
1915 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, 0 );
1919 // #i83100# set text label format, e.g. for trend line equations
1920 XclImpChTextRef xLabel
;
1921 XclImpChTextMap::iterator itr
= maLabels
.find(EXC_CHDATAFORMAT_ALLPOINTS
);
1922 if (itr
!= maLabels
.end())
1923 xLabel
= itr
->second
;
1924 mxSeriesFmt
->SetDataLabel(xLabel
);
1925 // create missing automatic formats
1926 mxSeriesFmt
->UpdateTrendLineFormat();
1929 // copy series formatting to child objects
1930 for (auto const& trendLine
: maTrendLines
)
1932 trendLine
->SetDataFormat(mxSeriesFmt
);
1933 if (mxTitleLink
&& mxTitleLink
->HasString())
1935 trendLine
->SetTrendlineName(mxTitleLink
->GetString());
1938 for (auto const& it
: m_ErrorBars
)
1940 it
.second
->SetSeriesData( mxValueLink
, mxSeriesFmt
);
1943 else if( XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
1945 // *** series is a regular data series ***
1947 // create missing series format
1950 // #i51639# use a new unused format index to create series default format
1951 sal_uInt16 nFormatIdx
= pTypeGroup
->PopUnusedFormatIndex();
1952 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, nFormatIdx
);
1955 // set text labels to data formats
1956 for (auto const& label
: maLabels
)
1958 sal_uInt16 nPointIdx
= label
.first
;
1959 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1962 mxSeriesFmt
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1963 mxSeriesFmt
->SetDataLabel(label
.second
);
1965 else if (nPointIdx
< EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1967 XclImpChDataFormatRef p
;
1968 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1969 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1971 // No object exists at this point index position. Insert
1973 p
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1974 itr
= maPointFmts
.insert(
1975 itr
, XclImpChDataFormatMap::value_type(nPointIdx
, p
));
1979 p
->SetDataLabel(label
.second
);
1983 // update series format (copy missing formatting from group default format)
1985 mxSeriesFmt
->UpdateSeriesFormat( pTypeGroup
->GetTypeInfo(), pTypeGroup
->GetGroupFormat().get() );
1987 // update data point formats (removes unchanged automatic formatting)
1988 for (auto const& pointFormat
: maPointFmts
)
1989 pointFormat
.second
->UpdatePointFormat( pTypeGroup
->GetTypeInfo(), mxSeriesFmt
.get() );
1995 /** Returns the property set of the specified data point. */
1996 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> const & xDataSeries
, sal_uInt16 nPointIdx
)
1998 ScfPropertySet aPropSet
;
2001 aPropSet
.Set( xDataSeries
->getDataPointByIndex( static_cast< sal_Int32
>( nPointIdx
) ) );
2005 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
2012 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateValueSequence( const OUString
& rValueRole
) const
2014 return lclCreateLabeledDataSequence( mxValueLink
, rValueRole
, mxTitleLink
.get() );
2017 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateCategSequence( const OUString
& rCategRole
) const
2019 return lclCreateLabeledDataSequence( mxCategLink
, rCategRole
);
2022 Reference
< XDataSeries
> XclImpChSeries::CreateDataSeries() const
2024 Reference
< XDataSeries
> xDataSeries
;
2025 if( const XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
2027 const XclChExtTypeInfo
& rTypeInfo
= pTypeGroup
->GetTypeInfo();
2029 // create the data series object
2030 xDataSeries
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2032 // attach data and title sequences to series
2033 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2034 if( xDataSink
.is() )
2036 // create vector of all value sequences
2037 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2039 Reference
< XLabeledDataSequence
> xYValueSeq
=
2040 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES
);
2041 if( xYValueSeq
.is() )
2042 aLabeledSeqVec
.push_back( xYValueSeq
);
2044 if( !rTypeInfo
.mbCategoryAxis
)
2046 Reference
< XLabeledDataSequence
> xXValueSeq
=
2047 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES
);
2048 if( xXValueSeq
.is() )
2049 aLabeledSeqVec
.push_back( xXValueSeq
);
2050 // add size values of bubble charts
2051 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
2053 Reference
< XLabeledDataSequence
> xSizeValueSeq
=
2054 lclCreateLabeledDataSequence( mxBubbleLink
, EXC_CHPROP_ROLE_SIZEVALUES
, mxTitleLink
.get() );
2055 if( xSizeValueSeq
.is() )
2056 aLabeledSeqVec
.push_back( xSizeValueSeq
);
2059 // attach labeled data sequences to series
2060 if( !aLabeledSeqVec
.empty() )
2061 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2064 // series formatting
2065 ScfPropertySet
aSeriesProp( xDataSeries
);
2067 mxSeriesFmt
->Convert( aSeriesProp
, rTypeInfo
);
2070 aSeriesProp
.SetProperty(EXC_CHPROP_SHOWLEGENDENTRY
, false);
2073 ConvertTrendLines( xDataSeries
);
2076 Reference
< XPropertySet
> xErrorBarX
= CreateErrorBar( EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
2077 if( xErrorBarX
.is() )
2078 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARX
, xErrorBarX
);
2079 Reference
< XPropertySet
> xErrorBarY
= CreateErrorBar( EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
2080 if( xErrorBarY
.is() )
2081 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARY
, xErrorBarY
);
2083 // own area formatting for every data point (TODO: varying line color not supported)
2084 bool bVarPointFmt
= pTypeGroup
->HasVarPointFormat() && rTypeInfo
.IsSeriesFrameFormat();
2085 aSeriesProp
.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
2086 // #i91271# always set area formatting for every point in pie/doughnut charts
2087 if (mxSeriesFmt
&& mxValueLink
&& ((bVarPointFmt
&& mxSeriesFmt
->IsAutoArea()) || (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)))
2089 for( sal_uInt16 nPointIdx
= 0, nPointCount
= mxValueLink
->GetCellCount(); nPointIdx
< nPointCount
; ++nPointIdx
)
2091 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
2092 mxSeriesFmt
->ConvertArea( aPointProp
, bVarPointFmt
? nPointIdx
: mnSeriesIdx
);
2096 // data point formatting
2097 for (auto const& pointFormat
: maPointFmts
)
2099 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, pointFormat
.first
);
2100 pointFormat
.second
->Convert( aPointProp
, rTypeInfo
, &aSeriesProp
);
2106 void XclImpChSeries::FillAllSourceLinks( ::std::vector
< ScTokenRef
>& rTokens
) const
2109 mxValueLink
->FillSourceLink( rTokens
);
2111 mxCategLink
->FillSourceLink( rTokens
);
2113 mxTitleLink
->FillSourceLink( rTokens
);
2115 mxBubbleLink
->FillSourceLink( rTokens
);
2118 void XclImpChSeries::ReadChSourceLink( XclImpStream
& rStrm
)
2120 XclImpChSourceLinkRef xSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
2121 xSrcLink
->ReadChSourceLink( rStrm
);
2122 switch( xSrcLink
->GetDestType() )
2124 case EXC_CHSRCLINK_TITLE
: mxTitleLink
= xSrcLink
; break;
2125 case EXC_CHSRCLINK_VALUES
: mxValueLink
= xSrcLink
; break;
2126 case EXC_CHSRCLINK_CATEGORY
: mxCategLink
= xSrcLink
; break;
2127 case EXC_CHSRCLINK_BUBBLES
: mxBubbleLink
= xSrcLink
; break;
2131 void XclImpChSeries::ReadChDataFormat( XclImpStream
& rStrm
)
2133 // #i51639# chart stores all data formats and assigns them later to the series
2134 GetChartData().ReadChDataFormat( rStrm
);
2137 void XclImpChSeries::ReadChSerParent( XclImpStream
& rStrm
)
2139 mnParentIdx
= rStrm
.ReaduInt16();
2140 // index to parent series is 1-based, convert it to 0-based
2141 if( mnParentIdx
> 0 )
2144 mnParentIdx
= EXC_CHSERIES_INVALID
;
2147 void XclImpChSeries::ReadChSerTrendLine( XclImpStream
& rStrm
)
2149 XclImpChSerTrendLineRef xTrendLine
= std::make_shared
<XclImpChSerTrendLine
>( GetChRoot() );
2150 xTrendLine
->ReadChSerTrendLine( rStrm
);
2151 maTrendLines
.push_back( xTrendLine
);
2154 void XclImpChSeries::ReadChSerErrorBar( XclImpStream
& rStrm
)
2156 unique_ptr
<XclImpChSerErrorBar
> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
2157 pErrorBar
->ReadChSerErrorBar(rStrm
);
2158 sal_uInt8 nBarType
= pErrorBar
->GetBarType();
2159 m_ErrorBars
.insert(std::make_pair(nBarType
, std::move(pErrorBar
)));
2162 XclImpChDataFormatRef
XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx
, sal_uInt16 nFormatIdx
)
2164 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
2165 xDataFmt
->SetPointPos( XclChDataPointPos( mnSeriesIdx
, nPointIdx
), nFormatIdx
);
2169 void XclImpChSeries::ConvertTrendLines( Reference
< XDataSeries
> const & xDataSeries
) const
2171 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2172 if( !xRegCurveCont
.is() )
2175 for (auto const& trendLine
: maTrendLines
)
2179 Reference
< XRegressionCurve
> xRegCurve
= trendLine
->CreateRegressionCurve();
2180 if( xRegCurve
.is() )
2182 xRegCurveCont
->addRegressionCurve( xRegCurve
);
2187 OSL_FAIL( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2192 Reference
< XPropertySet
> XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
) const
2194 XclImpChSerErrorBarMap::const_iterator itrPosBar
= m_ErrorBars
.find(nPosBarId
);
2195 XclImpChSerErrorBarMap::const_iterator itrNegBar
= m_ErrorBars
.find(nNegBarId
);
2196 XclImpChSerErrorBarMap::const_iterator itrEnd
= m_ErrorBars
.end();
2197 if (itrPosBar
== itrEnd
|| itrNegBar
== itrEnd
)
2198 return Reference
<XPropertySet
>();
2200 return XclImpChSerErrorBar::CreateErrorBar(itrPosBar
->second
.get(), itrNegBar
->second
.get());
2203 void XclImpChSeries::ReadChLegendException(XclImpStream
& rStrm
)
2206 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
2207 mbLabelDeleted
= (nFlags
& EXC_CHLEGENDEXCEPTION_DELETED
);
2210 // Chart type groups ==========================================================
2212 XclImpChType::XclImpChType( const XclImpChRoot
& rRoot
) :
2213 XclImpChRoot( rRoot
),
2214 mnRecId( EXC_ID_CHUNKNOWN
),
2215 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2219 void XclImpChType::ReadChType( XclImpStream
& rStrm
)
2221 sal_uInt16 nRecId
= rStrm
.GetRecId();
2222 bool bKnownType
= true;
2227 maData
.mnOverlap
= rStrm
.ReadInt16();
2228 maData
.mnGap
= rStrm
.ReadInt16();
2229 maData
.mnFlags
= rStrm
.ReaduInt16();
2234 case EXC_ID_CHRADARLINE
:
2235 case EXC_ID_CHRADARAREA
:
2236 maData
.mnFlags
= rStrm
.ReaduInt16();
2240 maData
.mnRotation
= rStrm
.ReaduInt16();
2241 maData
.mnPieHole
= rStrm
.ReaduInt16();
2242 if( GetBiff() == EXC_BIFF8
)
2243 maData
.mnFlags
= rStrm
.ReaduInt16();
2248 case EXC_ID_CHPIEEXT
:
2249 maData
.mnRotation
= 0;
2250 maData
.mnPieHole
= 0;
2254 case EXC_ID_CHSCATTER
:
2255 if( GetBiff() == EXC_BIFF8
)
2257 maData
.mnBubbleSize
= rStrm
.ReaduInt16();
2258 maData
.mnBubbleType
= rStrm
.ReaduInt16();
2259 maData
.mnFlags
= rStrm
.ReaduInt16();
2265 case EXC_ID_CHSURFACE
:
2266 maData
.mnFlags
= rStrm
.ReaduInt16();
2277 void XclImpChType::Finalize( bool bStockChart
)
2282 maTypeInfo
= GetChartTypeInfo( bStockChart
?
2283 EXC_CHTYPEID_STOCK
: EXC_CHTYPEID_LINE
);
2286 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2287 maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
,
2288 EXC_CHTYPEID_HORBAR
, EXC_CHTYPEID_BAR
) );
2291 maTypeInfo
= GetChartTypeInfo( (maData
.mnPieHole
> 0) ?
2292 EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2294 case EXC_ID_CHSCATTER
:
2295 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2296 maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
,
2297 EXC_CHTYPEID_BUBBLES
, EXC_CHTYPEID_SCATTER
) );
2300 maTypeInfo
= GetChartTypeInfo( mnRecId
);
2303 switch( maTypeInfo
.meTypeId
)
2305 case EXC_CHTYPEID_PIEEXT
:
2306 case EXC_CHTYPEID_BUBBLES
:
2307 case EXC_CHTYPEID_SURFACE
:
2308 case EXC_CHTYPEID_UNKNOWN
:
2309 GetTracer().TraceChartUnKnownType();
2315 bool XclImpChType::IsStacked() const
2317 bool bStacked
= false;
2318 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2320 case EXC_CHTYPECATEG_LINE
:
2322 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2323 !::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2325 case EXC_CHTYPECATEG_BAR
:
2327 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2328 !::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2335 bool XclImpChType::IsPercent() const
2337 bool bPercent
= false;
2338 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2340 case EXC_CHTYPECATEG_LINE
:
2342 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2343 ::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2345 case EXC_CHTYPECATEG_BAR
:
2347 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2348 ::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2355 bool XclImpChType::HasCategoryLabels() const
2357 // radar charts disable category labels in chart type, not in CHTICK of X axis
2358 return (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) || ::get_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
);
2361 Reference
< XCoordinateSystem
> XclImpChType::CreateCoordSystem( bool b3dChart
) const
2363 // create the coordinate system object
2364 Reference
< css::uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
2365 Reference
< XCoordinateSystem
> xCoordSystem
;
2366 if( maTypeInfo
.mbPolarCoordSystem
)
2369 xCoordSystem
= css::chart2::PolarCoordinateSystem3d::create(xContext
);
2371 xCoordSystem
= css::chart2::PolarCoordinateSystem2d::create(xContext
);
2376 xCoordSystem
= css::chart2::CartesianCoordinateSystem3d::create(xContext
);
2378 xCoordSystem
= css::chart2::CartesianCoordinateSystem2d::create(xContext
);
2381 // swap X and Y axis
2382 if( maTypeInfo
.mbSwappedAxesSet
)
2384 ScfPropertySet
aCoordSysProp( xCoordSystem
);
2385 aCoordSysProp
.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
, true );
2388 return xCoordSystem
;
2391 Reference
< XChartType
> XclImpChType::CreateChartType( Reference
< XDiagram
> const & xDiagram
, bool b3dChart
) const
2393 OUString aService
= OUString::createFromAscii( maTypeInfo
.mpcServiceName
);
2394 Reference
< XChartType
> xChartType( ScfApiHelper::CreateInstance( aService
), UNO_QUERY
);
2396 // additional properties
2397 switch( maTypeInfo
.meTypeCateg
)
2399 case EXC_CHTYPECATEG_BAR
:
2401 ScfPropertySet
aTypeProp( xChartType
);
2402 Sequence
< sal_Int32
> aInt32Seq
{ -maData
.mnOverlap
, -maData
.mnOverlap
};
2403 aTypeProp
.SetProperty( EXC_CHPROP_OVERLAPSEQ
, aInt32Seq
);
2404 aInt32Seq
= { maData
.mnGap
, maData
.mnGap
};
2405 aTypeProp
.SetProperty( EXC_CHPROP_GAPWIDTHSEQ
, aInt32Seq
);
2408 case EXC_CHTYPECATEG_PIE
:
2410 ScfPropertySet
aTypeProp( xChartType
);
2411 aTypeProp
.SetBoolProperty( EXC_CHPROP_USERINGS
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_DONUT
);
2412 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2413 rotation setting in view3D element. Of-pie charts do not
2414 support pie rotation. */
2415 if( !b3dChart
&& (maTypeInfo
.meTypeId
!= EXC_CHTYPEID_PIEEXT
) )
2417 ScfPropertySet
aDiaProp( xDiagram
);
2418 XclImpChRoot::ConvertPieRotation( aDiaProp
, maData
.mnRotation
);
2428 void XclImpChChart3d::ReadChChart3d( XclImpStream
& rStrm
)
2430 maData
.mnRotation
= rStrm
.ReaduInt16();
2431 maData
.mnElevation
= rStrm
.ReadInt16();
2432 maData
.mnEyeDist
= rStrm
.ReaduInt16();
2433 maData
.mnRelHeight
= rStrm
.ReaduInt16();
2434 maData
.mnRelDepth
= rStrm
.ReaduInt16();
2435 maData
.mnDepthGap
= rStrm
.ReaduInt16();
2436 maData
.mnFlags
= rStrm
.ReaduInt16();
2439 void XclImpChChart3d::Convert( ScfPropertySet
& rPropSet
, bool b3dWallChart
) const
2441 namespace cssd
= ::com::sun::star::drawing
;
2443 // #i104057# do not assert this, written by broken external generators
2444 // OSL_ENSURE( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2446 sal_Int32 nRotationY
= 0;
2447 sal_Int32 nRotationX
= 0;
2448 sal_Int32 nPerspective
= 15;
2449 bool bRightAngled
= false;
2450 cssd::ProjectionMode eProjMode
= cssd::ProjectionMode_PERSPECTIVE
;
2451 Color aAmbientColor
, aLightColor
;
2455 // Y rotation (Excel [0..359], Chart2 [-179,180])
2456 nRotationY
= NormAngle180
<sal_Int32
>(maData
.mnRotation
);
2457 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2458 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, -90, 90 );
2459 // perspective (Excel and Chart2 [0,100])
2460 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2461 // right-angled axes
2462 bRightAngled
= !::get_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
);
2463 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2464 bool bParallel
= bRightAngled
|| (nPerspective
== 0);
2465 eProjMode
= bParallel
? cssd::ProjectionMode_PARALLEL
: cssd::ProjectionMode_PERSPECTIVE
;
2466 // ambient color (Gray 20%)
2467 aAmbientColor
= Color( 204, 204, 204 );
2468 // light color (Gray 60%)
2469 aLightColor
= Color( 102, 102, 102 );
2473 // Y rotation not used in pie charts, but 'first pie slice angle'
2475 XclImpChRoot::ConvertPieRotation( rPropSet
, maData
.mnRotation
);
2476 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2477 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, 10, 80 ) - 90;
2478 // perspective (Excel and Chart2 [0,100])
2479 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2480 // no right-angled axes in pie charts, but parallel projection
2481 bRightAngled
= false;
2482 eProjMode
= cssd::ProjectionMode_PARALLEL
;
2483 // ambient color (Gray 30%)
2484 aAmbientColor
= Color( 179, 179, 179 );
2485 // light color (Gray 70%)
2486 aLightColor
= Color( 76, 76, 76 );
2490 rPropSet
.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT
, static_cast<sal_Int32
>(maData
.mnRelHeight
/ 2)); // seems to be 200%, change to 100%
2491 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONVERTICAL
, nRotationY
);
2492 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL
, nRotationX
);
2493 rPropSet
.SetProperty( EXC_CHPROP_PERSPECTIVE
, nPerspective
);
2494 rPropSet
.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
, bRightAngled
);
2495 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE
, eProjMode
);
2498 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE
, cssd::ShadeMode_FLAT
);
2499 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR
, aAmbientColor
);
2500 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1
, false );
2501 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2
, true );
2502 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2
, aLightColor
);
2503 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2
, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2506 XclImpChLegend::XclImpChLegend( const XclImpChRoot
& rRoot
) :
2507 XclImpChRoot( rRoot
)
2511 void XclImpChLegend::ReadHeaderRecord( XclImpStream
& rStrm
)
2513 rStrm
>> maData
.maRect
;
2514 maData
.mnDockMode
= rStrm
.ReaduInt8();
2515 maData
.mnSpacing
= rStrm
.ReaduInt8();
2516 maData
.mnFlags
= rStrm
.ReaduInt16();
2518 // trace unsupported features
2519 if( GetTracer().IsEnabled() )
2521 if( maData
.mnDockMode
== EXC_CHLEGEND_NOTDOCKED
)
2522 GetTracer().TraceChartLegendPosition();
2523 if( ::get_flag( maData
.mnFlags
, EXC_CHLEGEND_DATATABLE
) )
2524 GetTracer().TraceChartDataTable();
2528 void XclImpChLegend::ReadSubRecord( XclImpStream
& rStrm
)
2530 switch( rStrm
.GetRecId() )
2532 case EXC_ID_CHFRAMEPOS
:
2533 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
2534 mxFramePos
->ReadChFramePos( rStrm
);
2537 mxText
= std::make_shared
<XclImpChText
>( GetChRoot() );
2538 mxText
->ReadRecordGroup( rStrm
);
2540 case EXC_ID_CHFRAME
:
2541 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2542 mxFrame
->ReadRecordGroup( rStrm
);
2547 void XclImpChLegend::Finalize()
2549 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2551 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2552 // Update text formatting. If mxText is empty, the passed default text is used.
2553 lclUpdateText( mxText
, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND
) );
2556 Reference
< XLegend
> XclImpChLegend::CreateLegend() const
2558 Reference
< XLegend
> xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND
), UNO_QUERY
);
2561 ScfPropertySet
aLegendProp( xLegend
);
2562 aLegendProp
.SetBoolProperty( EXC_CHPROP_SHOW
, true );
2566 mxFrame
->Convert( aLegendProp
);
2569 mxText
->ConvertFont( aLegendProp
);
2571 /* Legend position and size. Default positions are used only if the
2572 plot area is positioned automatically (Excel sets the plot area to
2573 manual mode, if the legend is moved or resized). With manual plot
2574 areas, Excel ignores the value in maData.mnDockMode completely. */
2575 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_LINE_END
;
2576 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2577 if( !GetChartData().IsManualPlotArea() ) switch( maData
.mnDockMode
)
2579 case EXC_CHLEGEND_LEFT
:
2580 eApiPos
= cssc2::LegendPosition_LINE_START
;
2581 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2583 case EXC_CHLEGEND_RIGHT
:
2584 // top-right not supported
2585 case EXC_CHLEGEND_CORNER
:
2586 eApiPos
= cssc2::LegendPosition_LINE_END
;
2587 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2589 case EXC_CHLEGEND_TOP
:
2590 eApiPos
= cssc2::LegendPosition_PAGE_START
;
2591 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2593 case EXC_CHLEGEND_BOTTOM
:
2594 eApiPos
= cssc2::LegendPosition_PAGE_END
;
2595 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2599 // no automatic position/size: try to find the correct position and size
2600 if( GetChartData().IsManualPlotArea() || maData
.mnDockMode
== EXC_CHLEGEND_NOTDOCKED
)
2602 const XclChFramePos
* pFramePos
= mxFramePos
? &mxFramePos
->GetFramePosData() : nullptr;
2604 /* Legend position. Only the settings from the CHFRAMEPOS record
2605 are used by Excel, the position in the CHLEGEND record will be
2609 RelativePosition
aRelPos(
2610 CalcRelativeFromChartX( pFramePos
->maRect
.mnX
),
2611 CalcRelativeFromChartY( pFramePos
->maRect
.mnY
),
2612 css::drawing::Alignment_TOP_LEFT
);
2613 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVEPOSITION
, aRelPos
);
2617 // no manual position/size found, just go for the default
2618 eApiPos
= cssc2::LegendPosition_LINE_END
;
2621 /* Legend size. The member mnBRMode specifies whether size is
2622 automatic or changes manually. Manual size is given in points,
2623 not in chart units. */
2624 if( pFramePos
&& (pFramePos
->mnBRMode
== EXC_CHFRAMEPOS_ABSSIZE_POINTS
) &&
2625 (pFramePos
->maRect
.mnWidth
> 0) && (pFramePos
->maRect
.mnHeight
> 0) )
2627 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2628 sal_Int32 nWidthHmm
= o3tl::convert(pFramePos
->maRect
.mnWidth
, o3tl::Length::pt
, o3tl::Length::mm100
);
2629 sal_Int32 nHeightHmm
= o3tl::convert(pFramePos
->maRect
.mnHeight
, o3tl::Length::pt
, o3tl::Length::mm100
);
2630 RelativeSize
aRelSize( CalcRelativeFromHmmX( nWidthHmm
), CalcRelativeFromHmmY( nHeightHmm
) );
2631 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVESIZE
, aRelSize
);
2635 // automatic size: determine entry direction from flags
2636 eApiExpand
= ::get_flagvalue( maData
.mnFlags
, EXC_CHLEGEND_STACKED
,
2637 cssc::ChartLegendExpansion_HIGH
, cssc::ChartLegendExpansion_WIDE
);
2640 aLegendProp
.SetProperty( EXC_CHPROP_ANCHORPOSITION
, eApiPos
);
2641 aLegendProp
.SetProperty( EXC_CHPROP_EXPANSION
, eApiExpand
);
2646 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar
) :
2647 mnDropBar( nDropBar
),
2652 void XclImpChDropBar::ReadHeaderRecord( XclImpStream
& rStrm
)
2654 mnBarDist
= rStrm
.ReaduInt16();
2657 void XclImpChDropBar::Convert( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
2659 XclChObjectType eObjType
= EXC_CHOBJTYPE_BACKGROUND
;
2662 case EXC_CHDROPBAR_UP
: eObjType
= EXC_CHOBJTYPE_WHITEDROPBAR
; break;
2663 case EXC_CHDROPBAR_DOWN
: eObjType
= EXC_CHOBJTYPE_BLACKDROPBAR
; break;
2665 ConvertFrameBase( rRoot
, rPropSet
, eObjType
);
2668 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot
& rRoot
) :
2669 XclImpChRoot( rRoot
),
2671 maTypeInfo( maType
.GetTypeInfo() )
2673 // Initialize unused format indexes set. At this time, all formats are unused.
2674 for( sal_uInt16 nFormatIdx
= 0; nFormatIdx
<= EXC_CHSERIES_MAXSERIES
; ++nFormatIdx
)
2675 maUnusedFormats
.insert( maUnusedFormats
.end(), nFormatIdx
);
2678 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream
& rStrm
)
2681 maData
.mnFlags
= rStrm
.ReaduInt16();
2682 maData
.mnGroupIdx
= rStrm
.ReaduInt16();
2685 void XclImpChTypeGroup::ReadSubRecord( XclImpStream
& rStrm
)
2687 switch( rStrm
.GetRecId() )
2689 case EXC_ID_CHCHART3D
:
2690 mxChart3d
= std::make_shared
<XclImpChChart3d
>();
2691 mxChart3d
->ReadChChart3d( rStrm
);
2693 case EXC_ID_CHLEGEND
:
2694 mxLegend
= std::make_shared
<XclImpChLegend
>( GetChRoot() );
2695 mxLegend
->ReadRecordGroup( rStrm
);
2697 case EXC_ID_CHDEFAULTTEXT
:
2698 GetChartData().ReadChDefaultText( rStrm
);
2700 case EXC_ID_CHDROPBAR
:
2701 ReadChDropBar( rStrm
);
2703 case EXC_ID_CHCHARTLINE
:
2704 ReadChChartLine( rStrm
);
2706 case EXC_ID_CHDATAFORMAT
:
2707 ReadChDataFormat( rStrm
);
2710 maType
.ReadChType( rStrm
);
2714 void XclImpChTypeGroup::Finalize()
2716 // check and set valid chart type
2718 (maType
.GetRecId() == EXC_ID_CHLINE
) && // must be a line chart
2719 !mxChart3d
&& // must be a 2d chart
2720 m_ChartLines
.find(EXC_CHCHARTLINE_HILO
) != m_ChartLines
.end() && // must contain hi-lo lines
2721 (maSeries
.size() == static_cast<XclImpChSeriesVec::size_type
>(HasDropBars() ? 4 : 3)); // correct series count
2722 maType
.Finalize( bStockChart
);
2724 // extended type info
2725 maTypeInfo
.Set( maType
.GetTypeInfo(), static_cast< bool >(mxChart3d
), false );
2727 // reverse series order for some unstacked 2D chart types
2728 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() && !maType
.IsStacked() && !maType
.IsPercent() )
2729 ::std::reverse( maSeries
.begin(), maSeries
.end() );
2731 // update chart type group format, may depend on chart type finalized above
2733 mxGroupFmt
->UpdateGroupFormat( maTypeInfo
);
2736 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef
const & xSeries
)
2739 maSeries
.push_back( xSeries
);
2740 // store first inserted series separately, series order may be reversed later
2741 if( !mxFirstSeries
)
2742 mxFirstSeries
= xSeries
;
2745 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx
)
2747 maUnusedFormats
.erase( nFormatIdx
);
2750 sal_uInt16
XclImpChTypeGroup::PopUnusedFormatIndex()
2752 OSL_ENSURE( !maUnusedFormats
.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2753 sal_uInt16 nFormatIdx
= maUnusedFormats
.empty() ? 0 : *maUnusedFormats
.begin();
2754 SetUsedFormatIndex( nFormatIdx
);
2758 bool XclImpChTypeGroup::HasVarPointFormat() const
2760 return ::get_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
) &&
2761 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_MULTI
) || // multiple series allowed
2762 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_SINGLE
) && // or exactly 1 series?
2763 (maSeries
.size() == 1)));
2766 bool XclImpChTypeGroup::HasConnectorLines() const
2768 // existence of connector lines (only in stacked bar charts)
2769 if ( !(maType
.IsStacked() || maType
.IsPercent()) || (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
2771 XclImpChLineFormatMap::const_iterator aConLine
= m_ChartLines
.find(EXC_CHCHARTLINE_CONNECT
);
2772 return (aConLine
!= m_ChartLines
.end() && aConLine
->second
.HasLine());
2775 OUString
XclImpChTypeGroup::GetSingleSeriesTitle() const
2777 // no automatic title for series with trendlines or error bars
2778 // pie charts always show an automatic title, even if more series exist
2779 return (mxFirstSeries
&& !mxFirstSeries
->HasChildSeries() && (maTypeInfo
.mbSingleSeriesVis
|| (maSeries
.size() == 1))) ?
2780 mxFirstSeries
->GetTitle() : OUString();
2783 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet
& rPropSet
) const
2786 mxChart3d
->Convert( rPropSet
, Is3dWallChart() );
2789 Reference
< XCoordinateSystem
> XclImpChTypeGroup::CreateCoordSystem() const
2791 return maType
.CreateCoordSystem( Is3dChart() );
2794 Reference
< XChartType
> XclImpChTypeGroup::CreateChartType( Reference
< XDiagram
> const & xDiagram
, sal_Int32 nApiAxesSetIdx
) const
2796 OSL_ENSURE( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2798 // create the chart type object
2799 Reference
< XChartType
> xChartType
= maType
.CreateChartType( xDiagram
, Is3dChart() );
2801 // bar chart connector lines
2802 if( HasConnectorLines() )
2804 ScfPropertySet
aDiaProp( xDiagram
);
2805 aDiaProp
.SetBoolProperty( EXC_CHPROP_CONNECTBARS
, true );
2808 /* Stock chart needs special processing. Create one 'big' series with
2809 data sequences of different roles. */
2810 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2811 CreateStockSeries( xChartType
, nApiAxesSetIdx
);
2813 CreateDataSeries( xChartType
, nApiAxesSetIdx
);
2818 Reference
< XLabeledDataSequence
> XclImpChTypeGroup::CreateCategSequence() const
2820 Reference
< XLabeledDataSequence
> xLabeledSeq
;
2821 // create category sequence from first visible series
2823 xLabeledSeq
= mxFirstSeries
->CreateCategSequence( EXC_CHPROP_ROLE_CATEG
);
2827 void XclImpChTypeGroup::ReadChDropBar( XclImpStream
& rStrm
)
2829 if (m_DropBars
.find(EXC_CHDROPBAR_UP
) == m_DropBars
.end())
2831 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_UP
));
2832 p
->ReadRecordGroup(rStrm
);
2833 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_UP
, std::move(p
)));
2835 else if (m_DropBars
.find(EXC_CHDROPBAR_DOWN
) == m_DropBars
.end())
2837 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN
));
2838 p
->ReadRecordGroup(rStrm
);
2839 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_DOWN
, std::move(p
)));
2843 void XclImpChTypeGroup::ReadChChartLine( XclImpStream
& rStrm
)
2845 sal_uInt16 nLineId
= rStrm
.ReaduInt16();
2846 if( (rStrm
.GetNextRecId() == EXC_ID_CHLINEFORMAT
) && rStrm
.StartNextRecord() )
2848 XclImpChLineFormat aLineFmt
;
2849 aLineFmt
.ReadChLineFormat( rStrm
);
2850 m_ChartLines
[ nLineId
] = aLineFmt
;
2854 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream
& rStrm
)
2856 // global series and data point format
2857 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
2858 xDataFmt
->ReadRecordGroup( rStrm
);
2859 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
2860 if( (rPos
.mnSeriesIdx
== 0) && (rPos
.mnPointIdx
== 0) &&
2861 (xDataFmt
->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT
) )
2862 mxGroupFmt
= xDataFmt
;
2865 void XclImpChTypeGroup::InsertDataSeries( Reference
< XChartType
> const & xChartType
,
2866 Reference
< XDataSeries
> const & xSeries
, sal_Int32 nApiAxesSetIdx
) const
2868 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2869 if( !(xSeriesCont
.is() && xSeries
.is()) )
2872 // series stacking mode
2873 cssc2::StackingDirection eStacking
= cssc2::StackingDirection_NO_STACKING
;
2874 // stacked overrides deep-3d
2875 if( maType
.IsStacked() || maType
.IsPercent() )
2876 eStacking
= cssc2::StackingDirection_Y_STACKING
;
2877 else if( Is3dDeepChart() )
2878 eStacking
= cssc2::StackingDirection_Z_STACKING
;
2880 // additional series properties
2881 ScfPropertySet
aSeriesProp( xSeries
);
2882 aSeriesProp
.SetProperty( EXC_CHPROP_STACKINGDIR
, eStacking
);
2883 aSeriesProp
.SetProperty( EXC_CHPROP_ATTAXISINDEX
, nApiAxesSetIdx
);
2885 // insert series into container
2888 xSeriesCont
->addDataSeries( xSeries
);
2892 OSL_FAIL( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2896 void XclImpChTypeGroup::CreateDataSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2898 bool bSpline
= false;
2899 for (auto const& elem
: maSeries
)
2901 Reference
< XDataSeries
> xDataSeries
= elem
->CreateDataSeries();
2902 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2903 bSpline
|= elem
->HasSpline();
2905 // spline - TODO: set at single series (#i66858#)
2906 if( bSpline
&& !maTypeInfo
.IsSeriesFrameFormat() && (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) )
2908 ScfPropertySet
aTypeProp( xChartType
);
2909 aTypeProp
.SetProperty( EXC_CHPROP_CURVESTYLE
, css::chart2::CurveStyle_CUBIC_SPLINES
);
2913 void XclImpChTypeGroup::CreateStockSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2915 // create the data series object
2916 Reference
< XDataSeries
> xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2917 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2918 if( !xDataSink
.is() )
2921 // create a list of data sequences from all series
2922 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2923 OSL_ENSURE( maSeries
.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2924 int nRoleIdx
= (maSeries
.size() == 3) ? 1 : 0;
2925 for( const auto& rxSeries
: maSeries
)
2927 // create a data sequence with a specific role
2931 case 0: aRole
= EXC_CHPROP_ROLE_OPENVALUES
; break;
2932 case 1: aRole
= EXC_CHPROP_ROLE_HIGHVALUES
; break;
2933 case 2: aRole
= EXC_CHPROP_ROLE_LOWVALUES
; break;
2934 case 3: aRole
= EXC_CHPROP_ROLE_CLOSEVALUES
; break;
2936 Reference
< XLabeledDataSequence
> xDataSeq
= rxSeries
->CreateValueSequence( aRole
);
2938 aLabeledSeqVec
.push_back( xDataSeq
);
2944 // attach labeled data sequences to series and insert series into chart type
2945 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2947 // formatting of special stock chart elements
2948 ScfPropertySet
aTypeProp( xChartType
);
2949 aTypeProp
.SetBoolProperty( EXC_CHPROP_JAPANESE
, HasDropBars() );
2950 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWFIRST
, HasDropBars() );
2951 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
, true );
2952 // hi-lo line format
2953 XclImpChLineFormatMap::const_iterator aHiLoLine
= m_ChartLines
.find( EXC_CHCHARTLINE_HILO
);
2954 if (aHiLoLine
!= m_ChartLines
.end())
2956 ScfPropertySet
aSeriesProp( xDataSeries
);
2957 aHiLoLine
->second
.Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2959 // white dropbar format
2960 XclImpChDropBarMap::const_iterator itr
= m_DropBars
.find(EXC_CHDROPBAR_UP
);
2961 Reference
<XPropertySet
> xWhitePropSet
;
2962 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xWhitePropSet
, EXC_CHPROP_WHITEDAY
))
2964 ScfPropertySet
aBarProp( xWhitePropSet
);
2965 itr
->second
->Convert(GetChRoot(), aBarProp
);
2967 // black dropbar format
2968 itr
= m_DropBars
.find(EXC_CHDROPBAR_DOWN
);
2969 Reference
<XPropertySet
> xBlackPropSet
;
2970 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xBlackPropSet
, EXC_CHPROP_BLACKDAY
))
2972 ScfPropertySet
aBarProp( xBlackPropSet
);
2973 itr
->second
->Convert(GetChRoot(), aBarProp
);
2976 // insert the series into the chart type object
2977 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2980 // Axes =======================================================================
2982 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot
& rRoot
) :
2983 XclImpChRoot( rRoot
)
2987 void XclImpChLabelRange::ReadChLabelRange( XclImpStream
& rStrm
)
2989 maLabelData
.mnCross
= rStrm
.ReaduInt16();
2990 maLabelData
.mnLabelFreq
= rStrm
.ReaduInt16();
2991 maLabelData
.mnTickFreq
= rStrm
.ReaduInt16();
2992 maLabelData
.mnFlags
= rStrm
.ReaduInt16();
2995 void XclImpChLabelRange::ReadChDateRange( XclImpStream
& rStrm
)
2997 maDateData
.mnMinDate
= rStrm
.ReaduInt16();
2998 maDateData
.mnMaxDate
= rStrm
.ReaduInt16();
2999 maDateData
.mnMajorStep
= rStrm
.ReaduInt16();
3000 maDateData
.mnMajorUnit
= rStrm
.ReaduInt16();
3001 maDateData
.mnMinorStep
= rStrm
.ReaduInt16();
3002 maDateData
.mnMinorUnit
= rStrm
.ReaduInt16();
3003 maDateData
.mnBaseUnit
= rStrm
.ReaduInt16();
3004 maDateData
.mnCross
= rStrm
.ReaduInt16();
3005 maDateData
.mnFlags
= rStrm
.ReaduInt16();
3008 void XclImpChLabelRange::Convert( ScfPropertySet
& rPropSet
, ScaleData
& rScaleData
, bool bMirrorOrient
) const
3010 // automatic axis type detection
3011 rScaleData
.AutoDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
);
3013 // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
3014 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3016 /* Chart2 requires axis type CATEGORY for automatic category/date axis
3017 (even if it is a date axis currently). */
3018 rScaleData
.AxisType
= rScaleData
.AutoDateAxis
? cssc2::AxisType::CATEGORY
: cssc2::AxisType::DATE
;
3019 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3020 /* Min/max values depend on base time unit, they specify the number of
3021 days, months, or years starting from null date. */
3022 lclConvertTimeValue( GetRoot(), rScaleData
.Minimum
, maDateData
.mnMinDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
), maDateData
.mnBaseUnit
);
3023 lclConvertTimeValue( GetRoot(), rScaleData
.Maximum
, maDateData
.mnMaxDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
), maDateData
.mnBaseUnit
);
3025 cssc::TimeIncrement
& rTimeIncrement
= rScaleData
.TimeIncrement
;
3026 lclConvertTimeInterval( rTimeIncrement
.MajorTimeInterval
, maDateData
.mnMajorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
), maDateData
.mnMajorUnit
);
3027 lclConvertTimeInterval( rTimeIncrement
.MinorTimeInterval
, maDateData
.mnMinorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
), maDateData
.mnMinorUnit
);
3029 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
) )
3030 rTimeIncrement
.TimeResolution
.clear();
3032 rTimeIncrement
.TimeResolution
<<= lclGetApiTimeUnit( maDateData
.mnBaseUnit
);
3036 // do not overlap text unless all labels are visible
3037 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP
, maLabelData
.mnLabelFreq
== 1 );
3038 // do not break text into several lines unless all labels are visible
3039 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTBREAK
, maLabelData
.mnLabelFreq
== 1 );
3040 // do not stagger labels in two lines
3041 rPropSet
.SetProperty( EXC_CHPROP_ARRANGEORDER
, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE
);
3045 bool bReverse
= ::get_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
) != bMirrorOrient
;
3046 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3048 //TODO #i58731# show n-th category
3051 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
, bool b3dChart
) const
3053 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
3054 does not move the Y axis in 3D charts, regardless of actual settings.
3055 But: the Y axis has to be moved to "end", if the X axis is mirrored,
3056 to keep it at the left end of the chart. */
3057 bool bMaxCross
= ::get_flag( maLabelData
.mnFlags
, b3dChart
? EXC_CHLABELRANGE_REVERSE
: EXC_CHLABELRANGE_MAXCROSS
);
3058 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3059 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3061 // crossing position (depending on axis type text/date)
3062 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3064 bool bAutoCross
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
3065 /* Crossing position value depends on base time unit, it specifies the
3066 number of days, months, or years from null date. Note that Excel
3067 2007/2010 write broken BIFF8 files, they always stores the number
3068 of days regardless of the base time unit (and they are reading it
3069 the same way, thus wrongly displaying files written by Excel
3070 97-2003). This filter sticks to the correct behaviour of Excel
3072 double fCrossingPos
= bAutoCross
? 1.0 : lclGetSerialDay( GetRoot(), maDateData
.mnCross
, maDateData
.mnBaseUnit
);
3073 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3077 double fCrossingPos
= b3dChart
? 1.0 : maLabelData
.mnCross
;
3078 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3082 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot
& rRoot
) :
3083 XclImpChRoot( rRoot
)
3087 void XclImpChValueRange::ReadChValueRange( XclImpStream
& rStrm
)
3089 maData
.mfMin
= rStrm
.ReadDouble();
3090 maData
.mfMax
= rStrm
.ReadDouble();
3091 maData
.mfMajorStep
= rStrm
.ReadDouble();
3092 maData
.mfMinorStep
= rStrm
.ReadDouble();
3093 maData
.mfCross
= rStrm
.ReadDouble();
3094 maData
.mnFlags
= rStrm
.ReaduInt16();
3097 void XclImpChValueRange::Convert( ScaleData
& rScaleData
, bool bMirrorOrient
) const
3099 // scaling algorithm
3100 const bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3102 rScaleData
.Scaling
= css::chart2::LogarithmicScaling::create( comphelper::getProcessComponentContext() );
3104 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3107 lclSetExpValueOrClearAny( rScaleData
.Minimum
, maData
.mfMin
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
) );
3108 lclSetExpValueOrClearAny( rScaleData
.Maximum
, maData
.mfMax
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
) );
3111 bool bAutoMajor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
);
3112 bool bAutoMinor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
);
3114 IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
3115 lclSetValueOrClearAny( rIncrementData
.Distance
, maData
.mfMajorStep
, bAutoMajor
);
3117 Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
3118 rSubIncrementSeq
.realloc( 1 );
3119 Any
& rIntervalCount
= rSubIncrementSeq
.getArray()[ 0 ].IntervalCount
;
3120 rIntervalCount
.clear();
3124 rIntervalCount
<<= sal_Int32( 9 );
3126 else if( !bAutoMajor
&& !bAutoMinor
&& (0.0 < maData
.mfMinorStep
) && (maData
.mfMinorStep
<= maData
.mfMajorStep
) )
3128 double fCount
= maData
.mfMajorStep
/ maData
.mfMinorStep
+ 0.5;
3129 if( (1.0 <= fCount
) && (fCount
< 1001.0) )
3130 rIntervalCount
<<= static_cast< sal_Int32
>( fCount
);
3132 else if( bAutoMinor
)
3134 // tdf#114168 If minor unit is not set then set interval to 5, as MS Excel do.
3135 rIntervalCount
<<= static_cast< sal_Int32
>( 5 );
3139 bool bReverse
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
) != bMirrorOrient
;
3140 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3143 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
) const
3145 bool bMaxCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
3146 bool bAutoCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
3147 bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3149 // crossing mode (max-cross flag overrides other crossing settings)
3150 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3151 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3153 // crossing position
3154 double fCrossingPos
= bAutoCross
? 0.0 : maData
.mfCross
;
3155 if( bLogScale
) fCrossingPos
= pow( 10.0, fCrossingPos
);
3156 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3161 sal_Int32
lclGetApiTickmarks( sal_uInt8 nXclTickPos
)
3163 using namespace ::com::sun::star::chart2::TickmarkStyle
;
3164 sal_Int32 nApiTickmarks
= css::chart2::TickmarkStyle::NONE
;
3165 ::set_flag( nApiTickmarks
, INNER
, ::get_flag( nXclTickPos
, EXC_CHTICK_INSIDE
) );
3166 ::set_flag( nApiTickmarks
, OUTER
, ::get_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
) );
3167 return nApiTickmarks
;
3170 cssc::ChartAxisLabelPosition
lclGetApiLabelPosition( sal_Int8 nXclLabelPos
)
3172 using namespace ::com::sun::star::chart
;
3173 switch( nXclLabelPos
)
3175 case EXC_CHTICK_LOW
: return ChartAxisLabelPosition_OUTSIDE_START
;
3176 case EXC_CHTICK_HIGH
: return ChartAxisLabelPosition_OUTSIDE_END
;
3177 case EXC_CHTICK_NEXT
: return ChartAxisLabelPosition_NEAR_AXIS
;
3179 return ChartAxisLabelPosition_NEAR_AXIS
;
3184 XclImpChTick::XclImpChTick( const XclImpChRoot
& rRoot
) :
3185 XclImpChRoot( rRoot
)
3189 void XclImpChTick::ReadChTick( XclImpStream
& rStrm
)
3191 maData
.mnMajor
= rStrm
.ReaduInt8();
3192 maData
.mnMinor
= rStrm
.ReaduInt8();
3193 maData
.mnLabelPos
= rStrm
.ReaduInt8();
3194 maData
.mnBackMode
= rStrm
.ReaduInt8();
3196 rStrm
>> maData
.maTextColor
;
3197 maData
.mnFlags
= rStrm
.ReaduInt16();
3199 if( GetBiff() == EXC_BIFF8
)
3201 // BIFF8: index into palette used instead of RGB data
3202 maData
.maTextColor
= GetPalette().GetColor( rStrm
.ReaduInt16() );
3204 maData
.mnRotation
= rStrm
.ReaduInt16();
3208 // BIFF2-BIFF7: get rotation from text orientation
3209 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 2, 3 );
3210 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
3214 Color
XclImpChTick::GetFontColor() const
3216 return ::get_flag( maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextColor
;
3219 sal_uInt16
XclImpChTick::GetRotation() const
3221 /* n#720443: Ignore auto-rotation if there is a suggested rotation.
3222 * Better fix would be to improve our axis auto rotation algorithm.
3224 if( maData
.mnRotation
!= EXC_ROT_NONE
)
3225 return maData
.mnRotation
;
3226 return ::get_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
) ? EXC_CHART_AUTOROTATION
: maData
.mnRotation
;
3229 void XclImpChTick::Convert( ScfPropertySet
& rPropSet
) const
3231 rPropSet
.SetProperty( EXC_CHPROP_MAJORTICKS
, lclGetApiTickmarks( maData
.mnMajor
) );
3232 rPropSet
.SetProperty( EXC_CHPROP_MINORTICKS
, lclGetApiTickmarks( maData
.mnMinor
) );
3233 rPropSet
.SetProperty( EXC_CHPROP_LABELPOSITION
, lclGetApiLabelPosition( maData
.mnLabelPos
) );
3234 rPropSet
.SetProperty( EXC_CHPROP_MARKPOSITION
, cssc::ChartAxisMarkPosition_AT_AXIS
);
3237 XclImpChAxis::XclImpChAxis( const XclImpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
3238 XclImpChRoot( rRoot
),
3239 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
3241 maData
.mnType
= nAxisType
;
3244 void XclImpChAxis::ReadHeaderRecord( XclImpStream
& rStrm
)
3246 maData
.mnType
= rStrm
.ReaduInt16();
3249 void XclImpChAxis::ReadSubRecord( XclImpStream
& rStrm
)
3251 switch( rStrm
.GetRecId() )
3253 case EXC_ID_CHLABELRANGE
:
3254 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3255 mxLabelRange
->ReadChLabelRange( rStrm
);
3257 case EXC_ID_CHDATERANGE
:
3259 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3260 mxLabelRange
->ReadChDateRange( rStrm
);
3262 case EXC_ID_CHVALUERANGE
:
3263 mxValueRange
= std::make_shared
<XclImpChValueRange
>( GetChRoot() );
3264 mxValueRange
->ReadChValueRange( rStrm
);
3266 case EXC_ID_CHFORMAT
:
3267 mnNumFmtIdx
= rStrm
.ReaduInt16();
3270 mxTick
= std::make_shared
<XclImpChTick
>( GetChRoot() );
3271 mxTick
->ReadChTick( rStrm
);
3274 mxFont
= std::make_shared
<XclImpChFont
>();
3275 mxFont
->ReadChFont( rStrm
);
3277 case EXC_ID_CHAXISLINE
:
3278 ReadChAxisLine( rStrm
);
3283 void XclImpChAxis::Finalize()
3285 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3287 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3289 mxValueRange
= std::make_shared
<XclImpChValueRange
>( GetChRoot() );
3290 // remove invisible grid lines completely
3291 if( mxMajorGrid
&& !mxMajorGrid
->HasLine() )
3292 mxMajorGrid
.clear();
3293 if( mxMinorGrid
&& !mxMinorGrid
->HasLine() )
3294 mxMinorGrid
.clear();
3295 // default tick settings different in OOChart and Excel
3297 mxTick
= std::make_shared
<XclImpChTick
>( GetChRoot() );
3298 // #i4140# different default axis line color
3301 XclChLineFormat aLineFmt
;
3302 // set "show axis" flag, default if line format record is missing
3303 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_SHOWAXIS
);
3304 mxAxisLine
= new XclImpChLineFormat( aLineFmt
);
3306 // add wall/floor frame for 3d charts
3311 sal_uInt16
XclImpChAxis::GetFontIndex() const
3313 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
3316 Color
XclImpChAxis::GetFontColor() const
3318 return mxTick
? mxTick
->GetFontColor() : GetFontAutoColor();
3321 sal_uInt16
XclImpChAxis::GetRotation() const
3323 return mxTick
? mxTick
->GetRotation() : EXC_CHART_AUTOROTATION
;
3326 Reference
< XAxis
> XclImpChAxis::CreateAxis( const XclImpChTypeGroup
& rTypeGroup
, const XclImpChAxis
* pCrossingAxis
) const
3328 // create the axis object (always)
3329 Reference
< XAxis
> xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS
), UNO_QUERY
);
3332 ScfPropertySet
aAxisProp( xAxis
);
3333 // #i58688# axis enabled
3334 aAxisProp
.SetBoolProperty( EXC_CHPROP_SHOW
, !mxAxisLine
|| mxAxisLine
->IsShowAxis() );
3336 // axis line properties
3338 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
3339 // axis ticks properties
3341 mxTick
->Convert( aAxisProp
);
3343 // axis caption text --------------------------------------------------
3345 // radar charts disable their category labels via chart type, not via axis
3346 bool bHasLabels
= (!mxTick
|| mxTick
->HasLabels()) &&
3347 ((GetAxisType() != EXC_CHAXIS_X
) || rTypeGroup
.HasCategoryLabels());
3348 aAxisProp
.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS
, bHasLabels
);
3351 // font settings from CHFONT record or from default text
3353 ConvertFontBase( GetChRoot(), aAxisProp
);
3354 else if( const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL
) )
3355 pDefText
->ConvertFont( aAxisProp
);
3356 // label text rotation
3357 ConvertRotationBase( aAxisProp
, true );
3359 bool bLinkNumberFmtToSource
= true;
3360 if ( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3362 sal_uInt32 nScNumFmt
= GetNumFmtBuffer().GetScFormat( mnNumFmtIdx
);
3363 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
3365 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT
, static_cast< sal_Int32
>( nScNumFmt
) );
3366 bLinkNumberFmtToSource
= false;
3370 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT_LINKSRC
, bLinkNumberFmtToSource
);
3373 // axis scaling and increment -----------------------------------------
3375 const XclChExtTypeInfo
& rTypeInfo
= rTypeGroup
.GetTypeInfo();
3376 ScaleData aScaleData
= xAxis
->getScaleData();
3378 switch( GetAxisType() )
3381 if( rTypeInfo
.mbCategoryAxis
)
3383 aScaleData
.AxisType
= cssc2::AxisType::CATEGORY
;
3384 aScaleData
.Categories
= rTypeGroup
.CreateCategSequence();
3387 aScaleData
.AxisType
= cssc2::AxisType::REALNUMBER
;
3390 aScaleData
.AxisType
= rTypeGroup
.IsPercent() ?
3391 cssc2::AxisType::PERCENT
: cssc2::AxisType::REALNUMBER
;
3394 aScaleData
.AxisType
= cssc2::AxisType::SERIES
;
3397 // axis scaling settings, dependent on axis type
3398 switch( aScaleData
.AxisType
)
3400 case cssc2::AxisType::CATEGORY
:
3401 case cssc2::AxisType::SERIES
:
3402 // #i71684# radar charts have reversed rotation direction
3404 mxLabelRange
->Convert( aAxisProp
, aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
);
3406 SAL_WARN("sc.filter", "missing LabelRange");
3408 case cssc2::AxisType::REALNUMBER
:
3409 case cssc2::AxisType::PERCENT
:
3410 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3412 mxValueRange
->Convert( aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3414 SAL_WARN("sc.filter", "missing ValueRange");
3417 OSL_FAIL( "XclImpChAxis::CreateAxis - unknown axis type" );
3420 /* Do not set a value to the Origin member anymore (will be done via
3421 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3422 aScaleData
.Origin
.clear();
3425 xAxis
->setScaleData( aScaleData
);
3427 // grid ---------------------------------------------------------------
3430 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3431 aGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMajorGrid
) );
3433 mxMajorGrid
->Convert( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3435 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3436 if( aSubGridPropSeq
.hasElements() )
3438 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3439 aSubGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMinorGrid
) );
3441 mxMinorGrid
->Convert( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3444 // position of crossing axis ------------------------------------------
3447 pCrossingAxis
->ConvertAxisPosition( aAxisProp
, rTypeGroup
);
3452 void XclImpChAxis::ConvertWall( ScfPropertySet
& rPropSet
) const
3454 // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3456 mxWallFrame
->Convert( rPropSet
, true );
3459 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet
& rPropSet
, const XclImpChTypeGroup
& rTypeGroup
) const
3461 if( ((GetAxisType() == EXC_CHAXIS_X
) && rTypeGroup
.GetTypeInfo().mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
) )
3464 mxLabelRange
->ConvertAxisPosition( rPropSet
, rTypeGroup
.Is3dChart() );
3466 SAL_WARN("sc.filter", "missing LabelRange");
3471 mxValueRange
->ConvertAxisPosition( rPropSet
);
3473 SAL_WARN("sc.filter", "missing ValueRange");
3477 void XclImpChAxis::ReadChAxisLine( XclImpStream
& rStrm
)
3479 XclImpChLineFormatRef
* pxLineFmt
= nullptr;
3480 bool bWallFrame
= false;
3481 switch( rStrm
.ReaduInt16() )
3483 case EXC_CHAXISLINE_AXISLINE
: pxLineFmt
= &mxAxisLine
; break;
3484 case EXC_CHAXISLINE_MAJORGRID
: pxLineFmt
= &mxMajorGrid
; break;
3485 case EXC_CHAXISLINE_MINORGRID
: pxLineFmt
= &mxMinorGrid
; break;
3486 case EXC_CHAXISLINE_WALLS
: bWallFrame
= true; break;
3491 bool bLoop
= pxLineFmt
|| bWallFrame
;
3494 sal_uInt16 nRecId
= rStrm
.GetNextRecId();
3495 bLoop
= ((nRecId
== EXC_ID_CHLINEFORMAT
) ||
3496 (nRecId
== EXC_ID_CHAREAFORMAT
) ||
3497 (nRecId
== EXC_ID_CHESCHERFORMAT
))
3498 && rStrm
.StartNextRecord();
3501 if( pxLineFmt
&& (nRecId
== EXC_ID_CHLINEFORMAT
) )
3503 (*pxLineFmt
) = new XclImpChLineFormat();
3504 (*pxLineFmt
)->ReadChLineFormat( rStrm
);
3506 else if( bWallFrame
&& mxWallFrame
)
3508 mxWallFrame
->ReadSubRecord( rStrm
);
3514 void XclImpChAxis::CreateWallFrame()
3516 switch( GetAxisType() )
3519 mxWallFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_WALL3D
);
3522 mxWallFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D
);
3525 mxWallFrame
.reset();
3529 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3530 XclImpChRoot( rRoot
)
3532 maData
.mnAxesSetId
= nAxesSetId
;
3535 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream
& rStrm
)
3537 maData
.mnAxesSetId
= rStrm
.ReaduInt16();
3538 rStrm
>> maData
.maRect
;
3541 void XclImpChAxesSet::ReadSubRecord( XclImpStream
& rStrm
)
3543 switch( rStrm
.GetRecId() )
3545 case EXC_ID_CHFRAMEPOS
:
3546 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
3547 mxFramePos
->ReadChFramePos( rStrm
);
3550 ReadChAxis( rStrm
);
3553 ReadChText( rStrm
);
3555 case EXC_ID_CHPLOTFRAME
:
3556 ReadChPlotFrame( rStrm
);
3558 case EXC_ID_CHTYPEGROUP
:
3559 ReadChTypeGroup( rStrm
);
3564 void XclImpChAxesSet::Finalize()
3566 if( IsValidAxesSet() )
3568 // finalize chart type groups, erase empty groups without series
3569 XclImpChTypeGroupMap aValidGroups
;
3570 for (auto const& typeGroup
: maTypeGroups
)
3572 XclImpChTypeGroupRef xTypeGroup
= typeGroup
.second
;
3573 xTypeGroup
->Finalize();
3574 if( xTypeGroup
->IsValidGroup() )
3575 aValidGroups
.emplace(typeGroup
.first
, xTypeGroup
);
3577 maTypeGroups
.swap( aValidGroups
);
3580 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3581 if( !IsValidAxesSet() )
3584 // always create missing axis objects
3586 mxXAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_X
);
3588 mxYAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_Y
);
3589 if( !mxZAxis
&& GetFirstTypeGroup()->Is3dDeepChart() )
3590 mxZAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_Z
);
3593 if( mxXAxis
) mxXAxis
->Finalize();
3594 if( mxYAxis
) mxYAxis
->Finalize();
3595 if( mxZAxis
) mxZAxis
->Finalize();
3597 // finalize axis titles
3598 const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE
);
3599 OUString
aAutoTitle(ScResId(STR_AXISTITLE
));
3600 lclFinalizeTitle( mxXAxisTitle
, pDefText
, aAutoTitle
);
3601 lclFinalizeTitle( mxYAxisTitle
, pDefText
, aAutoTitle
);
3602 lclFinalizeTitle( mxZAxisTitle
, pDefText
, aAutoTitle
);
3604 // #i47745# missing plot frame -> invisible border and area
3606 mxPlotFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
);
3609 XclImpChTypeGroupRef
XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3611 XclImpChTypeGroupMap::const_iterator itr
= maTypeGroups
.find(nGroupIdx
);
3612 return itr
== maTypeGroups
.end() ? XclImpChTypeGroupRef() : itr
->second
;
3615 XclImpChTypeGroupRef
XclImpChAxesSet::GetFirstTypeGroup() const
3617 XclImpChTypeGroupRef xTypeGroup
;
3618 if( !maTypeGroups
.empty() )
3619 xTypeGroup
= maTypeGroups
.begin()->second
;
3623 XclImpChLegendRef
XclImpChAxesSet::GetLegend() const
3625 XclImpChLegendRef xLegend
;
3626 for( const auto& rEntry
: maTypeGroups
)
3628 xLegend
= rEntry
.second
->GetLegend();
3635 OUString
XclImpChAxesSet::GetSingleSeriesTitle() const
3637 return (maTypeGroups
.size() == 1) ? maTypeGroups
.begin()->second
->GetSingleSeriesTitle() : OUString();
3640 void XclImpChAxesSet::Convert( Reference
< XDiagram
> const & xDiagram
) const
3642 if( !(IsValidAxesSet() && xDiagram
.is()) )
3645 // diagram background formatting
3646 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY
)
3647 ConvertBackground( xDiagram
);
3649 // create the coordinate system, this inserts all chart types and series
3650 Reference
< XCoordinateSystem
> xCoordSystem
= CreateCoordSystem( xDiagram
);
3651 if( !xCoordSystem
.is() )
3654 // insert coordinate system, if not already done
3657 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY_THROW
);
3658 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3659 if( !aCoordSystems
.hasElements() )
3660 xCoordSystemCont
->addCoordinateSystem( xCoordSystem
);
3664 OSL_FAIL( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3667 // create the axes with grids and axis titles and insert them into the diagram
3668 ConvertAxis( mxXAxis
, mxXAxisTitle
, xCoordSystem
, mxYAxis
.get() );
3669 ConvertAxis( mxYAxis
, mxYAxisTitle
, xCoordSystem
, mxXAxis
.get() );
3670 ConvertAxis( mxZAxis
, mxZAxisTitle
, xCoordSystem
, nullptr );
3673 void XclImpChAxesSet::ConvertTitlePositions() const
3676 mxXAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_X
) );
3678 mxYAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Y
) );
3680 mxZAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Z
) );
3683 void XclImpChAxesSet::ReadChAxis( XclImpStream
& rStrm
)
3685 XclImpChAxisRef xAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot() );
3686 xAxis
->ReadRecordGroup( rStrm
);
3688 switch( xAxis
->GetAxisType() )
3690 case EXC_CHAXIS_X
: mxXAxis
= xAxis
; break;
3691 case EXC_CHAXIS_Y
: mxYAxis
= xAxis
; break;
3692 case EXC_CHAXIS_Z
: mxZAxis
= xAxis
; break;
3696 void XclImpChAxesSet::ReadChText( XclImpStream
& rStrm
)
3698 XclImpChTextRef xText
= std::make_shared
<XclImpChText
>( GetChRoot() );
3699 xText
->ReadRecordGroup( rStrm
);
3701 switch( xText
->GetLinkTarget() )
3703 case EXC_CHOBJLINK_XAXIS
: mxXAxisTitle
= xText
; break;
3704 case EXC_CHOBJLINK_YAXIS
: mxYAxisTitle
= xText
; break;
3705 case EXC_CHOBJLINK_ZAXIS
: mxZAxisTitle
= xText
; break;
3709 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream
& rStrm
)
3711 if( (rStrm
.GetNextRecId() == EXC_ID_CHFRAME
) && rStrm
.StartNextRecord() )
3713 mxPlotFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
);
3714 mxPlotFrame
->ReadRecordGroup( rStrm
);
3718 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream
& rStrm
)
3720 XclImpChTypeGroupRef xTypeGroup
= std::make_shared
<XclImpChTypeGroup
>( GetChRoot() );
3721 xTypeGroup
->ReadRecordGroup( rStrm
);
3722 sal_uInt16 nGroupIdx
= xTypeGroup
->GetGroupIdx();
3723 XclImpChTypeGroupMap::iterator itr
= maTypeGroups
.lower_bound(nGroupIdx
);
3724 if (itr
!= maTypeGroups
.end() && !maTypeGroups
.key_comp()(nGroupIdx
, itr
->first
))
3725 // Overwrite the existing element.
3726 itr
->second
= xTypeGroup
;
3728 maTypeGroups
.insert(
3729 itr
, XclImpChTypeGroupMap::value_type(nGroupIdx
, xTypeGroup
));
3732 Reference
< XCoordinateSystem
> XclImpChAxesSet::CreateCoordSystem( Reference
< XDiagram
> const & xDiagram
) const
3734 Reference
< XCoordinateSystem
> xCoordSystem
;
3736 /* Try to get existing coordinate system. For now, all series from primary
3737 and secondary axes sets are inserted into one coordinate system. Later,
3738 this should be changed to use one coordinate system for each axes set. */
3739 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY
);
3740 if( xCoordSystemCont
.is() )
3742 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3743 OSL_ENSURE( aCoordSystems
.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3744 if( aCoordSystems
.hasElements() )
3745 xCoordSystem
= aCoordSystems
[ 0 ];
3748 // create the coordinate system according to the first chart type
3749 if( !xCoordSystem
.is() )
3751 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3754 xCoordSystem
= xTypeGroup
->CreateCoordSystem();
3755 // convert 3d chart settings
3756 ScfPropertySet
aDiaProp( xDiagram
);
3757 xTypeGroup
->ConvertChart3d( aDiaProp
);
3761 /* Create XChartType objects for all chart type groups. Each group will
3762 add its series to the data provider attached to the chart document. */
3763 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3764 if( xChartTypeCont
.is() )
3766 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3767 for( const auto& rEntry
: maTypeGroups
)
3771 Reference
< XChartType
> xChartType
= rEntry
.second
->CreateChartType( xDiagram
, nApiAxesSetIdx
);
3772 if( xChartType
.is() )
3773 xChartTypeCont
->addChartType( xChartType
);
3777 OSL_FAIL( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3782 return xCoordSystem
;
3785 void XclImpChAxesSet::ConvertAxis(
3786 XclImpChAxisRef
const & xChAxis
, XclImpChTextRef
const & xChAxisTitle
,
3787 Reference
< XCoordinateSystem
> const & xCoordSystem
, const XclImpChAxis
* pCrossingAxis
) const
3792 // create and attach the axis object
3793 Reference
< XAxis
> xAxis
= CreateAxis( *xChAxis
, pCrossingAxis
);
3797 // create and attach the axis title
3798 if( xChAxisTitle
) try
3800 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY_THROW
);
3801 Reference
< XTitle
> xTitle( xChAxisTitle
->CreateTitle(), UNO_SET_THROW
);
3802 xTitled
->setTitleObject( xTitle
);
3806 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3809 // insert axis into coordinate system
3812 sal_Int32 nApiAxisDim
= xChAxis
->GetApiAxisDimension();
3813 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3814 xCoordSystem
->setAxisByDimension( nApiAxisDim
, xAxis
, nApiAxesSetIdx
);
3818 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3822 Reference
< XAxis
> XclImpChAxesSet::CreateAxis( const XclImpChAxis
& rChAxis
, const XclImpChAxis
* pCrossingAxis
) const
3824 Reference
< XAxis
> xAxis
;
3825 if( const XclImpChTypeGroup
* pTypeGroup
= GetFirstTypeGroup().get() )
3826 xAxis
= rChAxis
.CreateAxis( *pTypeGroup
, pCrossingAxis
);
3830 void XclImpChAxesSet::ConvertBackground( Reference
< XDiagram
> const & xDiagram
) const
3832 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3833 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3835 // wall/floor formatting (3D charts)
3838 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3839 mxXAxis
->ConvertWall( aWallProp
);
3843 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3844 mxYAxis
->ConvertWall( aFloorProp
);
3847 else if( mxPlotFrame
)
3849 // diagram background formatting
3850 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3851 mxPlotFrame
->Convert( aWallProp
);
3855 // The chart object ===========================================================
3857 XclImpChChart::XclImpChChart( const XclImpRoot
& rRoot
) :
3858 XclImpChRoot( rRoot
, *this )
3860 mxPrimAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_PRIMARY
);
3861 mxSecnAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_SECONDARY
);
3864 XclImpChChart::~XclImpChChart()
3868 void XclImpChChart::ReadHeaderRecord( XclImpStream
& rStrm
)
3870 // coordinates are stored as 16.16 fixed point
3874 void XclImpChChart::ReadSubRecord( XclImpStream
& rStrm
)
3876 switch( rStrm
.GetRecId() )
3878 case EXC_ID_CHFRAME
:
3879 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
3880 mxFrame
->ReadRecordGroup( rStrm
);
3882 case EXC_ID_CHSERIES
:
3883 ReadChSeries( rStrm
);
3885 case EXC_ID_CHPROPERTIES
:
3886 ReadChProperties( rStrm
);
3888 case EXC_ID_CHDEFAULTTEXT
:
3889 ReadChDefaultText( rStrm
);
3891 case EXC_ID_CHAXESSET
:
3892 ReadChAxesSet( rStrm
);
3895 ReadChText( rStrm
);
3898 Finalize(); // finalize the entire chart object
3903 void XclImpChChart::ReadChDefaultText( XclImpStream
& rStrm
)
3905 sal_uInt16 nTextId
= rStrm
.ReaduInt16();
3906 if( (rStrm
.GetNextRecId() == EXC_ID_CHTEXT
) && rStrm
.StartNextRecord() )
3908 unique_ptr
<XclImpChText
> pText(new XclImpChText(GetChRoot()));
3909 pText
->ReadRecordGroup(rStrm
);
3910 m_DefTexts
.insert(std::make_pair(nTextId
, std::move(pText
)));
3914 void XclImpChChart::ReadChDataFormat( XclImpStream
& rStrm
)
3916 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
3917 xDataFmt
->ReadRecordGroup( rStrm
);
3918 if( xDataFmt
->GetPointPos().mnSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3920 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
3921 XclImpChDataFormatMap::iterator itr
= maDataFmts
.lower_bound(rPos
);
3922 if (itr
== maDataFmts
.end() || maDataFmts
.key_comp()(rPos
, itr
->first
))
3923 // No element exists for this data point. Insert it.
3925 itr
, XclImpChDataFormatMap::value_type(rPos
, xDataFmt
));
3927 /* Do not overwrite existing data format group, Excel always uses the
3928 first data format group occurring in any CHSERIES group. */
3932 void XclImpChChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
3935 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
3936 mxFrame
->UpdateObjFrame( rLineData
, rFillData
);
3939 XclImpChTypeGroupRef
XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3941 XclImpChTypeGroupRef xTypeGroup
= mxPrimAxesSet
->GetTypeGroup( nGroupIdx
);
3942 if( !xTypeGroup
) xTypeGroup
= mxSecnAxesSet
->GetTypeGroup( nGroupIdx
);
3943 if( !xTypeGroup
) xTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup();
3947 const XclImpChText
* XclImpChChart::GetDefaultText( XclChTextType eTextType
) const
3949 sal_uInt16 nDefTextId
= EXC_CHDEFTEXT_GLOBAL
;
3950 bool bBiff8
= GetBiff() == EXC_BIFF8
;
3953 case EXC_CHTEXTTYPE_TITLE
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3954 case EXC_CHTEXTTYPE_LEGEND
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3955 case EXC_CHTEXTTYPE_AXISTITLE
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3956 case EXC_CHTEXTTYPE_AXISLABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3957 case EXC_CHTEXTTYPE_DATALABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3960 XclImpChTextMap::const_iterator
const itr
= m_DefTexts
.find(nDefTextId
);
3961 return itr
== m_DefTexts
.end() ? nullptr : itr
->second
.get();
3964 bool XclImpChChart::IsManualPlotArea() const
3966 // there is no real automatic mode in BIFF5 charts
3967 return (GetBiff() <= EXC_BIFF5
) || ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3970 void XclImpChChart::Convert( const Reference
<XChartDocument
>& xChartDoc
,
3971 XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
3973 // initialize conversion (locks the model to suppress any internal updates)
3974 InitConversion( xChartDoc
, rChartRect
);
3976 // chart frame formatting
3979 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3980 mxFrame
->Convert( aFrameProp
);
3986 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY_THROW
);
3987 Reference
< XTitle
> xTitle( mxTitle
->CreateTitle(), UNO_SET_THROW
);
3988 xTitled
->setTitleObject( xTitle
);
3994 /* Create the diagram object and attach it to the chart document. Currently,
3995 one diagram is used to carry all coordinate systems and data series. */
3996 Reference
< XDiagram
> xDiagram
= CreateDiagram();
3997 xChartDoc
->setFirstDiagram( xDiagram
);
3999 // coordinate systems and chart types, convert axis settings
4000 mxPrimAxesSet
->Convert( xDiagram
);
4001 mxSecnAxesSet
->Convert( xDiagram
);
4004 if( xDiagram
.is() && mxLegend
)
4005 xDiagram
->setLegend( mxLegend
->CreateLegend() );
4007 /* Following all conversions needing the old Chart1 API that involves full
4008 initialization of the chart view. */
4009 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY
);
4010 if( xChart1Doc
.is() )
4012 Reference
< cssc::XDiagram
> xDiagram1
= xChart1Doc
->getDiagram();
4014 /* Set the 'IncludeHiddenCells' property via the old API as only this
4015 ensures that the data provider and all created sequences get this
4017 ScfPropertySet
aDiaProp( xDiagram1
);
4018 bool bShowVisCells
= ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
);
4019 aDiaProp
.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
, !bShowVisCells
);
4021 // plot area position and size (there is no real automatic mode in BIFF5 charts)
4022 XclImpChFramePosRef xPlotAreaPos
= mxPrimAxesSet
->GetPlotAreaFramePos();
4023 if( IsManualPlotArea() && xPlotAreaPos
) try
4025 const XclChFramePos
& rFramePos
= xPlotAreaPos
->GetFramePosData();
4026 if( (rFramePos
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rFramePos
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
) )
4028 Reference
< cssc::XDiagramPositioning
> xPositioning( xDiagram1
, UNO_QUERY_THROW
);
4029 css::awt::Rectangle aDiagramRect
= CalcHmmFromChartRect( rFramePos
.maRect
);
4030 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
4031 const XclImpChTypeGroup
* pFirstTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup().get();
4032 if( pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
4033 xPositioning
->setDiagramPositionExcludingAxes( aDiagramRect
);
4034 else if( pFirstTypeGroup
&& pFirstTypeGroup
->Is3dChart() )
4035 xPositioning
->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect
);
4037 xPositioning
->setDiagramPositionIncludingAxes( aDiagramRect
);
4044 // positions of all title objects
4046 mxTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE
) );
4047 mxPrimAxesSet
->ConvertTitlePositions();
4048 mxSecnAxesSet
->ConvertTitlePositions();
4052 FinishConversion( rDffConv
);
4054 // start listening to this chart
4055 ScDocument
& rDoc
= GetRoot().GetDoc();
4056 ScChartListenerCollection
* pChartCollection
= rDoc
.GetChartListenerCollection();
4057 if(!pChartCollection
)
4060 ::std::unique_ptr
< ::std::vector
< ScTokenRef
> > xRefTokens( new ::std::vector
< ScTokenRef
> );
4061 for( const auto& rxSeries
: maSeries
)
4062 rxSeries
->FillAllSourceLinks( *xRefTokens
);
4063 if( !xRefTokens
->empty() )
4065 ::std::unique_ptr
< ScChartListener
> xListener( new ScChartListener( rObjName
, rDoc
, std::move(xRefTokens
) ) );
4066 xListener
->SetUsed( true );
4067 xListener
->StartListeningTo();
4068 pChartCollection
->insert( xListener
.release() );
4072 void XclImpChChart::ReadChSeries( XclImpStream
& rStrm
)
4074 sal_uInt16 nNewSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.size() );
4075 XclImpChSeriesRef xSeries
= std::make_shared
<XclImpChSeries
>( GetChRoot(), nNewSeriesIdx
);
4076 xSeries
->ReadRecordGroup( rStrm
);
4077 maSeries
.push_back( xSeries
);
4080 void XclImpChChart::ReadChProperties( XclImpStream
& rStrm
)
4082 maProps
.mnFlags
= rStrm
.ReaduInt16();
4083 maProps
.mnEmptyMode
= rStrm
.ReaduInt8();
4086 void XclImpChChart::ReadChAxesSet( XclImpStream
& rStrm
)
4088 XclImpChAxesSetRef xAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_NONE
);
4089 xAxesSet
->ReadRecordGroup( rStrm
);
4090 switch( xAxesSet
->GetAxesSetId() )
4092 case EXC_CHAXESSET_PRIMARY
: mxPrimAxesSet
= xAxesSet
; break;
4093 case EXC_CHAXESSET_SECONDARY
: mxSecnAxesSet
= xAxesSet
; break;
4097 void XclImpChChart::ReadChText( XclImpStream
& rStrm
)
4099 XclImpChTextRef xText
= std::make_shared
<XclImpChText
>( GetChRoot() );
4100 xText
->ReadRecordGroup( rStrm
);
4101 switch( xText
->GetLinkTarget() )
4103 case EXC_CHOBJLINK_TITLE
:
4106 case EXC_CHOBJLINK_DATA
:
4108 sal_uInt16 nSeriesIdx
= xText
->GetPointPos().mnSeriesIdx
;
4109 if( nSeriesIdx
< maSeries
.size() )
4110 maSeries
[ nSeriesIdx
]->SetDataLabel( xText
);
4116 void XclImpChChart::Finalize()
4118 // finalize series (must be done first)
4120 // #i49218# legend may be attached to primary or secondary axes set
4121 mxLegend
= mxPrimAxesSet
->GetLegend();
4123 mxLegend
= mxSecnAxesSet
->GetLegend();
4125 mxLegend
->Finalize();
4126 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
4127 mxPrimAxesSet
->Finalize();
4128 mxSecnAxesSet
->Finalize();
4129 // formatting of all series
4130 FinalizeDataFormats();
4131 // #i47745# missing frame -> invisible border and area
4133 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
4138 void XclImpChChart::FinalizeSeries()
4140 for( const XclImpChSeriesRef
& xSeries
: maSeries
)
4142 if( xSeries
->HasParentSeries() )
4144 /* Process child series (trend lines and error bars). Data of
4145 child series will be set at the connected parent series. */
4146 if( xSeries
->GetParentIdx() < maSeries
.size() )
4147 maSeries
[ xSeries
->GetParentIdx() ]->AddChildSeries( *xSeries
);
4151 // insert the series into the related chart type group
4152 if( XclImpChTypeGroup
* pTypeGroup
= GetTypeGroup( xSeries
->GetGroupIdx() ).get() )
4153 pTypeGroup
->AddSeries( xSeries
);
4158 void XclImpChChart::FinalizeDataFormats()
4160 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4161 Each CHDATAFORMAT group specifies the series and data point it is
4162 assigned to. This makes it possible to have a data format that is
4163 related to another series, e.g. a CHDATAFORMAT group for series 2 is
4164 part of a CHSERIES group that describes series 1. Therefore the chart
4165 itself has collected all CHDATAFORMAT groups to be able to store data
4166 format groups for series that have not been imported at that time. This
4167 loop finally assigns these groups to the related series. */
4168 for( const auto& [rPos
, rDataFmt
] : maDataFmts
)
4170 sal_uInt16 nSeriesIdx
= rPos
.mnSeriesIdx
;
4171 if( nSeriesIdx
< maSeries
.size() )
4172 maSeries
[ nSeriesIdx
]->SetDataFormat( rDataFmt
);
4175 /* #i51639# (part 2): Finalize data formats of all series. This adds for
4176 example missing CHDATAFORMAT groups for entire series that are needed
4177 for automatic colors of lines and areas. */
4178 for( auto& rxSeries
: maSeries
)
4179 rxSeries
->FinalizeDataFormats();
4182 void XclImpChChart::FinalizeTitle()
4184 // special handling for auto-generated title
4185 OUString aAutoTitle
;
4186 if( !mxTitle
|| (!mxTitle
->IsDeleted() && !mxTitle
->HasString()) )
4188 // automatic title from first series name (if there are no series on secondary axes set)
4189 if( !mxSecnAxesSet
->IsValidAxesSet() )
4190 aAutoTitle
= mxPrimAxesSet
->GetSingleSeriesTitle();
4191 if( mxTitle
|| (!aAutoTitle
.isEmpty()) )
4194 mxTitle
= std::make_shared
<XclImpChText
>( GetChRoot() );
4195 if( aAutoTitle
.isEmpty() )
4196 aAutoTitle
= ScResId(STR_CHARTTITLE
);
4200 // will reset mxTitle, if it does not contain a string and no auto title exists
4201 lclFinalizeTitle( mxTitle
, GetDefaultText( EXC_CHTEXTTYPE_TITLE
), aAutoTitle
);
4204 Reference
< XDiagram
> XclImpChChart::CreateDiagram() const
4206 // create a diagram object
4207 Reference
< XDiagram
> xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM
), UNO_QUERY
);
4209 // convert global chart settings
4210 ScfPropertySet
aDiaProp( xDiagram
);
4212 // treatment of missing values
4213 using namespace cssc::MissingValueTreatment
;
4214 sal_Int32 nMissingValues
= LEAVE_GAP
;
4215 switch( maProps
.mnEmptyMode
)
4217 case EXC_CHPROPS_EMPTY_SKIP
: nMissingValues
= LEAVE_GAP
; break;
4218 case EXC_CHPROPS_EMPTY_ZERO
: nMissingValues
= USE_ZERO
; break;
4219 case EXC_CHPROPS_EMPTY_INTERPOLATE
: nMissingValues
= CONTINUE
; break;
4221 aDiaProp
.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT
, nMissingValues
);
4226 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4227 XclImpDrawing( rRoot
, bOwnTab
), // sheet charts may contain OLE objects
4228 mnScTab( rRoot
.GetCurrScTab() ),
4233 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter
& rDffConv
,
4234 const Reference
< XModel
>& rxModel
, const tools::Rectangle
& rChartRect
)
4236 maChartRect
= rChartRect
; // needed in CalcAnchorRect() callback
4238 SdrModel
* pSdrModel
= nullptr;
4239 SdrPage
* pSdrPage
= nullptr;
4242 // chart sheet: insert all shapes into the sheet, not into the chart object
4243 pSdrModel
= GetDoc().GetDrawLayer();
4244 pSdrPage
= GetSdrPage( mnScTab
);
4248 // embedded chart object: insert all shapes into the chart
4251 Reference
< XDrawPageSupplier
> xDrawPageSupp( rxModel
, UNO_QUERY_THROW
);
4252 Reference
< XDrawPage
> xDrawPage( xDrawPageSupp
->getDrawPage(), UNO_SET_THROW
);
4253 pSdrPage
= ::GetSdrPageFromXDrawPage( xDrawPage
);
4254 pSdrModel
= pSdrPage
? &pSdrPage
->getSdrModelFromSdrPage() : nullptr;
4261 if( pSdrModel
&& pSdrPage
)
4262 ImplConvertObjects( rDffConv
, *pSdrModel
, *pSdrPage
);
4265 tools::Rectangle
XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor
& rAnchor
, bool bDffAnchor
) const
4267 /* In objects with DFF client anchor, the position of the shape is stored
4268 in the cell address components of the client anchor. In old BIFF3-BIFF5
4269 objects, the position is stored in the offset components of the anchor. */
4270 tools::Rectangle
aRect(
4271 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnCol
: rAnchor
.mnLX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4272 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnRow
: rAnchor
.mnTY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ),
4273 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnCol
: rAnchor
.mnRX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4274 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnRow
: rAnchor
.mnBY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ) );
4276 // move shapes into chart area for sheet charts
4278 aRect
.Move( maChartRect
.Left(), maChartRect
.Top() );
4282 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase
& )
4286 XclImpChart::XclImpChart( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4287 XclImpRoot( rRoot
),
4288 mbOwnTab( bOwnTab
),
4289 mbIsPivotChart( false )
4293 XclImpChart::~XclImpChart()
4297 void XclImpChart::ReadChartSubStream( XclImpStream
& rStrm
)
4299 XclImpPageSettings
& rPageSett
= GetPageSettings();
4300 XclImpTabViewSettings
& rTabViewSett
= GetTabViewSettings();
4303 while( bLoop
&& rStrm
.StartNextRecord() )
4305 // page settings - only for charts in entire sheet
4306 if( mbOwnTab
) switch( rStrm
.GetRecId() )
4308 case EXC_ID_HORPAGEBREAKS
:
4309 case EXC_ID_VERPAGEBREAKS
: rPageSett
.ReadPageBreaks( rStrm
); break;
4311 case EXC_ID_FOOTER
: rPageSett
.ReadHeaderFooter( rStrm
); break;
4312 case EXC_ID_LEFTMARGIN
:
4313 case EXC_ID_RIGHTMARGIN
:
4314 case EXC_ID_TOPMARGIN
:
4315 case EXC_ID_BOTTOMMARGIN
: rPageSett
.ReadMargin( rStrm
); break;
4316 case EXC_ID_PRINTHEADERS
: rPageSett
.ReadPrintHeaders( rStrm
); break;
4317 case EXC_ID_PRINTGRIDLINES
: rPageSett
.ReadPrintGridLines( rStrm
); break;
4318 case EXC_ID_HCENTER
:
4319 case EXC_ID_VCENTER
: rPageSett
.ReadCenter( rStrm
); break;
4320 case EXC_ID_SETUP
: rPageSett
.ReadSetup( rStrm
); break;
4321 case EXC_ID8_IMGDATA
: rPageSett
.ReadImgData( rStrm
); break;
4323 case EXC_ID_WINDOW2
: rTabViewSett
.ReadWindow2( rStrm
, true );break;
4324 case EXC_ID_SCL
: rTabViewSett
.ReadScl( rStrm
); break;
4326 case EXC_ID_SHEETEXT
: //0x0862
4328 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4329 XclImpPalette
& rPal
= GetPalette();
4330 rTabViewSett
.ReadTabBgColor( rStrm
, rPal
);
4334 case EXC_ID_CODENAME
: ReadCodeName( rStrm
, false ); break;
4338 switch( rStrm
.GetRecId() )
4340 case EXC_ID_EOF
: bLoop
= false; break;
4342 // #i31882# ignore embedded chart objects
4346 case EXC_ID5_BOF
: XclTools::SkipSubStream( rStrm
); break;
4348 case EXC_ID_CHCHART
: ReadChChart( rStrm
); break;
4350 case EXC_ID8_CHPIVOTREF
:
4351 GetTracer().TracePivotChartExists();
4352 mbIsPivotChart
= true;
4355 // BIFF specific records
4356 default: switch( GetBiff() )
4358 case EXC_BIFF5
: switch( rStrm
.GetRecId() )
4360 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4363 case EXC_BIFF8
: switch( rStrm
.GetRecId() )
4365 case EXC_ID_MSODRAWING
: GetChartDrawing().ReadMsoDrawing( rStrm
); break;
4366 // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4367 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4376 void XclImpChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
4379 mxChartData
= std::make_shared
<XclImpChChart
>( GetRoot() );
4380 mxChartData
->UpdateObjFrame( rLineData
, rFillData
);
4383 std::size_t XclImpChart::GetProgressSize() const
4386 (mxChartData
? XclImpChChart::GetProgressSize() : 0) +
4387 (mxChartDrawing
? mxChartDrawing
->GetProgressSize() : 0);
4390 void XclImpChart::Convert( Reference
< XModel
> const & xModel
, XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
4392 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
4393 if( xChartDoc
.is() )
4396 mxChartData
->Convert( xChartDoc
, rDffConv
, rObjName
, rChartRect
);
4397 if( mxChartDrawing
)
4398 mxChartDrawing
->ConvertObjects( rDffConv
, xModel
, rChartRect
);
4402 XclImpChartDrawing
& XclImpChart::GetChartDrawing()
4404 if( !mxChartDrawing
)
4405 mxChartDrawing
= std::make_shared
<XclImpChartDrawing
>( GetRoot(), mbOwnTab
);
4406 return *mxChartDrawing
;
4409 void XclImpChart::ReadChChart( XclImpStream
& rStrm
)
4411 mxChartData
= std::make_shared
<XclImpChChart
>( GetRoot() );
4412 mxChartData
->ReadRecordGroup( rStrm
);
4415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */