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>
89 #include <tokenarray.hxx>
90 #include <compiler.hxx>
91 #include <reftokenhelper.hxx>
92 #include <chartlis.hxx>
93 #include <globstr.hrc>
94 #include <scresid.hxx>
95 #include <xltracer.hxx>
96 #include <xltools.hxx>
97 #include <xistream.hxx>
98 #include <xiformula.hxx>
99 #include <xistyle.hxx>
100 #include <xipage.hxx>
101 #include <xiview.hxx>
103 using ::com::sun::star::uno::Any
;
104 using ::com::sun::star::uno::Reference
;
105 using ::com::sun::star::uno::Sequence
;
106 using ::com::sun::star::uno::UNO_QUERY
;
107 using ::com::sun::star::uno::UNO_QUERY_THROW
;
108 using ::com::sun::star::uno::UNO_SET_THROW
;
109 using ::com::sun::star::uno::Exception
;
110 using ::com::sun::star::beans::XPropertySet
;
111 using ::com::sun::star::frame::XModel
;
112 using ::com::sun::star::util::XNumberFormatsSupplier
;
113 using ::com::sun::star::drawing::XDrawPage
;
114 using ::com::sun::star::drawing::XDrawPageSupplier
;
115 using ::com::sun::star::drawing::XShape
;
117 using namespace ::com::sun::star::chart2
;
119 using ::com::sun::star::chart2::data::XDataProvider
;
120 using ::com::sun::star::chart2::data::XDataReceiver
;
121 using ::com::sun::star::chart2::data::XDataSequence
;
122 using ::com::sun::star::chart2::data::XDataSink
;
123 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
124 using ::com::sun::star::chart2::data::LabeledDataSequence
;
126 using ::formula::FormulaToken
;
127 using ::formula::FormulaTokenArrayPlainIterator
;
128 using ::std::unique_ptr
;
130 namespace cssc
= ::com::sun::star::chart
;
131 namespace cssc2
= ::com::sun::star::chart2
;
133 // Helpers ====================================================================
137 XclImpStream
& operator>>( XclImpStream
& rStrm
, XclChRectangle
& rRect
)
139 rRect
.mnX
= rStrm
.ReadInt32();
140 rRect
.mnY
= rStrm
.ReadInt32();
141 rRect
.mnWidth
= rStrm
.ReadInt32();
142 rRect
.mnHeight
= rStrm
.ReadInt32();
146 void lclSetValueOrClearAny( Any
& rAny
, double fValue
, bool bClear
)
154 void lclSetExpValueOrClearAny( Any
& rAny
, double fValue
, bool bLogScale
, bool bClear
)
156 if( !bClear
&& bLogScale
)
157 fValue
= pow( 10.0, fValue
);
158 lclSetValueOrClearAny( rAny
, fValue
, bClear
);
161 double lclGetSerialDay( const XclImpRoot
& rRoot
, sal_uInt16 nValue
, sal_uInt16 nTimeUnit
)
165 case EXC_CHDATERANGE_DAYS
:
167 case EXC_CHDATERANGE_MONTHS
:
168 return rRoot
.GetDoubleFromDateTime( DateTime( Date( 1, static_cast< sal_uInt16
>( 1 + nValue
% 12 ), static_cast< sal_uInt16
>( rRoot
.GetBaseYear() + nValue
/ 12 ) ) ) );
169 case EXC_CHDATERANGE_YEARS
:
170 return rRoot
.GetDoubleFromDateTime( DateTime( Date( 1, 1, static_cast< sal_uInt16
>( rRoot
.GetBaseYear() + nValue
) ) ) );
172 OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
177 void lclConvertTimeValue( const XclImpRoot
& rRoot
, Any
& rAny
, sal_uInt16 nValue
, bool bAuto
, sal_uInt16 nTimeUnit
)
182 rAny
<<= lclGetSerialDay( rRoot
, nValue
, nTimeUnit
);
185 sal_Int32
lclGetApiTimeUnit( sal_uInt16 nTimeUnit
)
189 case EXC_CHDATERANGE_DAYS
: return cssc::TimeUnit::DAY
;
190 case EXC_CHDATERANGE_MONTHS
: return cssc::TimeUnit::MONTH
;
191 case EXC_CHDATERANGE_YEARS
: return cssc::TimeUnit::YEAR
;
192 default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
194 return cssc::TimeUnit::DAY
;
197 void lclConvertTimeInterval( Any
& rInterval
, sal_uInt16 nValue
, bool bAuto
, sal_uInt16 nTimeUnit
)
199 if( bAuto
|| (nValue
== 0) )
202 rInterval
<<= cssc::TimeInterval( nValue
, lclGetApiTimeUnit( nTimeUnit
) );
207 // Common =====================================================================
209 /** Stores global data needed in various classes of the Chart import filter. */
210 struct XclImpChRootData
: public XclChRootData
212 XclImpChChart
& mrChartData
; /// The chart data object.
214 explicit XclImpChRootData( XclImpChChart
& rChartData
) : mrChartData( rChartData
) {}
217 XclImpChRoot::XclImpChRoot( const XclImpRoot
& rRoot
, XclImpChChart
& rChartData
) :
219 mxChData( std::make_shared
<XclImpChRootData
>( rChartData
) )
223 XclImpChRoot::~XclImpChRoot()
227 XclImpChChart
& XclImpChRoot::GetChartData() const
229 return mxChData
->mrChartData
;
232 const XclChTypeInfo
& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType
) const
234 return mxChData
->mxTypeInfoProv
->GetTypeInfo( eType
);
237 const XclChTypeInfo
& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId
) const
239 return mxChData
->mxTypeInfoProv
->GetTypeInfoFromRecId( nRecId
);
242 const XclChFormatInfo
& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType
) const
244 return mxChData
->mxFmtInfoProv
->GetFormatInfo( eObjType
);
247 Color
XclImpChRoot::GetFontAutoColor() const
249 return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT
);
252 Color
XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx
) const
254 return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx
) );
257 Color
XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx
) const
259 const XclImpPalette
& rPal
= GetPalette();
260 Color aColor
= rPal
.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx
) );
261 sal_uInt8 nTrans
= XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx
);
262 return ScfTools::GetMixedColor( aColor
, rPal
.GetColor( EXC_COLOR_CHWINDOWBACK
), nTrans
);
265 void XclImpChRoot::InitConversion( const Reference
<XChartDocument
>& xChartDoc
, const tools::Rectangle
& rChartRect
) const
267 // create formatting object tables
268 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
270 // lock the model to suppress any internal updates
272 xChartDoc
->lockControllers();
274 ScDocShell
* pDocShell
= GetDocShell();
275 Reference
< XDataReceiver
> xDataRec( xChartDoc
, UNO_QUERY
);
276 if( pDocShell
&& xDataRec
.is() )
278 // create and register a data provider
279 Reference
< XDataProvider
> xDataProv(
280 ScfApiHelper::CreateInstance( pDocShell
, SERVICE_CHART2_DATAPROVIDER
), UNO_QUERY
);
282 xDataRec
->attachDataProvider( xDataProv
);
283 // attach the number formatter
284 Reference
< XNumberFormatsSupplier
> xNumFmtSupp( static_cast<cppu::OWeakObject
*>(pDocShell
->GetModel()), UNO_QUERY
);
285 if( xNumFmtSupp
.is() )
286 xDataRec
->attachNumberFormatsSupplier( xNumFmtSupp
);
290 void XclImpChRoot::FinishConversion( XclImpDffConverter
& rDffConv
) const
292 rDffConv
.Progress( EXC_CHART_PROGRESS_SIZE
);
294 Reference
< XModel
> xModel
= mxChData
->mxChartDoc
;
296 xModel
->unlockControllers();
297 rDffConv
.Progress( EXC_CHART_PROGRESS_SIZE
);
299 mxChData
->FinishConversion();
302 Reference
< XDataProvider
> XclImpChRoot::GetDataProvider() const
304 return mxChData
->mxChartDoc
->getDataProvider();
307 Reference
< XShape
> XclImpChRoot::GetTitleShape( const XclChTextKey
& rTitleKey
) const
309 return mxChData
->GetTitleShape( rTitleKey
);
312 sal_Int32
XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX
) const
314 return static_cast< sal_Int32
>( mxChData
->mfUnitSizeX
* nPosX
+ mxChData
->mnBorderGapX
+ 0.5 );
317 sal_Int32
XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY
) const
319 return static_cast< sal_Int32
>( mxChData
->mfUnitSizeY
* nPosY
+ mxChData
->mnBorderGapY
+ 0.5 );
322 css::awt::Rectangle
XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle
& rRect
) const
324 return css::awt::Rectangle(
325 CalcHmmFromChartX( rRect
.mnX
),
326 CalcHmmFromChartY( rRect
.mnY
),
327 CalcHmmFromChartX( rRect
.mnWidth
),
328 CalcHmmFromChartY( rRect
.mnHeight
) );
331 double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX
) const
333 const tools::Long nWidth
= mxChData
->maChartRect
.GetWidth();
335 throw o3tl::divide_by_zero();
336 return static_cast<double>(nPosX
) / nWidth
;
339 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY
) const
341 const tools::Long nHeight
= mxChData
->maChartRect
.GetHeight();
343 throw o3tl::divide_by_zero();
344 return static_cast<double >(nPosY
) / nHeight
;
347 double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX
) const
349 return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX
) );
352 double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY
) const
354 return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY
) );
357 void XclImpChRoot::ConvertLineFormat( ScfPropertySet
& rPropSet
,
358 const XclChLineFormat
& rLineFmt
, XclChPropertyMode ePropMode
) const
360 GetChartPropSetHelper().WriteLineProperties(
361 rPropSet
, *mxChData
->mxLineDashTable
, rLineFmt
, ePropMode
);
364 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet
& rPropSet
,
365 const XclChAreaFormat
& rAreaFmt
, XclChPropertyMode ePropMode
) const
367 GetChartPropSetHelper().WriteAreaProperties( rPropSet
, rAreaFmt
, ePropMode
);
370 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet
& rPropSet
,
371 const XclChEscherFormat
& rEscherFmt
, const XclChPicFormat
* pPicFmt
,
372 sal_uInt32 nDffFillType
, XclChPropertyMode ePropMode
) const
374 GetChartPropSetHelper().WriteEscherProperties( rPropSet
,
375 *mxChData
->mxGradientTable
, *mxChData
->mxBitmapTable
,
376 rEscherFmt
, pPicFmt
, nDffFillType
, ePropMode
);
379 void XclImpChRoot::ConvertFont( ScfPropertySet
& rPropSet
,
380 sal_uInt16 nFontIdx
, const Color
* pFontColor
) const
382 GetFontBuffer().WriteFontProperties( rPropSet
, EXC_FONTPROPSET_CHART
, nFontIdx
, pFontColor
);
385 void XclImpChRoot::ConvertPieRotation( ScfPropertySet
& rPropSet
, sal_uInt16 nAngle
)
387 sal_Int32 nApiRot
= (450 - (nAngle
% 360)) % 360;
388 rPropSet
.SetProperty( EXC_CHPROP_STARTINGANGLE
, nApiRot
);
391 XclImpChGroupBase::~XclImpChGroupBase()
395 void XclImpChGroupBase::ReadRecordGroup( XclImpStream
& rStrm
)
397 // read contents of the header record
398 ReadHeaderRecord( rStrm
);
400 // only read sub records, if the next record is a CHBEGIN
401 if( rStrm
.GetNextRecId() != EXC_ID_CHBEGIN
)
404 // read the CHBEGIN record, may be used for special initial processing
405 rStrm
.StartNextRecord();
406 ReadSubRecord( rStrm
);
408 // read the nested records
410 while( bLoop
&& rStrm
.StartNextRecord() )
412 sal_uInt16 nRecId
= rStrm
.GetRecId();
413 bLoop
= nRecId
!= EXC_ID_CHEND
;
414 // skip unsupported nested blocks
415 if( nRecId
== EXC_ID_CHBEGIN
)
418 ReadSubRecord( rStrm
);
420 /* Returns with current CHEND record or unchanged stream, if no record
421 group present. In every case another call to StartNextRecord() will go
422 to next record of interest. */
425 void XclImpChGroupBase::SkipBlock( XclImpStream
& rStrm
)
427 OSL_ENSURE( rStrm
.GetRecId() == EXC_ID_CHBEGIN
, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
428 // do nothing if current record is not CHBEGIN
429 bool bLoop
= rStrm
.GetRecId() == EXC_ID_CHBEGIN
;
430 while( bLoop
&& rStrm
.StartNextRecord() )
432 sal_uInt16 nRecId
= rStrm
.GetRecId();
433 bLoop
= nRecId
!= EXC_ID_CHEND
;
434 // skip nested record groups
435 if( nRecId
== EXC_ID_CHBEGIN
)
440 // Frame formatting ===========================================================
442 void XclImpChFramePos::ReadChFramePos( XclImpStream
& rStrm
)
444 maData
.mnTLMode
= rStrm
.ReaduInt16();
445 maData
.mnBRMode
= rStrm
.ReaduInt16();
446 /* According to the spec, the upper 16 bits of all members in the
447 rectangle are unused and may contain garbage. */
448 maData
.maRect
.mnX
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
449 maData
.maRect
.mnY
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
450 maData
.maRect
.mnWidth
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
451 maData
.maRect
.mnHeight
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
454 void XclImpChLineFormat::ReadChLineFormat( XclImpStream
& rStrm
)
456 rStrm
>> maData
.maColor
;
457 maData
.mnPattern
= rStrm
.ReaduInt16();
458 maData
.mnWeight
= rStrm
.ReadInt16();
459 maData
.mnFlags
= rStrm
.ReaduInt16();
461 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
462 if( rRoot
.GetBiff() == EXC_BIFF8
)
463 // BIFF8: index into palette used instead of RGB data
464 maData
.maColor
= rRoot
.GetPalette().GetColor( rStrm
.ReaduInt16() );
467 void XclImpChLineFormat::Convert( const XclImpChRoot
& rRoot
,
468 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
470 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
473 XclChLineFormat aLineFmt
;
474 aLineFmt
.maColor
= (eObjType
== EXC_CHOBJTYPE_LINEARSERIES
) ?
475 rRoot
.GetSeriesLineAutoColor( nFormatIdx
) :
476 rRoot
.GetPalette().GetColor( rFmtInfo
.mnAutoLineColorIdx
);
477 aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
;
478 aLineFmt
.mnWeight
= rFmtInfo
.mnAutoLineWeight
;
479 rRoot
.ConvertLineFormat( rPropSet
, aLineFmt
, rFmtInfo
.mePropMode
);
483 rRoot
.ConvertLineFormat( rPropSet
, maData
, rFmtInfo
.mePropMode
);
487 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream
& rStrm
)
489 rStrm
>> maData
.maPattColor
>> maData
.maBackColor
;
490 maData
.mnPattern
= rStrm
.ReaduInt16();
491 maData
.mnFlags
= rStrm
.ReaduInt16();
493 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
494 if( rRoot
.GetBiff() == EXC_BIFF8
)
496 // BIFF8: index into palette used instead of RGB data
497 const XclImpPalette
& rPal
= rRoot
.GetPalette();
498 maData
.maPattColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
499 maData
.maBackColor
= rPal
.GetColor( rStrm
.ReaduInt16());
503 void XclImpChAreaFormat::Convert( const XclImpChRoot
& rRoot
,
504 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
506 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
509 XclChAreaFormat aAreaFmt
;
510 aAreaFmt
.maPattColor
= (eObjType
== EXC_CHOBJTYPE_FILLEDSERIES
) ?
511 rRoot
.GetSeriesFillAutoColor( nFormatIdx
) :
512 rRoot
.GetPalette().GetColor( rFmtInfo
.mnAutoPattColorIdx
);
513 aAreaFmt
.mnPattern
= EXC_PATT_SOLID
;
514 rRoot
.ConvertAreaFormat( rPropSet
, aAreaFmt
, rFmtInfo
.mePropMode
);
518 rRoot
.ConvertAreaFormat( rPropSet
, maData
, rFmtInfo
.mePropMode
);
522 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot
& rRoot
) :
523 mnDffFillType( mso_fillSolid
)
526 std::make_shared
<SfxItemSet
>( rRoot
.GetDoc().GetDrawLayer()->GetItemPool() );
529 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream
& rStrm
)
531 // read from stream - CHESCHERFORMAT uses own ID for record continuation
532 XclImpDffPropSet
aPropSet( rStrm
.GetRoot() );
533 rStrm
.ResetRecord( true, rStrm
.GetRecId() );
536 aPropSet
.FillToItemSet( *maData
.mxItemSet
);
537 // get fill type from DFF property set
538 mnDffFillType
= aPropSet
.GetPropertyValue( DFF_Prop_fillType
);
541 void XclImpChEscherFormat::ReadSubRecord( XclImpStream
& rStrm
)
543 switch( rStrm
.GetRecId() )
545 case EXC_ID_CHPICFORMAT
:
546 maPicFmt
.mnBmpMode
= rStrm
.ReaduInt16();
548 maPicFmt
.mnFlags
= rStrm
.ReaduInt16();
549 maPicFmt
.mfScale
= rStrm
.ReadDouble();
554 void XclImpChEscherFormat::Convert( const XclImpChRoot
& rRoot
,
555 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, bool bUsePicFmt
) const
557 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
558 rRoot
.ConvertEscherFormat( rPropSet
, maData
, bUsePicFmt
? &maPicFmt
: nullptr, mnDffFillType
, rFmtInfo
.mePropMode
);
561 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo
& rFmtInfo
)
563 if( !rFmtInfo
.mbCreateDefFrame
)
566 switch( rFmtInfo
.meDefFrameType
)
568 case EXC_CHFRAMETYPE_AUTO
:
569 mxLineFmt
= new XclImpChLineFormat();
570 if( rFmtInfo
.mbIsFrame
)
571 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
573 case EXC_CHFRAMETYPE_INVISIBLE
:
575 XclChLineFormat aLineFmt
;
576 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, false );
577 aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
578 mxLineFmt
= new XclImpChLineFormat( aLineFmt
);
579 if( rFmtInfo
.mbIsFrame
)
581 XclChAreaFormat aAreaFmt
;
582 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, false );
583 aAreaFmt
.mnPattern
= EXC_PATT_NONE
;
584 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>( aAreaFmt
);
589 OSL_FAIL( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
593 void XclImpChFrameBase::ReadSubRecord( XclImpStream
& rStrm
)
595 switch( rStrm
.GetRecId() )
597 case EXC_ID_CHLINEFORMAT
:
598 mxLineFmt
= new XclImpChLineFormat();
599 mxLineFmt
->ReadChLineFormat( rStrm
);
601 case EXC_ID_CHAREAFORMAT
:
602 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
603 mxAreaFmt
->ReadChAreaFormat( rStrm
);
605 case EXC_ID_CHESCHERFORMAT
:
606 mxEscherFmt
= std::make_shared
<XclImpChEscherFormat
>( rStrm
.GetRoot() );
607 mxEscherFmt
->ReadRecordGroup( rStrm
);
612 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot
& rRoot
,
613 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
616 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
619 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot
& rRoot
,
620 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
622 if( rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
624 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
626 mxEscherFmt
->Convert( rRoot
, rPropSet
, eObjType
, bUsePicFmt
);
628 mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
632 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot
& rRoot
,
633 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
635 ConvertLineBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
636 ConvertAreaBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
, bUsePicFmt
);
639 XclImpChFrame::XclImpChFrame( const XclImpChRoot
& rRoot
, XclChObjectType eObjType
) :
640 XclImpChFrameBase( rRoot
.GetFormatInfo( eObjType
) ),
641 XclImpChRoot( rRoot
),
642 meObjType( eObjType
)
646 void XclImpChFrame::ReadHeaderRecord( XclImpStream
& rStrm
)
648 maData
.mnFormat
= rStrm
.ReaduInt16();
649 maData
.mnFlags
= rStrm
.ReaduInt16();
652 void XclImpChFrame::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
654 const XclImpPalette
& rPal
= GetPalette();
656 if( rLineData
.IsVisible() && (!mxLineFmt
|| !mxLineFmt
->HasLine()) )
659 XclChLineFormat aLineFmt
;
660 aLineFmt
.maColor
= rPal
.GetColor( rLineData
.mnColorIdx
);
661 switch( rLineData
.mnStyle
)
663 case EXC_OBJ_LINE_SOLID
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
; break;
664 case EXC_OBJ_LINE_DASH
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASH
; break;
665 case EXC_OBJ_LINE_DOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DOT
; break;
666 case EXC_OBJ_LINE_DASHDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOT
; break;
667 case EXC_OBJ_LINE_DASHDOTDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOTDOT
; break;
668 case EXC_OBJ_LINE_MEDTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_MEDTRANS
; break;
669 case EXC_OBJ_LINE_DARKTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DARKTRANS
; break;
670 case EXC_OBJ_LINE_LIGHTTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_LIGHTTRANS
; break;
671 case EXC_OBJ_LINE_NONE
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
; break;
672 default: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
;
674 switch( rLineData
.mnWidth
)
676 case EXC_OBJ_LINE_HAIR
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
; break;
677 case EXC_OBJ_LINE_THIN
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_SINGLE
; break;
678 case EXC_OBJ_LINE_MEDIUM
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_DOUBLE
; break;
679 case EXC_OBJ_LINE_THICK
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_TRIPLE
; break;
680 default: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
;
682 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, rLineData
.IsAuto() );
683 mxLineFmt
= new XclImpChLineFormat( aLineFmt
);
686 if( rFillData
.IsFilled() && (!mxAreaFmt
|| !mxAreaFmt
->HasArea()) && !mxEscherFmt
)
689 XclChAreaFormat aAreaFmt
;
690 aAreaFmt
.maPattColor
= rPal
.GetColor( rFillData
.mnPattColorIdx
);
691 aAreaFmt
.maBackColor
= rPal
.GetColor( rFillData
.mnBackColorIdx
);
692 aAreaFmt
.mnPattern
= rFillData
.mnPattern
;
693 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, rFillData
.IsAuto() );
694 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>( aAreaFmt
);
698 void XclImpChFrame::Convert( ScfPropertySet
& rPropSet
, bool bUsePicFmt
) const
700 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
, EXC_CHDATAFORMAT_UNKNOWN
, bUsePicFmt
);
703 // Source links ===============================================================
707 /** Creates a labeled data sequence object, adds link for series title if present. */
708 Reference
< XLabeledDataSequence
> lclCreateLabeledDataSequence(
709 const XclImpChSourceLinkRef
& xValueLink
, const OUString
& rValueRole
,
710 const XclImpChSourceLink
* pTitleLink
= nullptr )
712 // create data sequence for values and title
713 Reference
< XDataSequence
> xValueSeq
;
715 xValueSeq
= xValueLink
->CreateDataSequence( rValueRole
);
716 Reference
< XDataSequence
> xTitleSeq
;
718 xTitleSeq
= pTitleLink
->CreateDataSequence( EXC_CHPROP_ROLE_LABEL
);
720 // create the labeled data sequence, if values or title are present
721 Reference
< XLabeledDataSequence
> xLabeledSeq
;
722 if( xValueSeq
.is() || xTitleSeq
.is() )
723 xLabeledSeq
= LabeledDataSequence::create(comphelper::getProcessComponentContext());
724 if( xLabeledSeq
.is() )
727 xLabeledSeq
->setValues( xValueSeq
);
729 xLabeledSeq
->setLabel( xTitleSeq
);
736 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot
& rRoot
) :
737 XclImpChRoot( rRoot
)
741 XclImpChSourceLink::~XclImpChSourceLink()
745 void XclImpChSourceLink::ReadChSourceLink( XclImpStream
& rStrm
)
747 maData
.mnDestType
= rStrm
.ReaduInt8();
748 maData
.mnLinkType
= rStrm
.ReaduInt8();
749 maData
.mnFlags
= rStrm
.ReaduInt16();
750 maData
.mnNumFmtIdx
= rStrm
.ReaduInt16();
752 mxTokenArray
.reset();
753 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET
)
756 XclTokenArray aXclTokArr
;
759 // convert BIFF formula tokens to Calc token array
760 if( std::unique_ptr
<ScTokenArray
> pTokens
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aXclTokArr
) )
761 mxTokenArray
= std::move( pTokens
);
764 // try to read a following CHSTRING record
765 if( (rStrm
.GetNextRecId() == EXC_ID_CHSTRING
) && rStrm
.StartNextRecord() )
767 mxString
= std::make_shared
<XclImpString
>();
769 mxString
->Read( rStrm
, XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
773 void XclImpChSourceLink::SetString( const OUString
& rString
)
776 mxString
= std::make_shared
<XclImpString
>();
777 mxString
->SetText( rString
);
780 void XclImpChSourceLink::SetTextFormats( XclFormatRunVec
&& rFormats
)
783 mxString
->SetFormats( std::move(rFormats
) );
786 sal_uInt16
XclImpChSourceLink::GetCellCount() const
788 sal_uInt32 nCellCount
= 0;
791 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
792 for( const FormulaToken
* pToken
= aIter
.First(); pToken
; pToken
= aIter
.Next() )
794 switch( pToken
->GetType() )
796 case ::formula::svSingleRef
:
797 case ::formula::svExternalSingleRef
:
801 case ::formula::svDoubleRef
:
802 case ::formula::svExternalDoubleRef
:
805 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
806 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(GetRoot().GetDoc(), ScAddress());
807 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(GetRoot().GetDoc(), ScAddress());
808 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
809 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
810 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
811 nCellCount
+= nCols
* nRows
* nTabs
;
818 return limit_cast
< sal_uInt16
>( nCellCount
);
821 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
823 bool bLinkToSource
= ::get_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
824 sal_uInt32 nScNumFmt
= bLinkToSource
? GetNumFmtBuffer().GetScFormat( maData
.mnNumFmtIdx
) : NUMBERFORMAT_ENTRY_NOT_FOUND
;
825 OUString aPropName
= bPercent
? EXC_CHPROP_PERCENTAGENUMFMT
: EXC_CHPROP_NUMBERFORMAT
;
826 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
827 rPropSet
.SetProperty( aPropName
, static_cast< sal_Int32
>( nScNumFmt
) );
829 // restore 'link to source' at data point (series may contain manual number format)
830 rPropSet
.SetAnyProperty( aPropName
, Any() );
833 Reference
< XDataSequence
> XclImpChSourceLink::CreateDataSequence( const OUString
& rRole
) const
835 Reference
< XDataSequence
> xDataSeq
;
836 Reference
< XDataProvider
> xDataProv
= GetDataProvider();
841 ScCompiler
aComp( GetDoc(), ScAddress(), *mxTokenArray
, GetDoc().GetGrammar() );
842 OUStringBuffer aRangeRep
;
843 aComp
.CreateStringFromTokenArray( aRangeRep
);
846 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aRangeRep
.makeStringAndClear() );
848 ScfPropertySet
aSeqProp( xDataSeq
);
849 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
853 // OSL_FAIL( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
856 else if( rRole
== EXC_CHPROP_ROLE_LABEL
&& mxString
&& !mxString
->GetText().isEmpty() )
860 OUString
aString(u
"\""_ustr
);
861 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aString
+ mxString
->GetText() + aString
);
863 ScfPropertySet
aSeqProp( xDataSeq
);
864 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
866 catch( Exception
& ) { }
872 Sequence
< Reference
< XFormattedString
> > XclImpChSourceLink::CreateStringSequence(
873 const XclImpChRoot
& rRoot
, sal_uInt16 nLeadFontIdx
, const Color
& rLeadFontColor
) const
875 ::std::vector
< Reference
< XFormattedString
> > aStringVec
;
878 for( XclImpStringIterator
aIt( *mxString
); aIt
.Is(); ++aIt
)
880 Reference
< css::chart2::XFormattedString2
> xFmtStr
= css::chart2::FormattedString::create( comphelper::getProcessComponentContext() );
882 xFmtStr
->setString( aIt
.GetPortionText() );
884 // set font formatting and font color
885 ScfPropertySet
aStringProp( xFmtStr
);
886 sal_uInt16 nFontIdx
= aIt
.GetPortionFont();
887 if( (nFontIdx
== EXC_FONT_NOTFOUND
) && (aIt
.GetPortionIndex() == 0) )
888 // leading unformatted portion - use passed font settings
889 rRoot
.ConvertFont( aStringProp
, nLeadFontIdx
, &rLeadFontColor
);
891 rRoot
.ConvertFont( aStringProp
, nFontIdx
);
893 // add string to vector of strings
894 aStringVec
.emplace_back(xFmtStr
);
897 return ScfApiHelper::VectorToSequence( aStringVec
);
900 void XclImpChSourceLink::FillSourceLink( ::std::vector
< ScTokenRef
>& rTokens
) const
906 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
907 for (FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
909 ScTokenRef
pToken(p
->Clone());
910 if (ScRefTokenHelper::isRef(pToken
))
911 // This is a reference token. Store it.
912 ScRefTokenHelper::join(&GetRoot().GetDoc(), rTokens
, pToken
, ScAddress());
916 // Text =======================================================================
918 XclImpChFontBase::~XclImpChFontBase()
922 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
924 Color aFontColor
= GetFontColor();
925 rRoot
.ConvertFont( rPropSet
, GetFontIndex(), &aFontColor
);
928 void XclImpChFontBase::ConvertRotationBase( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
930 XclChPropSetHelper::WriteRotationProperties( rPropSet
, GetRotation(), bSupportsStacked
);
933 XclImpChFont::XclImpChFont() :
934 mnFontIdx( EXC_FONT_NOTFOUND
)
938 void XclImpChFont::ReadChFont( XclImpStream
& rStrm
)
940 mnFontIdx
= rStrm
.ReaduInt16();
943 XclImpChText::XclImpChText( const XclImpChRoot
& rRoot
) :
944 XclImpChRoot( rRoot
)
948 void XclImpChText::ReadHeaderRecord( XclImpStream
& rStrm
)
950 maData
.mnHAlign
= rStrm
.ReaduInt8();
951 maData
.mnVAlign
= rStrm
.ReaduInt8();
952 maData
.mnBackMode
= rStrm
.ReaduInt16();
956 maData
.maTextComplexColor
.setColor(aColor
);
958 rStrm
>> maData
.maRect
;
959 maData
.mnFlags
= rStrm
.ReaduInt16();
961 if( GetBiff() == EXC_BIFF8
)
963 // BIFF8: index into palette used instead of RGB data
964 aColor
= GetPalette().GetColor(rStrm
.ReaduInt16());
965 maData
.maTextComplexColor
.setColor(aColor
);
966 // placement and rotation
967 maData
.mnFlags2
= rStrm
.ReaduInt16();
968 maData
.mnRotation
= rStrm
.ReaduInt16();
972 // BIFF2-BIFF7: get rotation from text orientation
973 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 8, 3 );
974 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
978 void XclImpChText::ReadSubRecord( XclImpStream
& rStrm
)
980 switch( rStrm
.GetRecId() )
982 case EXC_ID_CHFRAMEPOS
:
983 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
984 mxFramePos
->ReadChFramePos( rStrm
);
987 mxFont
= std::make_shared
<XclImpChFont
>();
988 mxFont
->ReadChFont( rStrm
);
990 case EXC_ID_CHFORMATRUNS
:
991 if( GetBiff() == EXC_BIFF8
)
992 XclImpString::ReadFormats( rStrm
, maFormats
);
994 case EXC_ID_CHSOURCELINK
:
995 mxSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
996 mxSrcLink
->ReadChSourceLink( rStrm
);
999 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_TEXT
);
1000 mxFrame
->ReadRecordGroup( rStrm
);
1002 case EXC_ID_CHOBJECTLINK
:
1003 maObjLink
.mnTarget
= rStrm
.ReaduInt16();
1004 maObjLink
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
1005 maObjLink
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
1007 case EXC_ID_CHFRLABELPROPS
:
1008 ReadChFrLabelProps( rStrm
);
1011 if( mxSrcLink
&& !maFormats
.empty() )
1012 mxSrcLink
->SetTextFormats( std::vector(maFormats
) );
1017 sal_uInt16
XclImpChText::GetFontIndex() const
1019 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
1022 Color
XclImpChText::GetFontColor() const
1024 return ::get_flag(maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextComplexColor
.getFinalColor();
1027 sal_uInt16
XclImpChText::GetRotation() const
1029 return maData
.mnRotation
;
1032 void XclImpChText::SetString( const OUString
& rString
)
1035 mxSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
1036 mxSrcLink
->SetString( rString
);
1039 void XclImpChText::UpdateText( const XclImpChText
* pParentText
)
1044 // update missing members
1046 mxFrame
= pParentText
->mxFrame
;
1049 mxFont
= pParentText
->mxFont
;
1050 // text color is taken from CHTEXT record, not from font in CHFONT
1051 ::set_flag(maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, ::get_flag(pParentText
->maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
));
1052 maData
.maTextComplexColor
= pParentText
->maData
.maTextComplexColor
;
1056 void XclImpChText::UpdateDataLabel( bool bCateg
, bool bValue
, bool bPercent
)
1058 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bCateg
);
1059 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bValue
);
1060 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bPercent
);
1061 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bCateg
&& bPercent
);
1062 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bCateg
&& !bValue
&& !bPercent
);
1065 void XclImpChText::ConvertFont( ScfPropertySet
& rPropSet
) const
1067 ConvertFontBase( GetChRoot(), rPropSet
);
1070 void XclImpChText::ConvertRotation( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
1072 ConvertRotationBase( rPropSet
, bSupportsStacked
);
1075 void XclImpChText::ConvertFrame( ScfPropertySet
& rPropSet
) const
1078 mxFrame
->Convert( rPropSet
);
1081 void XclImpChText::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
1084 mxSrcLink
->ConvertNumFmt( rPropSet
, bPercent
);
1087 void XclImpChText::ConvertDataLabel( ScfPropertySet
& rPropSet
, const XclChTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1089 // existing CHFRLABELPROPS record wins over flags from CHTEXT
1090 sal_uInt16 nShowFlags
= mxLabelProps
? mxLabelProps
->mnFlags
: maData
.mnFlags
;
1091 sal_uInt16 SHOWANYCATEG
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWCATEG
: (EXC_CHTEXT_SHOWCATEGPERC
| EXC_CHTEXT_SHOWCATEG
);
1092 sal_uInt16 SHOWANYVALUE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWVALUE
: EXC_CHTEXT_SHOWVALUE
;
1093 sal_uInt16 SHOWANYPERCENT
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWPERCENT
: (EXC_CHTEXT_SHOWPERCENT
| EXC_CHTEXT_SHOWCATEGPERC
);
1094 sal_uInt16 SHOWANYBUBBLE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWBUBBLE
: EXC_CHTEXT_SHOWBUBBLE
;
1096 // get raw flags for label values
1097 bool bShowNone
= IsDeleted();
1098 bool bShowCateg
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYCATEG
);
1099 bool bShowPercent
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYPERCENT
);
1100 bool bShowValue
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYVALUE
);
1101 bool bShowBubble
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYBUBBLE
);
1103 // adjust to Chart2 behaviour
1104 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
1105 bShowValue
= bShowBubble
; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1108 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
;
1109 bool bShowSymbol
= bShowAny
&& ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
);
1111 // create API struct for label values, set API label separator
1112 cssc2::DataPointLabel
aPointLabel( bShowValue
, bShowPercent
, bShowCateg
, bShowSymbol
, false, false );
1113 rPropSet
.SetProperty( EXC_CHPROP_LABEL
, aPointLabel
);
1114 OUString aSep
= mxLabelProps
? mxLabelProps
->maSeparator
: OUString('\n');
1115 if( aSep
.isEmpty() )
1117 rPropSet
.SetStringProperty( EXC_CHPROP_LABELSEPARATOR
, aSep
);
1119 // text properties of attached label
1123 ConvertFont( rPropSet
);
1124 ConvertRotation( rPropSet
, false );
1126 using namespace cssc::DataLabelPlacement
;
1127 sal_Int32 nPlacement
= rTypeInfo
.mnDefaultLabelPos
;
1128 switch( ::extract_value
< sal_uInt16
>( maData
.mnFlags2
, 0, 4 ) )
1130 case EXC_CHTEXT_POS_DEFAULT
: nPlacement
= rTypeInfo
.mnDefaultLabelPos
; break;
1131 case EXC_CHTEXT_POS_OUTSIDE
: nPlacement
= OUTSIDE
; break;
1132 case EXC_CHTEXT_POS_INSIDE
: nPlacement
= INSIDE
; break;
1133 case EXC_CHTEXT_POS_CENTER
: nPlacement
= CENTER
; break;
1134 case EXC_CHTEXT_POS_AXIS
: nPlacement
= NEAR_ORIGIN
; break;
1135 case EXC_CHTEXT_POS_ABOVE
: nPlacement
= TOP
; break;
1136 case EXC_CHTEXT_POS_BELOW
: nPlacement
= BOTTOM
; break;
1137 case EXC_CHTEXT_POS_LEFT
: nPlacement
= LEFT
; break;
1138 case EXC_CHTEXT_POS_RIGHT
: nPlacement
= RIGHT
; break;
1139 case EXC_CHTEXT_POS_AUTO
: nPlacement
= AVOID_OVERLAP
; break;
1141 sal_Int32 nGlobalPlacement
= 0;
1142 if ( ( nPlacement
== rTypeInfo
.mnDefaultLabelPos
) && pGlobalPropSet
&&
1143 pGlobalPropSet
->GetProperty( nGlobalPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1144 nPlacement
= nGlobalPlacement
;
1146 rPropSet
.SetProperty( EXC_CHPROP_LABELPLACEMENT
, nPlacement
);
1147 // label number format (percentage format wins over value format)
1148 if( bShowPercent
|| bShowValue
)
1149 ConvertNumFmt( rPropSet
, bShowPercent
);
1152 Reference
< XTitle
> XclImpChText::CreateTitle() const
1154 Reference
< XTitle
> xTitle
;
1155 if( mxSrcLink
&& mxSrcLink
->HasString() )
1157 // create the formatted strings
1158 Sequence
< Reference
< XFormattedString
> > aStringSeq(
1159 mxSrcLink
->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1160 if( aStringSeq
.hasElements() )
1162 // create the title object
1163 xTitle
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE
), UNO_QUERY
);
1166 // set the formatted strings
1167 xTitle
->setText( aStringSeq
);
1168 // more title formatting properties
1169 ScfPropertySet
aTitleProp( xTitle
);
1170 ConvertFrame( aTitleProp
);
1171 ConvertRotation( aTitleProp
, true );
1178 void XclImpChText::ConvertTitlePosition( const XclChTextKey
& rTitleKey
) const
1180 if( !mxFramePos
) return;
1182 const XclChFramePos
& rPosData
= mxFramePos
->GetFramePosData();
1183 OSL_ENSURE( (rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rPosData
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
),
1184 "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1186 /* Check if title is moved manually. To get the actual position of the
1187 title, we do some kind of hack and use the values from the CHTEXT
1188 record, effectively ignoring the contents of the CHFRAMEPOS record
1189 which contains the position relative to the default title position
1190 (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1191 Especially when it comes to axis titles, things would become very
1192 complicated here, because the relative title position is stored in a
1193 measurement unit that is dependent on the size of the inner plot area,
1194 the interpretation of the X and Y coordinate is dependent on the
1195 direction of the axis, and in 3D charts, and the title default
1196 positions are dependent on the 3D view settings (rotation, elevation,
1197 and perspective). Thus, it is easier to assume that the creator has
1198 written out the correct absolute position and size of the title in the
1199 CHTEXT record. This is assured by checking that the shape size stored
1200 in the CHTEXT record is non-zero. */
1201 if( !((rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) &&
1202 ((rPosData
.maRect
.mnX
!= 0) || (rPosData
.maRect
.mnY
!= 0)) &&
1203 (maData
.maRect
.mnWidth
> 0) && (maData
.maRect
.mnHeight
> 0)) )
1208 Reference
< XShape
> xTitleShape( GetTitleShape( rTitleKey
), UNO_SET_THROW
);
1209 // the call to XShape.getSize() may recalc the chart view
1210 css::awt::Size aTitleSize
= xTitleShape
->getSize();
1211 // rotated titles need special handling...
1212 Degree100 nScRot
= XclTools::GetScRotation( GetRotation(), 0_deg100
);
1213 double fRad
= toRadians(nScRot
);
1214 double fSin
= fabs( sin( fRad
) );
1215 // calculate the title position from the values in the CHTEXT record
1216 css::awt::Point
aTitlePos(
1217 CalcHmmFromChartX( maData
.maRect
.mnX
),
1218 CalcHmmFromChartY( maData
.maRect
.mnY
) );
1219 // add part of height to X direction, if title is rotated down (clockwise)
1220 if( nScRot
> 18000_deg100
)
1221 aTitlePos
.X
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Height
+ 0.5 );
1222 // add part of width to Y direction, if title is rotated up (counterclockwise)
1223 else if( nScRot
> 0_deg100
)
1224 aTitlePos
.Y
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Width
+ 0.5 );
1225 // set the resulting position at the title shape
1226 xTitleShape
->setPosition( aTitlePos
);
1233 void XclImpChText::ReadChFrLabelProps( XclImpStream
& rStrm
)
1235 if( GetBiff() == EXC_BIFF8
)
1237 mxLabelProps
= std::make_shared
<XclChFrLabelProps
>();
1240 mxLabelProps
->mnFlags
= rStrm
.ReaduInt16();
1241 nSepLen
= rStrm
.ReaduInt16();
1243 mxLabelProps
->maSeparator
= rStrm
.ReadUniString( nSepLen
);
1249 void lclUpdateText( XclImpChTextRef
& rxText
, const XclImpChText
* xDefText
)
1252 rxText
->UpdateText( xDefText
);
1255 rxText
= std::make_shared
<XclImpChText
>(*xDefText
);
1259 void lclFinalizeTitle( XclImpChTextRef
& rxTitle
, const XclImpChText
* pDefText
, const OUString
& rAutoTitle
)
1261 /* Do not update a title, if it is not visible (if rxTitle is null).
1262 Existing reference indicates enabled title. */
1265 if( !rxTitle
->HasString() )
1266 rxTitle
->SetString( rAutoTitle
);
1267 if( rxTitle
->HasString() )
1268 rxTitle
->UpdateText(pDefText
);
1276 // Data series ================================================================
1278 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream
& rStrm
)
1280 rStrm
>> maData
.maLineColor
>> maData
.maFillColor
;
1281 maData
.mnMarkerType
= rStrm
.ReaduInt16();
1282 maData
.mnFlags
= rStrm
.ReaduInt16();
1284 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
1285 if( rRoot
.GetBiff() == EXC_BIFF8
)
1287 // BIFF8: index into palette used instead of RGB data
1288 const XclImpPalette
& rPal
= rRoot
.GetPalette();
1289 maData
.maLineColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1290 maData
.maFillColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1292 maData
.mnMarkerSize
= rStrm
.ReaduInt32();
1296 void XclImpChMarkerFormat::Convert( const XclImpChRoot
& rRoot
,
1297 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
, sal_Int16 nLineWeight
) const
1301 XclChMarkerFormat aMarkerFmt
;
1302 // line and fill color of the symbol are equal to series line color
1303 //TODO: Excel sets no fill color for specific symbols (e.g. cross)
1304 aMarkerFmt
.maLineColor
= aMarkerFmt
.maFillColor
= rRoot
.GetSeriesLineAutoColor( nFormatIdx
);
1305 switch( nLineWeight
)
1307 case EXC_CHLINEFORMAT_HAIR
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_HAIRSIZE
; break;
1308 case EXC_CHLINEFORMAT_SINGLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
; break;
1309 case EXC_CHLINEFORMAT_DOUBLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
; break;
1310 case EXC_CHLINEFORMAT_TRIPLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_TRIPLESIZE
; break;
1311 default: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
;
1313 aMarkerFmt
.mnMarkerType
= XclChartHelper::GetAutoMarkerType( nFormatIdx
);
1314 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, aMarkerFmt
);
1318 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, maData
);
1322 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot
& rRoot
,
1323 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1325 Color aLineColor
= IsAuto() ? rRoot
.GetSeriesLineAutoColor( nFormatIdx
) : maData
.maFillColor
;
1326 rPropSet
.SetColorProperty( EXC_CHPROP_COLOR
, aLineColor
);
1329 XclImpChPieFormat::XclImpChPieFormat() :
1334 void XclImpChPieFormat::ReadChPieFormat( XclImpStream
& rStrm
)
1336 mnPieDist
= rStrm
.ReaduInt16();
1339 void XclImpChPieFormat::Convert( ScfPropertySet
& rPropSet
) const
1341 double fApiDist
= ::std::min
< double >( mnPieDist
/ 100.0, 1.0 );
1342 rPropSet
.SetProperty( EXC_CHPROP_OFFSET
, fApiDist
);
1345 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1350 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream
& rStrm
)
1352 mnFlags
= rStrm
.ReaduInt16();
1355 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream
& rStrm
)
1357 maData
.mnBase
= rStrm
.ReaduInt8();
1358 maData
.mnTop
= rStrm
.ReaduInt8();
1361 void XclImpCh3dDataFormat::Convert( ScfPropertySet
& rPropSet
) const
1363 using namespace ::com::sun::star::chart2::DataPointGeometry3D
;
1364 sal_Int32 nApiType
= (maData
.mnBase
== EXC_CH3DDATAFORMAT_RECT
) ?
1365 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CUBOID
: PYRAMID
) :
1366 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CYLINDER
: CONE
);
1367 rPropSet
.SetProperty( EXC_CHPROP_GEOMETRY3D
, nApiType
);
1370 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot
& rRoot
) :
1371 XclImpChRoot( rRoot
),
1376 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream
& rStrm
)
1378 mnFlags
= rStrm
.ReaduInt16();
1381 XclImpChTextRef
XclImpChAttachedLabel::CreateDataLabel( const XclImpChText
* pParent
) const
1383 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE
= EXC_CHATTLABEL_SHOWVALUE
;
1384 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT
= EXC_CHATTLABEL_SHOWPERCENT
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1385 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG
= EXC_CHATTLABEL_SHOWCATEG
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1387 XclImpChTextRef xLabel
;
1389 xLabel
= std::make_shared
<XclImpChText
>( *pParent
);
1391 xLabel
= std::make_shared
<XclImpChText
>( GetChRoot() );
1392 xLabel
->UpdateDataLabel(
1393 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYCATEG
),
1394 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYVALUE
),
1395 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYPERCENT
) );
1399 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot
& rRoot
) :
1400 XclImpChRoot( rRoot
)
1404 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream
& rStrm
)
1406 maData
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
1407 maData
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
1408 maData
.mnFormatIdx
= rStrm
.ReaduInt16();
1409 maData
.mnFlags
= rStrm
.ReaduInt16();
1412 void XclImpChDataFormat::ReadSubRecord( XclImpStream
& rStrm
)
1414 switch( rStrm
.GetRecId() )
1416 case EXC_ID_CHMARKERFORMAT
:
1417 mxMarkerFmt
= std::make_shared
<XclImpChMarkerFormat
>();
1418 mxMarkerFmt
->ReadChMarkerFormat( rStrm
);
1420 case EXC_ID_CHPIEFORMAT
:
1421 mxPieFmt
= std::make_shared
<XclImpChPieFormat
>();
1422 mxPieFmt
->ReadChPieFormat( rStrm
);
1424 case EXC_ID_CHSERIESFORMAT
:
1425 mxSeriesFmt
= std::make_shared
<XclImpChSeriesFormat
>();
1426 mxSeriesFmt
->ReadChSeriesFormat( rStrm
);
1428 case EXC_ID_CH3DDATAFORMAT
:
1429 mx3dDataFmt
= std::make_shared
<XclImpCh3dDataFormat
>();
1430 mx3dDataFmt
->ReadCh3dDataFormat( rStrm
);
1432 case EXC_ID_CHATTACHEDLABEL
:
1433 mxAttLabel
= std::make_shared
<XclImpChAttachedLabel
>( GetChRoot() );
1434 mxAttLabel
->ReadChAttachedLabel( rStrm
);
1437 XclImpChFrameBase::ReadSubRecord( rStrm
);
1441 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
)
1443 maData
.maPointPos
= rPointPos
;
1444 maData
.mnFormatIdx
= nFormatIdx
;
1447 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo
& rTypeInfo
)
1449 // remove formats not used for the current chart type
1450 RemoveUnusedFormats( rTypeInfo
);
1453 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pGroupFmt
)
1455 // update missing formats from passed chart type group format
1459 mxLineFmt
= pGroupFmt
->mxLineFmt
;
1460 if( !mxAreaFmt
&& !mxEscherFmt
)
1462 mxAreaFmt
= pGroupFmt
->mxAreaFmt
;
1463 mxEscherFmt
= pGroupFmt
->mxEscherFmt
;
1466 mxMarkerFmt
= pGroupFmt
->mxMarkerFmt
;
1468 mxPieFmt
= pGroupFmt
->mxPieFmt
;
1470 mxSeriesFmt
= pGroupFmt
->mxSeriesFmt
;
1472 mx3dDataFmt
= pGroupFmt
->mx3dDataFmt
;
1474 mxAttLabel
= pGroupFmt
->mxAttLabel
;
1477 /* Create missing but required formats. Existing line, area, and marker
1478 format objects are needed to create automatic series formatting. */
1480 mxLineFmt
= new XclImpChLineFormat();
1481 if( !mxAreaFmt
&& !mxEscherFmt
)
1482 mxAreaFmt
= std::make_shared
<XclImpChAreaFormat
>();
1484 mxMarkerFmt
= std::make_shared
<XclImpChMarkerFormat
>();
1486 // remove formats not used for the current chart type
1487 RemoveUnusedFormats( rTypeInfo
);
1488 // update data label
1489 UpdateDataLabel( pGroupFmt
);
1492 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pSeriesFmt
)
1494 // remove formats if they are automatic in this and in the passed series format
1497 if( IsAutoLine() && pSeriesFmt
->IsAutoLine() )
1499 if( IsAutoArea() && pSeriesFmt
->IsAutoArea() )
1501 if( IsAutoMarker() && pSeriesFmt
->IsAutoMarker() )
1502 mxMarkerFmt
.reset();
1503 mxSeriesFmt
.reset();
1506 // Excel ignores 3D bar format for single data points
1507 mx3dDataFmt
.reset();
1508 // remove point line formats for linear chart types, TODO: implement in OOChart
1509 if( !rTypeInfo
.IsSeriesFrameFormat() )
1512 // remove formats not used for the current chart type
1513 RemoveUnusedFormats( rTypeInfo
);
1514 // update data label
1515 UpdateDataLabel( pSeriesFmt
);
1518 void XclImpChDataFormat::UpdateTrendLineFormat()
1521 mxLineFmt
= new XclImpChLineFormat();
1523 mxEscherFmt
.reset();
1524 mxMarkerFmt
.reset();
1526 mxSeriesFmt
.reset();
1527 mx3dDataFmt
.reset();
1529 // update data label
1530 UpdateDataLabel( nullptr );
1533 void XclImpChDataFormat::Convert( ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1535 /* Line and area format.
1536 #i71810# If the data points are filled with bitmaps, textures, or
1537 patterns, then only bar charts will use the CHPICFORMAT record to
1538 determine stacking/stretching mode. All other chart types ignore this
1539 record and always use the property 'fill-type' from the DFF property
1540 set (stretched for bitmaps, and stacked for textures and patterns). */
1541 bool bUsePicFmt
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
;
1542 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType(), maData
.mnFormatIdx
, bUsePicFmt
);
1544 // #i83151# only hair lines in 3D charts with filled data points
1545 if( rTypeInfo
.mb3dChart
&& rTypeInfo
.IsSeriesFrameFormat() && mxLineFmt
&& mxLineFmt
->HasLine() )
1546 rPropSet
.SetProperty
< sal_Int32
>( u
"BorderWidth"_ustr
, 0 );
1550 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
, GetLineWeight() );
1552 mxPieFmt
->Convert( rPropSet
);
1554 mx3dDataFmt
->Convert( rPropSet
);
1556 mxLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, pGlobalPropSet
);
1559 rPropSet
.SetProperty
< sal_Int16
>( EXC_CHPROP_PERCENTDIAGONAL
, 0 );
1561 /* Special case: set marker color as line color, if series line is not
1562 visible. This makes the color visible in the marker area.
1563 TODO: remove this if OOChart supports own colors in markers. */
1564 if( !rTypeInfo
.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt
)
1565 mxMarkerFmt
->ConvertColor( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1568 void XclImpChDataFormat::ConvertLine( ScfPropertySet
& rPropSet
, XclChObjectType eObjType
) const
1570 ConvertLineBase( GetChRoot(), rPropSet
, eObjType
);
1573 void XclImpChDataFormat::ConvertArea( ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1575 ConvertAreaBase( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_FILLEDSERIES
, nFormatIdx
);
1578 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo
& rTypeInfo
)
1580 // data point marker only in linear 2D charts
1581 if( rTypeInfo
.IsSeriesFrameFormat() )
1582 mxMarkerFmt
.reset();
1583 // pie format only in pie/donut charts
1584 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
1586 // 3D format only in 3D bar charts
1587 if( !rTypeInfo
.mb3dChart
|| (rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
1588 mx3dDataFmt
.reset();
1591 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat
* pParentFmt
)
1593 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1594 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1595 group, the contents of the CHATTACHEDLABEL record are used. In this
1596 case a new CHTEXT group is created and filled with the settings from
1597 the CHATTACHEDLABEL record. */
1598 const XclImpChText
* pDefText
= nullptr;
1600 pDefText
= pParentFmt
->GetDataLabel();
1602 pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL
);
1604 mxLabel
->UpdateText(pDefText
);
1605 else if (mxAttLabel
)
1606 mxLabel
= mxAttLabel
->CreateDataLabel( pDefText
);
1609 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot
& rRoot
) :
1610 XclImpChRoot( rRoot
)
1614 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream
& rStrm
)
1616 maData
.mnLineType
= rStrm
.ReaduInt8();
1617 maData
.mnOrder
= rStrm
.ReaduInt8();
1618 maData
.mfIntercept
= rStrm
.ReadDouble();
1619 maData
.mnShowEquation
= rStrm
.ReaduInt8();
1620 maData
.mnShowRSquared
= rStrm
.ReaduInt8();
1621 maData
.mfForecastFor
= rStrm
.ReadDouble();
1622 maData
.mfForecastBack
= rStrm
.ReadDouble();
1625 Reference
< XRegressionCurve
> XclImpChSerTrendLine::CreateRegressionCurve() const
1628 Reference
< XRegressionCurve
> xRegCurve
;
1629 switch( maData
.mnLineType
)
1631 case EXC_CHSERTREND_POLYNOMIAL
:
1632 if( maData
.mnOrder
== 1 )
1634 xRegCurve
= LinearRegressionCurve::create( comphelper::getProcessComponentContext() );
1636 xRegCurve
= PolynomialRegressionCurve::create( comphelper::getProcessComponentContext() );
1639 case EXC_CHSERTREND_EXPONENTIAL
:
1640 xRegCurve
= ExponentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1642 case EXC_CHSERTREND_LOGARITHMIC
:
1643 xRegCurve
= LogarithmicRegressionCurve::create( comphelper::getProcessComponentContext() );
1645 case EXC_CHSERTREND_POWER
:
1646 xRegCurve
= PotentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1648 case EXC_CHSERTREND_MOVING_AVG
:
1649 xRegCurve
= MovingAverageRegressionCurve::create( comphelper::getProcessComponentContext() );
1653 // trend line formatting
1654 if( xRegCurve
.is() && mxDataFmt
)
1656 ScfPropertySet
aPropSet( xRegCurve
);
1657 mxDataFmt
->ConvertLine( aPropSet
, EXC_CHOBJTYPE_TRENDLINE
);
1659 aPropSet
.SetProperty(EXC_CHPROP_CURVENAME
, maTrendLineName
);
1660 aPropSet
.SetProperty(EXC_CHPROP_POLYNOMIAL_DEGREE
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1661 aPropSet
.SetProperty(EXC_CHPROP_MOVING_AVERAGE_PERIOD
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1662 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_FORWARD
, maData
.mfForecastFor
);
1663 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_BACKWARD
, maData
.mfForecastBack
);
1665 bool bForceIntercept
= std::isfinite(maData
.mfIntercept
);
1666 aPropSet
.SetProperty(EXC_CHPROP_FORCE_INTERCEPT
, bForceIntercept
);
1667 if (bForceIntercept
)
1669 aPropSet
.SetProperty(EXC_CHPROP_INTERCEPT_VALUE
, maData
.mfIntercept
);
1672 // #i83100# show equation and correlation coefficient
1673 ScfPropertySet
aLabelProp( xRegCurve
->getEquationProperties() );
1674 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWEQUATION
, maData
.mnShowEquation
!= 0 );
1675 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION
, maData
.mnShowRSquared
!= 0 );
1677 // #i83100# formatting of the equation text box
1678 if (const XclImpChText
* pLabel
= mxDataFmt
->GetDataLabel())
1680 pLabel
->ConvertFont( aLabelProp
);
1681 pLabel
->ConvertFrame( aLabelProp
);
1682 pLabel
->ConvertNumFmt( aLabelProp
, false );
1689 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot
& rRoot
) :
1690 XclImpChRoot( rRoot
)
1694 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream
& rStrm
)
1696 maData
.mnBarType
= rStrm
.ReaduInt8();
1697 maData
.mnSourceType
= rStrm
.ReaduInt8();
1698 maData
.mnLineEnd
= rStrm
.ReaduInt8();
1700 maData
.mfValue
= rStrm
.ReadDouble();
1701 maData
.mnValueCount
= rStrm
.ReaduInt16();
1704 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef
const & xValueLink
, XclImpChDataFormatRef
const & xDataFmt
)
1706 mxValueLink
= xValueLink
;
1707 mxDataFmt
= xDataFmt
;
1710 Reference
< XLabeledDataSequence
> XclImpChSerErrorBar::CreateValueSequence() const
1712 return lclCreateLabeledDataSequence( mxValueLink
, XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
) );
1715 Reference
< XPropertySet
> XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar
* pPosBar
, const XclImpChSerErrorBar
* pNegBar
)
1717 Reference
< XPropertySet
> xErrorBar
;
1719 if( const XclImpChSerErrorBar
* pPrimaryBar
= pPosBar
? pPosBar
: pNegBar
)
1721 xErrorBar
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR
), UNO_QUERY
);
1722 ScfPropertySet
aBarProp( xErrorBar
);
1724 // plus/minus bars visible?
1725 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR
, pPosBar
!= nullptr );
1726 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR
, pNegBar
!= nullptr );
1728 // type of displayed error
1729 switch( pPrimaryBar
->maData
.mnSourceType
)
1731 case EXC_CHSERERR_PERCENT
:
1732 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::RELATIVE
);
1733 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1734 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1736 case EXC_CHSERERR_FIXED
:
1737 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::ABSOLUTE
);
1738 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1739 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1741 case EXC_CHSERERR_STDDEV
:
1742 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_DEVIATION
);
1743 aBarProp
.SetProperty( EXC_CHPROP_WEIGHT
, pPrimaryBar
->maData
.mfValue
);
1745 case EXC_CHSERERR_STDERR
:
1746 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_ERROR
);
1748 case EXC_CHSERERR_CUSTOM
:
1750 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::FROM_DATA
);
1751 // attach data sequences to error bar
1752 Reference
< XDataSink
> xDataSink( xErrorBar
, UNO_QUERY
);
1753 if( xDataSink
.is() )
1755 // create vector of all value sequences
1756 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
1757 // add positive values
1760 Reference
< XLabeledDataSequence
> xValueSeq
= pPosBar
->CreateValueSequence();
1761 if( xValueSeq
.is() )
1762 aLabeledSeqVec
.push_back( xValueSeq
);
1764 // add negative values
1767 Reference
< XLabeledDataSequence
> xValueSeq
= pNegBar
->CreateValueSequence();
1768 if( xValueSeq
.is() )
1769 aLabeledSeqVec
.push_back( xValueSeq
);
1771 // attach labeled data sequences to series
1772 if( aLabeledSeqVec
.empty() )
1775 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
1783 // error bar formatting
1784 if( pPrimaryBar
->mxDataFmt
&& xErrorBar
.is() )
1785 pPrimaryBar
->mxDataFmt
->ConvertLine( aBarProp
, EXC_CHOBJTYPE_ERRORBAR
);
1791 XclImpChSeries::XclImpChSeries( const XclImpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1792 XclImpChRoot( rRoot
),
1793 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1794 mnSeriesIdx( nSeriesIdx
),
1795 mnParentIdx( EXC_CHSERIES_INVALID
),
1796 mbLabelDeleted( false )
1800 void XclImpChSeries::ReadHeaderRecord( XclImpStream
& rStrm
)
1802 maData
.mnCategType
= rStrm
.ReaduInt16();
1803 maData
.mnValueType
= rStrm
.ReaduInt16();
1804 maData
.mnCategCount
= rStrm
.ReaduInt16();
1805 maData
.mnValueCount
= rStrm
.ReaduInt16();
1806 if( GetBiff() == EXC_BIFF8
)
1808 maData
.mnBubbleType
= rStrm
.ReaduInt16();
1809 maData
.mnBubbleCount
= rStrm
.ReaduInt16();
1813 void XclImpChSeries::ReadSubRecord( XclImpStream
& rStrm
)
1815 switch( rStrm
.GetRecId() )
1817 case EXC_ID_CHSOURCELINK
:
1818 ReadChSourceLink( rStrm
);
1820 case EXC_ID_CHDATAFORMAT
:
1821 ReadChDataFormat( rStrm
);
1823 case EXC_ID_CHSERGROUP
:
1824 mnGroupIdx
= rStrm
.ReaduInt16();
1826 case EXC_ID_CHSERPARENT
:
1827 ReadChSerParent( rStrm
);
1829 case EXC_ID_CHSERTRENDLINE
:
1830 ReadChSerTrendLine( rStrm
);
1832 case EXC_ID_CHSERERRORBAR
:
1833 ReadChSerErrorBar( rStrm
);
1835 case EXC_ID_CHLEGENDEXCEPTION
:
1836 ReadChLegendException( rStrm
);
1841 void XclImpChSeries::SetDataFormat( const XclImpChDataFormatRef
& xDataFmt
)
1846 sal_uInt16 nPointIdx
= xDataFmt
->GetPointPos().mnPointIdx
;
1847 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1850 // Don't overwrite the existing format.
1853 mxSeriesFmt
= xDataFmt
;
1854 if (HasParentSeries())
1857 XclImpChTypeGroupRef pTypeGroup
= GetChartData().GetTypeGroup(mnGroupIdx
);
1859 pTypeGroup
->SetUsedFormatIndex(xDataFmt
->GetFormatIdx());
1864 if (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1865 // Above the max point count. Bail out.
1868 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1869 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1871 // No object exists at this point index position. Insert it.
1872 itr
= maPointFmts
.insert(itr
, XclImpChDataFormatMap::value_type(nPointIdx
, xDataFmt
));
1876 void XclImpChSeries::SetDataLabel( const XclImpChTextRef
& xLabel
)
1881 sal_uInt16 nPointIdx
= xLabel
->GetPointPos().mnPointIdx
;
1882 if ((nPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
) && (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
))
1883 // Above the maximum allowed data points. Bail out.
1886 XclImpChTextMap::iterator itr
= maLabels
.lower_bound(nPointIdx
);
1887 if (itr
== maLabels
.end() || maLabels
.key_comp()(nPointIdx
, itr
->first
))
1889 // No object exists at this point index position. Insert it.
1890 itr
= maLabels
.insert(itr
, XclImpChTextMap::value_type(nPointIdx
, xLabel
));
1894 void XclImpChSeries::AddChildSeries( const XclImpChSeries
& rSeries
)
1896 OSL_ENSURE( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1897 if (&rSeries
== this)
1899 SAL_WARN("sc.filter", "self add attempt");
1903 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1904 these are properties of the parent series. This function adds the
1905 settings of the passed series to this series. */
1906 maTrendLines
.insert( maTrendLines
.end(), rSeries
.maTrendLines
.begin(), rSeries
.maTrendLines
.end() );
1907 for (auto const& it
: rSeries
.m_ErrorBars
)
1909 m_ErrorBars
.insert(std::make_pair(it
.first
, std::make_unique
<XclImpChSerErrorBar
>(*it
.second
)));
1913 void XclImpChSeries::FinalizeDataFormats()
1915 if( HasParentSeries() )
1917 // *** series is a child series, e.g. trend line or error bar ***
1919 // create missing series format
1921 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, 0 );
1925 // #i83100# set text label format, e.g. for trend line equations
1926 XclImpChTextRef xLabel
;
1927 XclImpChTextMap::iterator itr
= maLabels
.find(EXC_CHDATAFORMAT_ALLPOINTS
);
1928 if (itr
!= maLabels
.end())
1929 xLabel
= itr
->second
;
1930 mxSeriesFmt
->SetDataLabel(xLabel
);
1931 // create missing automatic formats
1932 mxSeriesFmt
->UpdateTrendLineFormat();
1935 // copy series formatting to child objects
1936 for (auto const& trendLine
: maTrendLines
)
1938 trendLine
->SetDataFormat(mxSeriesFmt
);
1939 if (mxTitleLink
&& mxTitleLink
->HasString())
1941 trendLine
->SetTrendlineName(mxTitleLink
->GetString());
1944 for (auto const& it
: m_ErrorBars
)
1946 it
.second
->SetSeriesData( mxValueLink
, mxSeriesFmt
);
1949 else if( XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
1951 // *** series is a regular data series ***
1953 // create missing series format
1956 // #i51639# use a new unused format index to create series default format
1957 sal_uInt16 nFormatIdx
= pTypeGroup
->PopUnusedFormatIndex();
1958 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, nFormatIdx
);
1961 // set text labels to data formats
1962 for (auto const& label
: maLabels
)
1964 sal_uInt16 nPointIdx
= label
.first
;
1965 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1968 mxSeriesFmt
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1969 mxSeriesFmt
->SetDataLabel(label
.second
);
1971 else if (nPointIdx
< EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1973 XclImpChDataFormatRef p
;
1974 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1975 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1977 // No object exists at this point index position. Insert
1979 p
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1980 itr
= maPointFmts
.insert(
1981 itr
, XclImpChDataFormatMap::value_type(nPointIdx
, p
));
1985 p
->SetDataLabel(label
.second
);
1989 // update series format (copy missing formatting from group default format)
1991 mxSeriesFmt
->UpdateSeriesFormat( pTypeGroup
->GetTypeInfo(), pTypeGroup
->GetGroupFormat().get() );
1993 // update data point formats (removes unchanged automatic formatting)
1994 for (auto const& pointFormat
: maPointFmts
)
1995 pointFormat
.second
->UpdatePointFormat( pTypeGroup
->GetTypeInfo(), mxSeriesFmt
.get() );
2001 /** Returns the property set of the specified data point. */
2002 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> const & xDataSeries
, sal_uInt16 nPointIdx
)
2004 ScfPropertySet aPropSet
;
2007 aPropSet
.Set( xDataSeries
->getDataPointByIndex( static_cast< sal_Int32
>( nPointIdx
) ) );
2011 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
2018 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateValueSequence( const OUString
& rValueRole
) const
2020 return lclCreateLabeledDataSequence( mxValueLink
, rValueRole
, mxTitleLink
.get() );
2023 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateCategSequence( const OUString
& rCategRole
) const
2025 return lclCreateLabeledDataSequence( mxCategLink
, rCategRole
);
2028 Reference
< XDataSeries
> XclImpChSeries::CreateDataSeries() const
2030 Reference
< XDataSeries
> xDataSeries
;
2031 if( const XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
2033 const XclChExtTypeInfo
& rTypeInfo
= pTypeGroup
->GetTypeInfo();
2035 // create the data series object
2036 xDataSeries
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2038 // attach data and title sequences to series
2039 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2040 if( xDataSink
.is() )
2042 // create vector of all value sequences
2043 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2045 Reference
< XLabeledDataSequence
> xYValueSeq
=
2046 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES
);
2047 if( xYValueSeq
.is() )
2048 aLabeledSeqVec
.push_back( xYValueSeq
);
2050 if( !rTypeInfo
.mbCategoryAxis
)
2052 Reference
< XLabeledDataSequence
> xXValueSeq
=
2053 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES
);
2054 if( xXValueSeq
.is() )
2055 aLabeledSeqVec
.push_back( xXValueSeq
);
2056 // add size values of bubble charts
2057 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
2059 Reference
< XLabeledDataSequence
> xSizeValueSeq
=
2060 lclCreateLabeledDataSequence( mxBubbleLink
, EXC_CHPROP_ROLE_SIZEVALUES
, mxTitleLink
.get() );
2061 if( xSizeValueSeq
.is() )
2062 aLabeledSeqVec
.push_back( xSizeValueSeq
);
2065 // attach labeled data sequences to series
2066 if( !aLabeledSeqVec
.empty() )
2067 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2070 // series formatting
2071 ScfPropertySet
aSeriesProp( xDataSeries
);
2073 mxSeriesFmt
->Convert( aSeriesProp
, rTypeInfo
);
2076 aSeriesProp
.SetProperty(EXC_CHPROP_SHOWLEGENDENTRY
, false);
2079 ConvertTrendLines( xDataSeries
);
2082 Reference
< XPropertySet
> xErrorBarX
= CreateErrorBar( EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
2083 if( xErrorBarX
.is() )
2084 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARX
, xErrorBarX
);
2085 Reference
< XPropertySet
> xErrorBarY
= CreateErrorBar( EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
2086 if( xErrorBarY
.is() )
2087 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARY
, xErrorBarY
);
2089 // own area formatting for every data point (TODO: varying line color not supported)
2090 bool bVarPointFmt
= pTypeGroup
->HasVarPointFormat() && rTypeInfo
.IsSeriesFrameFormat();
2091 aSeriesProp
.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
2092 // #i91271# always set area formatting for every point in pie/doughnut charts
2093 if (mxSeriesFmt
&& mxValueLink
&& ((bVarPointFmt
&& mxSeriesFmt
->IsAutoArea()) || (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)))
2095 for( sal_uInt16 nPointIdx
= 0, nPointCount
= mxValueLink
->GetCellCount(); nPointIdx
< nPointCount
; ++nPointIdx
)
2097 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
2098 mxSeriesFmt
->ConvertArea( aPointProp
, bVarPointFmt
? nPointIdx
: mnSeriesIdx
);
2102 // data point formatting
2103 for (auto const& pointFormat
: maPointFmts
)
2105 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, pointFormat
.first
);
2106 pointFormat
.second
->Convert( aPointProp
, rTypeInfo
, &aSeriesProp
);
2112 void XclImpChSeries::FillAllSourceLinks( ::std::vector
< ScTokenRef
>& rTokens
) const
2115 mxValueLink
->FillSourceLink( rTokens
);
2117 mxCategLink
->FillSourceLink( rTokens
);
2119 mxTitleLink
->FillSourceLink( rTokens
);
2121 mxBubbleLink
->FillSourceLink( rTokens
);
2124 void XclImpChSeries::ReadChSourceLink( XclImpStream
& rStrm
)
2126 XclImpChSourceLinkRef xSrcLink
= std::make_shared
<XclImpChSourceLink
>( GetChRoot() );
2127 xSrcLink
->ReadChSourceLink( rStrm
);
2128 switch( xSrcLink
->GetDestType() )
2130 case EXC_CHSRCLINK_TITLE
: mxTitleLink
= xSrcLink
; break;
2131 case EXC_CHSRCLINK_VALUES
: mxValueLink
= xSrcLink
; break;
2132 case EXC_CHSRCLINK_CATEGORY
: mxCategLink
= xSrcLink
; break;
2133 case EXC_CHSRCLINK_BUBBLES
: mxBubbleLink
= xSrcLink
; break;
2137 void XclImpChSeries::ReadChDataFormat( XclImpStream
& rStrm
)
2139 // #i51639# chart stores all data formats and assigns them later to the series
2140 GetChartData().ReadChDataFormat( rStrm
);
2143 void XclImpChSeries::ReadChSerParent( XclImpStream
& rStrm
)
2145 mnParentIdx
= rStrm
.ReaduInt16();
2146 // index to parent series is 1-based, convert it to 0-based
2147 if( mnParentIdx
> 0 )
2150 mnParentIdx
= EXC_CHSERIES_INVALID
;
2153 void XclImpChSeries::ReadChSerTrendLine( XclImpStream
& rStrm
)
2155 XclImpChSerTrendLineRef xTrendLine
= std::make_shared
<XclImpChSerTrendLine
>( GetChRoot() );
2156 xTrendLine
->ReadChSerTrendLine( rStrm
);
2157 maTrendLines
.push_back( xTrendLine
);
2160 void XclImpChSeries::ReadChSerErrorBar( XclImpStream
& rStrm
)
2162 unique_ptr
<XclImpChSerErrorBar
> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
2163 pErrorBar
->ReadChSerErrorBar(rStrm
);
2164 sal_uInt8 nBarType
= pErrorBar
->GetBarType();
2165 m_ErrorBars
.insert(std::make_pair(nBarType
, std::move(pErrorBar
)));
2168 XclImpChDataFormatRef
XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx
, sal_uInt16 nFormatIdx
)
2170 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
2171 xDataFmt
->SetPointPos( XclChDataPointPos( mnSeriesIdx
, nPointIdx
), nFormatIdx
);
2175 void XclImpChSeries::ConvertTrendLines( Reference
< XDataSeries
> const & xDataSeries
) const
2177 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2178 if( !xRegCurveCont
.is() )
2181 for (auto const& trendLine
: maTrendLines
)
2185 Reference
< XRegressionCurve
> xRegCurve
= trendLine
->CreateRegressionCurve();
2186 if( xRegCurve
.is() )
2188 xRegCurveCont
->addRegressionCurve( xRegCurve
);
2193 OSL_FAIL( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2198 Reference
< XPropertySet
> XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
) const
2200 XclImpChSerErrorBarMap::const_iterator itrPosBar
= m_ErrorBars
.find(nPosBarId
);
2201 XclImpChSerErrorBarMap::const_iterator itrNegBar
= m_ErrorBars
.find(nNegBarId
);
2202 XclImpChSerErrorBarMap::const_iterator itrEnd
= m_ErrorBars
.end();
2203 if (itrPosBar
== itrEnd
|| itrNegBar
== itrEnd
)
2204 return Reference
<XPropertySet
>();
2206 return XclImpChSerErrorBar::CreateErrorBar(itrPosBar
->second
.get(), itrNegBar
->second
.get());
2209 void XclImpChSeries::ReadChLegendException(XclImpStream
& rStrm
)
2212 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
2213 mbLabelDeleted
= (nFlags
& EXC_CHLEGENDEXCEPTION_DELETED
);
2216 // Chart type groups ==========================================================
2218 XclImpChType::XclImpChType( const XclImpChRoot
& rRoot
) :
2219 XclImpChRoot( rRoot
),
2220 mnRecId( EXC_ID_CHUNKNOWN
),
2221 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2225 void XclImpChType::ReadChType( XclImpStream
& rStrm
)
2227 sal_uInt16 nRecId
= rStrm
.GetRecId();
2228 bool bKnownType
= true;
2233 maData
.mnOverlap
= rStrm
.ReadInt16();
2234 maData
.mnGap
= rStrm
.ReadInt16();
2235 maData
.mnFlags
= rStrm
.ReaduInt16();
2240 case EXC_ID_CHRADARLINE
:
2241 case EXC_ID_CHRADARAREA
:
2242 case EXC_ID_CHSURFACE
:
2243 maData
.mnFlags
= rStrm
.ReaduInt16();
2247 maData
.mnRotation
= rStrm
.ReaduInt16();
2248 maData
.mnPieHole
= rStrm
.ReaduInt16();
2249 if( GetBiff() == EXC_BIFF8
)
2250 maData
.mnFlags
= rStrm
.ReaduInt16();
2255 case EXC_ID_CHPIEEXT
:
2256 maData
.mnRotation
= 0;
2257 maData
.mnPieHole
= 0;
2261 case EXC_ID_CHSCATTER
:
2262 if( GetBiff() == EXC_BIFF8
)
2264 maData
.mnBubbleSize
= rStrm
.ReaduInt16();
2265 maData
.mnBubbleType
= rStrm
.ReaduInt16();
2266 maData
.mnFlags
= rStrm
.ReaduInt16();
2280 void XclImpChType::Finalize( bool bStockChart
)
2285 maTypeInfo
= GetChartTypeInfo( bStockChart
?
2286 EXC_CHTYPEID_STOCK
: EXC_CHTYPEID_LINE
);
2289 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2290 maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
,
2291 EXC_CHTYPEID_HORBAR
, EXC_CHTYPEID_BAR
) );
2294 maTypeInfo
= GetChartTypeInfo( (maData
.mnPieHole
> 0) ?
2295 EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2297 case EXC_ID_CHSCATTER
:
2298 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2299 maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
,
2300 EXC_CHTYPEID_BUBBLES
, EXC_CHTYPEID_SCATTER
) );
2303 maTypeInfo
= GetChartTypeInfo( mnRecId
);
2306 switch( maTypeInfo
.meTypeId
)
2308 case EXC_CHTYPEID_PIEEXT
:
2309 case EXC_CHTYPEID_BUBBLES
:
2310 case EXC_CHTYPEID_SURFACE
:
2311 case EXC_CHTYPEID_UNKNOWN
:
2312 GetTracer().TraceChartUnKnownType();
2318 bool XclImpChType::IsStacked() const
2320 bool bStacked
= false;
2321 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2323 case EXC_CHTYPECATEG_LINE
:
2325 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2326 !::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2328 case EXC_CHTYPECATEG_BAR
:
2330 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2331 !::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2338 bool XclImpChType::IsPercent() const
2340 bool bPercent
= false;
2341 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2343 case EXC_CHTYPECATEG_LINE
:
2345 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2346 ::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2348 case EXC_CHTYPECATEG_BAR
:
2350 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2351 ::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2358 bool XclImpChType::HasCategoryLabels() const
2360 // radar charts disable category labels in chart type, not in CHTICK of X axis
2361 return (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) || ::get_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
);
2364 Reference
< XCoordinateSystem
> XclImpChType::CreateCoordSystem( bool b3dChart
) const
2366 // create the coordinate system object
2367 const Reference
< css::uno::XComponentContext
>& xContext
= comphelper::getProcessComponentContext();
2368 Reference
< XCoordinateSystem
> xCoordSystem
;
2369 if( maTypeInfo
.mbPolarCoordSystem
)
2372 xCoordSystem
= css::chart2::PolarCoordinateSystem3d::create(xContext
);
2374 xCoordSystem
= css::chart2::PolarCoordinateSystem2d::create(xContext
);
2379 xCoordSystem
= css::chart2::CartesianCoordinateSystem3d::create(xContext
);
2381 xCoordSystem
= css::chart2::CartesianCoordinateSystem2d::create(xContext
);
2384 // swap X and Y axis
2385 if( maTypeInfo
.mbSwappedAxesSet
)
2387 ScfPropertySet
aCoordSysProp( xCoordSystem
);
2388 aCoordSysProp
.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
, true );
2391 return xCoordSystem
;
2394 Reference
< XChartType
> XclImpChType::CreateChartType( Reference
< XDiagram
> const & xDiagram
, bool b3dChart
) const
2396 OUString aService
= OUString::createFromAscii( maTypeInfo
.mpcServiceName
);
2397 Reference
< XChartType
> xChartType( ScfApiHelper::CreateInstance( aService
), UNO_QUERY
);
2399 // additional properties
2400 switch( maTypeInfo
.meTypeCateg
)
2402 case EXC_CHTYPECATEG_BAR
:
2404 ScfPropertySet
aTypeProp( xChartType
);
2405 Sequence
< sal_Int32
> aInt32Seq
{ -maData
.mnOverlap
, -maData
.mnOverlap
};
2406 aTypeProp
.SetProperty( EXC_CHPROP_OVERLAPSEQ
, aInt32Seq
);
2407 aInt32Seq
= { maData
.mnGap
, maData
.mnGap
};
2408 aTypeProp
.SetProperty( EXC_CHPROP_GAPWIDTHSEQ
, aInt32Seq
);
2411 case EXC_CHTYPECATEG_PIE
:
2413 ScfPropertySet
aTypeProp( xChartType
);
2414 aTypeProp
.SetBoolProperty( EXC_CHPROP_USERINGS
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_DONUT
);
2415 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2416 rotation setting in view3D element. Of-pie charts do not
2417 support pie rotation. */
2418 if( !b3dChart
&& (maTypeInfo
.meTypeId
!= EXC_CHTYPEID_PIEEXT
) )
2420 ScfPropertySet
aDiaProp( xDiagram
);
2421 XclImpChRoot::ConvertPieRotation( aDiaProp
, maData
.mnRotation
);
2431 void XclImpChChart3d::ReadChChart3d( XclImpStream
& rStrm
)
2433 maData
.mnRotation
= rStrm
.ReaduInt16();
2434 maData
.mnElevation
= rStrm
.ReadInt16();
2435 maData
.mnEyeDist
= rStrm
.ReaduInt16();
2436 maData
.mnRelHeight
= rStrm
.ReaduInt16();
2437 maData
.mnRelDepth
= rStrm
.ReaduInt16();
2438 maData
.mnDepthGap
= rStrm
.ReaduInt16();
2439 maData
.mnFlags
= rStrm
.ReaduInt16();
2442 void XclImpChChart3d::Convert( ScfPropertySet
& rPropSet
, bool b3dWallChart
) const
2444 namespace cssd
= ::com::sun::star::drawing
;
2446 // #i104057# do not assert this, written by broken external generators
2447 // OSL_ENSURE( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2449 sal_Int32 nRotationY
= 0;
2450 sal_Int32 nRotationX
= 0;
2451 sal_Int32 nPerspective
= 15;
2452 bool bRightAngled
= false;
2453 cssd::ProjectionMode eProjMode
= cssd::ProjectionMode_PERSPECTIVE
;
2454 Color aAmbientColor
, aLightColor
;
2458 // Y rotation (Excel [0..359], Chart2 [-179,180])
2459 nRotationY
= NormAngle180
<sal_Int32
>(maData
.mnRotation
);
2460 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2461 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, -90, 90 );
2462 // perspective (Excel and Chart2 [0,100])
2463 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2464 // right-angled axes
2465 bRightAngled
= !::get_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
);
2466 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2467 bool bParallel
= bRightAngled
|| (nPerspective
== 0);
2468 eProjMode
= bParallel
? cssd::ProjectionMode_PARALLEL
: cssd::ProjectionMode_PERSPECTIVE
;
2469 // ambient color (Gray 20%)
2470 aAmbientColor
= Color( 204, 204, 204 );
2471 // light color (Gray 60%)
2472 aLightColor
= Color( 102, 102, 102 );
2476 // Y rotation not used in pie charts, but 'first pie slice angle'
2478 XclImpChRoot::ConvertPieRotation( rPropSet
, maData
.mnRotation
);
2479 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2480 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, 10, 80 ) - 90;
2481 // perspective (Excel and Chart2 [0,100])
2482 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2483 // no right-angled axes in pie charts, but parallel projection
2484 bRightAngled
= false;
2485 eProjMode
= cssd::ProjectionMode_PARALLEL
;
2486 // ambient color (Gray 30%)
2487 aAmbientColor
= Color( 179, 179, 179 );
2488 // light color (Gray 70%)
2489 aLightColor
= Color( 76, 76, 76 );
2493 rPropSet
.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT
, static_cast<sal_Int32
>(maData
.mnRelHeight
/ 2)); // seems to be 200%, change to 100%
2494 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONVERTICAL
, nRotationY
);
2495 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL
, nRotationX
);
2496 rPropSet
.SetProperty( EXC_CHPROP_PERSPECTIVE
, nPerspective
);
2497 rPropSet
.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
, bRightAngled
);
2498 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE
, eProjMode
);
2501 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE
, cssd::ShadeMode_FLAT
);
2502 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR
, aAmbientColor
);
2503 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1
, false );
2504 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2
, true );
2505 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2
, aLightColor
);
2506 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2
, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2509 XclImpChLegend::XclImpChLegend( const XclImpChRoot
& rRoot
) :
2510 XclImpChRoot( rRoot
)
2514 void XclImpChLegend::ReadHeaderRecord( XclImpStream
& rStrm
)
2516 rStrm
>> maData
.maRect
;
2517 maData
.mnDockMode
= rStrm
.ReaduInt8();
2518 maData
.mnSpacing
= rStrm
.ReaduInt8();
2519 maData
.mnFlags
= rStrm
.ReaduInt16();
2521 // trace unsupported features
2522 if( GetTracer().IsEnabled() )
2524 if( maData
.mnDockMode
== EXC_CHLEGEND_NOTDOCKED
)
2525 GetTracer().TraceChartLegendPosition();
2526 if( ::get_flag( maData
.mnFlags
, EXC_CHLEGEND_DATATABLE
) )
2527 GetTracer().TraceChartDataTable();
2531 void XclImpChLegend::ReadSubRecord( XclImpStream
& rStrm
)
2533 switch( rStrm
.GetRecId() )
2535 case EXC_ID_CHFRAMEPOS
:
2536 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
2537 mxFramePos
->ReadChFramePos( rStrm
);
2540 mxText
= std::make_shared
<XclImpChText
>( GetChRoot() );
2541 mxText
->ReadRecordGroup( rStrm
);
2543 case EXC_ID_CHFRAME
:
2544 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2545 mxFrame
->ReadRecordGroup( rStrm
);
2550 void XclImpChLegend::Finalize()
2552 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2554 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2555 // Update text formatting. If mxText is empty, the passed default text is used.
2556 lclUpdateText( mxText
, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND
) );
2559 Reference
< XLegend
> XclImpChLegend::CreateLegend() const
2561 Reference
< XLegend
> xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND
), UNO_QUERY
);
2564 ScfPropertySet
aLegendProp( xLegend
);
2565 aLegendProp
.SetBoolProperty( EXC_CHPROP_SHOW
, true );
2569 mxFrame
->Convert( aLegendProp
);
2572 mxText
->ConvertFont( aLegendProp
);
2574 /* Legend position and size. Default positions are used only if the
2575 plot area is positioned automatically (Excel sets the plot area to
2576 manual mode, if the legend is moved or resized). With manual plot
2577 areas, Excel ignores the value in maData.mnDockMode completely. */
2578 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_LINE_END
;
2579 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2580 if( !GetChartData().IsManualPlotArea() ) switch( maData
.mnDockMode
)
2582 case EXC_CHLEGEND_LEFT
:
2583 eApiPos
= cssc2::LegendPosition_LINE_START
;
2584 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2586 case EXC_CHLEGEND_RIGHT
:
2587 // top-right not supported
2588 case EXC_CHLEGEND_CORNER
:
2589 eApiPos
= cssc2::LegendPosition_LINE_END
;
2590 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2592 case EXC_CHLEGEND_TOP
:
2593 eApiPos
= cssc2::LegendPosition_PAGE_START
;
2594 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2596 case EXC_CHLEGEND_BOTTOM
:
2597 eApiPos
= cssc2::LegendPosition_PAGE_END
;
2598 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2602 // no automatic position/size: try to find the correct position and size
2603 if( GetChartData().IsManualPlotArea() || maData
.mnDockMode
== EXC_CHLEGEND_NOTDOCKED
)
2605 const XclChFramePos
* pFramePos
= mxFramePos
? &mxFramePos
->GetFramePosData() : nullptr;
2607 /* Legend position. Only the settings from the CHFRAMEPOS record
2608 are used by Excel, the position in the CHLEGEND record will be
2612 RelativePosition
aRelPos(
2613 CalcRelativeFromChartX( pFramePos
->maRect
.mnX
),
2614 CalcRelativeFromChartY( pFramePos
->maRect
.mnY
),
2615 css::drawing::Alignment_TOP_LEFT
);
2616 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVEPOSITION
, aRelPos
);
2620 // no manual position/size found, just go for the default
2621 eApiPos
= cssc2::LegendPosition_LINE_END
;
2624 /* Legend size. The member mnBRMode specifies whether size is
2625 automatic or changes manually. Manual size is given in points,
2626 not in chart units. */
2627 if( pFramePos
&& (pFramePos
->mnBRMode
== EXC_CHFRAMEPOS_ABSSIZE_POINTS
) &&
2628 (pFramePos
->maRect
.mnWidth
> 0) && (pFramePos
->maRect
.mnHeight
> 0) )
2630 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2631 sal_Int32 nWidthHmm
= o3tl::convert(pFramePos
->maRect
.mnWidth
, o3tl::Length::pt
, o3tl::Length::mm100
);
2632 sal_Int32 nHeightHmm
= o3tl::convert(pFramePos
->maRect
.mnHeight
, o3tl::Length::pt
, o3tl::Length::mm100
);
2633 RelativeSize
aRelSize( CalcRelativeFromHmmX( nWidthHmm
), CalcRelativeFromHmmY( nHeightHmm
) );
2634 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVESIZE
, aRelSize
);
2638 // automatic size: determine entry direction from flags
2639 eApiExpand
= ::get_flagvalue( maData
.mnFlags
, EXC_CHLEGEND_STACKED
,
2640 cssc::ChartLegendExpansion_HIGH
, cssc::ChartLegendExpansion_WIDE
);
2643 aLegendProp
.SetProperty( EXC_CHPROP_ANCHORPOSITION
, eApiPos
);
2644 aLegendProp
.SetProperty( EXC_CHPROP_EXPANSION
, eApiExpand
);
2649 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar
) :
2650 mnDropBar( nDropBar
),
2655 void XclImpChDropBar::ReadHeaderRecord( XclImpStream
& rStrm
)
2657 mnBarDist
= rStrm
.ReaduInt16();
2660 void XclImpChDropBar::Convert( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
2662 XclChObjectType eObjType
= EXC_CHOBJTYPE_BACKGROUND
;
2665 case EXC_CHDROPBAR_UP
: eObjType
= EXC_CHOBJTYPE_WHITEDROPBAR
; break;
2666 case EXC_CHDROPBAR_DOWN
: eObjType
= EXC_CHOBJTYPE_BLACKDROPBAR
; break;
2668 ConvertFrameBase( rRoot
, rPropSet
, eObjType
);
2671 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot
& rRoot
) :
2672 XclImpChRoot( rRoot
),
2674 maTypeInfo( maType
.GetTypeInfo() )
2676 // Initialize unused format indexes set. At this time, all formats are unused.
2677 for( sal_uInt16 nFormatIdx
= 0; nFormatIdx
<= EXC_CHSERIES_MAXSERIES
; ++nFormatIdx
)
2678 maUnusedFormats
.insert( maUnusedFormats
.end(), nFormatIdx
);
2681 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream
& rStrm
)
2684 maData
.mnFlags
= rStrm
.ReaduInt16();
2685 maData
.mnGroupIdx
= rStrm
.ReaduInt16();
2688 void XclImpChTypeGroup::ReadSubRecord( XclImpStream
& rStrm
)
2690 switch( rStrm
.GetRecId() )
2692 case EXC_ID_CHCHART3D
:
2693 mxChart3d
= std::make_shared
<XclImpChChart3d
>();
2694 mxChart3d
->ReadChChart3d( rStrm
);
2696 case EXC_ID_CHLEGEND
:
2697 mxLegend
= std::make_shared
<XclImpChLegend
>( GetChRoot() );
2698 mxLegend
->ReadRecordGroup( rStrm
);
2700 case EXC_ID_CHDEFAULTTEXT
:
2701 GetChartData().ReadChDefaultText( rStrm
);
2703 case EXC_ID_CHDROPBAR
:
2704 ReadChDropBar( rStrm
);
2706 case EXC_ID_CHCHARTLINE
:
2707 ReadChChartLine( rStrm
);
2709 case EXC_ID_CHDATAFORMAT
:
2710 ReadChDataFormat( rStrm
);
2713 maType
.ReadChType( rStrm
);
2717 void XclImpChTypeGroup::Finalize()
2719 // check and set valid chart type
2721 (maType
.GetRecId() == EXC_ID_CHLINE
) && // must be a line chart
2722 !mxChart3d
&& // must be a 2d chart
2723 m_ChartLines
.find(EXC_CHCHARTLINE_HILO
) != m_ChartLines
.end() && // must contain hi-lo lines
2724 (maSeries
.size() == static_cast<XclImpChSeriesVec::size_type
>(HasDropBars() ? 4 : 3)); // correct series count
2725 maType
.Finalize( bStockChart
);
2727 // extended type info
2728 maTypeInfo
.Set( maType
.GetTypeInfo(), static_cast< bool >(mxChart3d
), false );
2730 // reverse series order for some unstacked 2D chart types
2731 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() && !maType
.IsStacked() && !maType
.IsPercent() )
2732 ::std::reverse( maSeries
.begin(), maSeries
.end() );
2734 // update chart type group format, may depend on chart type finalized above
2736 mxGroupFmt
->UpdateGroupFormat( maTypeInfo
);
2739 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef
const & xSeries
)
2742 maSeries
.push_back( xSeries
);
2743 // store first inserted series separately, series order may be reversed later
2744 if( !mxFirstSeries
)
2745 mxFirstSeries
= xSeries
;
2748 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx
)
2750 maUnusedFormats
.erase( nFormatIdx
);
2753 sal_uInt16
XclImpChTypeGroup::PopUnusedFormatIndex()
2755 OSL_ENSURE( !maUnusedFormats
.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2756 sal_uInt16 nFormatIdx
= maUnusedFormats
.empty() ? 0 : *maUnusedFormats
.begin();
2757 SetUsedFormatIndex( nFormatIdx
);
2761 bool XclImpChTypeGroup::HasVarPointFormat() const
2763 return ::get_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
) &&
2764 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_MULTI
) || // multiple series allowed
2765 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_SINGLE
) && // or exactly 1 series?
2766 (maSeries
.size() == 1)));
2769 bool XclImpChTypeGroup::HasConnectorLines() const
2771 // existence of connector lines (only in stacked bar charts)
2772 if ( !(maType
.IsStacked() || maType
.IsPercent()) || (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
2774 XclImpChLineFormatMap::const_iterator aConLine
= m_ChartLines
.find(EXC_CHCHARTLINE_CONNECT
);
2775 return (aConLine
!= m_ChartLines
.end() && aConLine
->second
.HasLine());
2778 OUString
XclImpChTypeGroup::GetSingleSeriesTitle() const
2780 // no automatic title for series with trendlines or error bars
2781 // pie charts always show an automatic title, even if more series exist
2782 return (mxFirstSeries
&& !mxFirstSeries
->HasChildSeries() && (maTypeInfo
.mbSingleSeriesVis
|| (maSeries
.size() == 1))) ?
2783 mxFirstSeries
->GetTitle() : OUString();
2786 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet
& rPropSet
) const
2789 mxChart3d
->Convert( rPropSet
, Is3dWallChart() );
2792 Reference
< XCoordinateSystem
> XclImpChTypeGroup::CreateCoordSystem() const
2794 return maType
.CreateCoordSystem( Is3dChart() );
2797 Reference
< XChartType
> XclImpChTypeGroup::CreateChartType( Reference
< XDiagram
> const & xDiagram
, sal_Int32 nApiAxesSetIdx
) const
2799 OSL_ENSURE( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2801 // create the chart type object
2802 Reference
< XChartType
> xChartType
= maType
.CreateChartType( xDiagram
, Is3dChart() );
2804 // bar chart connector lines
2805 if( HasConnectorLines() )
2807 ScfPropertySet
aDiaProp( xDiagram
);
2808 aDiaProp
.SetBoolProperty( EXC_CHPROP_CONNECTBARS
, true );
2811 /* Stock chart needs special processing. Create one 'big' series with
2812 data sequences of different roles. */
2813 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2814 CreateStockSeries( xChartType
, nApiAxesSetIdx
);
2816 CreateDataSeries( xChartType
, nApiAxesSetIdx
);
2821 Reference
< XLabeledDataSequence
> XclImpChTypeGroup::CreateCategSequence() const
2823 Reference
< XLabeledDataSequence
> xLabeledSeq
;
2824 // create category sequence from first visible series
2826 xLabeledSeq
= mxFirstSeries
->CreateCategSequence( EXC_CHPROP_ROLE_CATEG
);
2830 void XclImpChTypeGroup::ReadChDropBar( XclImpStream
& rStrm
)
2832 if (m_DropBars
.find(EXC_CHDROPBAR_UP
) == m_DropBars
.end())
2834 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_UP
));
2835 p
->ReadRecordGroup(rStrm
);
2836 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_UP
, std::move(p
)));
2838 else if (m_DropBars
.find(EXC_CHDROPBAR_DOWN
) == m_DropBars
.end())
2840 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN
));
2841 p
->ReadRecordGroup(rStrm
);
2842 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_DOWN
, std::move(p
)));
2846 void XclImpChTypeGroup::ReadChChartLine( XclImpStream
& rStrm
)
2848 sal_uInt16 nLineId
= rStrm
.ReaduInt16();
2849 if( (rStrm
.GetNextRecId() == EXC_ID_CHLINEFORMAT
) && rStrm
.StartNextRecord() )
2851 XclImpChLineFormat aLineFmt
;
2852 aLineFmt
.ReadChLineFormat( rStrm
);
2853 m_ChartLines
[nLineId
] = std::move(aLineFmt
);
2857 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream
& rStrm
)
2859 // global series and data point format
2860 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
2861 xDataFmt
->ReadRecordGroup( rStrm
);
2862 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
2863 if( (rPos
.mnSeriesIdx
== 0) && (rPos
.mnPointIdx
== 0) &&
2864 (xDataFmt
->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT
) )
2865 mxGroupFmt
= std::move(xDataFmt
);
2868 void XclImpChTypeGroup::InsertDataSeries( Reference
< XChartType
> const & xChartType
,
2869 Reference
< XDataSeries
> const & xSeries
, sal_Int32 nApiAxesSetIdx
) const
2871 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2872 if( !(xSeriesCont
.is() && xSeries
.is()) )
2875 // series stacking mode
2876 cssc2::StackingDirection eStacking
= cssc2::StackingDirection_NO_STACKING
;
2877 // stacked overrides deep-3d
2878 if( maType
.IsStacked() || maType
.IsPercent() )
2879 eStacking
= cssc2::StackingDirection_Y_STACKING
;
2880 else if( Is3dDeepChart() )
2881 eStacking
= cssc2::StackingDirection_Z_STACKING
;
2883 // additional series properties
2884 ScfPropertySet
aSeriesProp( xSeries
);
2885 aSeriesProp
.SetProperty( EXC_CHPROP_STACKINGDIR
, eStacking
);
2886 aSeriesProp
.SetProperty( EXC_CHPROP_ATTAXISINDEX
, nApiAxesSetIdx
);
2888 // insert series into container
2891 xSeriesCont
->addDataSeries( xSeries
);
2895 OSL_FAIL( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2899 void XclImpChTypeGroup::CreateDataSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2901 bool bSpline
= false;
2902 for (auto const& elem
: maSeries
)
2904 Reference
< XDataSeries
> xDataSeries
= elem
->CreateDataSeries();
2905 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2906 bSpline
|= elem
->HasSpline();
2908 // spline - TODO: set at single series (#i66858#)
2909 if( bSpline
&& !maTypeInfo
.IsSeriesFrameFormat() && (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) )
2911 ScfPropertySet
aTypeProp( xChartType
);
2912 aTypeProp
.SetProperty( EXC_CHPROP_CURVESTYLE
, css::chart2::CurveStyle_CUBIC_SPLINES
);
2916 void XclImpChTypeGroup::CreateStockSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2918 // create the data series object
2919 Reference
< XDataSeries
> xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2920 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2921 if( !xDataSink
.is() )
2924 // create a list of data sequences from all series
2925 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2926 OSL_ENSURE( maSeries
.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2927 int nRoleIdx
= (maSeries
.size() == 3) ? 1 : 0;
2928 for( const auto& rxSeries
: maSeries
)
2930 // create a data sequence with a specific role
2934 case 0: aRole
= EXC_CHPROP_ROLE_OPENVALUES
; break;
2935 case 1: aRole
= EXC_CHPROP_ROLE_HIGHVALUES
; break;
2936 case 2: aRole
= EXC_CHPROP_ROLE_LOWVALUES
; break;
2937 case 3: aRole
= EXC_CHPROP_ROLE_CLOSEVALUES
; break;
2939 Reference
< XLabeledDataSequence
> xDataSeq
= rxSeries
->CreateValueSequence( aRole
);
2941 aLabeledSeqVec
.push_back( xDataSeq
);
2947 // attach labeled data sequences to series and insert series into chart type
2948 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2950 // formatting of special stock chart elements
2951 ScfPropertySet
aTypeProp( xChartType
);
2952 aTypeProp
.SetBoolProperty( EXC_CHPROP_JAPANESE
, HasDropBars() );
2953 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWFIRST
, HasDropBars() );
2954 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
, true );
2955 // hi-lo line format
2956 XclImpChLineFormatMap::const_iterator aHiLoLine
= m_ChartLines
.find( EXC_CHCHARTLINE_HILO
);
2957 if (aHiLoLine
!= m_ChartLines
.end())
2959 ScfPropertySet
aSeriesProp( xDataSeries
);
2960 aHiLoLine
->second
.Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2962 // white dropbar format
2963 XclImpChDropBarMap::const_iterator itr
= m_DropBars
.find(EXC_CHDROPBAR_UP
);
2964 Reference
<XPropertySet
> xWhitePropSet
;
2965 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xWhitePropSet
, EXC_CHPROP_WHITEDAY
))
2967 ScfPropertySet
aBarProp( xWhitePropSet
);
2968 itr
->second
->Convert(GetChRoot(), aBarProp
);
2970 // black dropbar format
2971 itr
= m_DropBars
.find(EXC_CHDROPBAR_DOWN
);
2972 Reference
<XPropertySet
> xBlackPropSet
;
2973 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xBlackPropSet
, EXC_CHPROP_BLACKDAY
))
2975 ScfPropertySet
aBarProp( xBlackPropSet
);
2976 itr
->second
->Convert(GetChRoot(), aBarProp
);
2979 // insert the series into the chart type object
2980 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2983 // Axes =======================================================================
2985 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot
& rRoot
) :
2986 XclImpChRoot( rRoot
)
2990 void XclImpChLabelRange::ReadChLabelRange( XclImpStream
& rStrm
)
2992 maLabelData
.mnCross
= rStrm
.ReaduInt16();
2993 maLabelData
.mnLabelFreq
= rStrm
.ReaduInt16();
2994 maLabelData
.mnTickFreq
= rStrm
.ReaduInt16();
2995 maLabelData
.mnFlags
= rStrm
.ReaduInt16();
2998 void XclImpChLabelRange::ReadChDateRange( XclImpStream
& rStrm
)
3000 maDateData
.mnMinDate
= rStrm
.ReaduInt16();
3001 maDateData
.mnMaxDate
= rStrm
.ReaduInt16();
3002 maDateData
.mnMajorStep
= rStrm
.ReaduInt16();
3003 maDateData
.mnMajorUnit
= rStrm
.ReaduInt16();
3004 maDateData
.mnMinorStep
= rStrm
.ReaduInt16();
3005 maDateData
.mnMinorUnit
= rStrm
.ReaduInt16();
3006 maDateData
.mnBaseUnit
= rStrm
.ReaduInt16();
3007 maDateData
.mnCross
= rStrm
.ReaduInt16();
3008 maDateData
.mnFlags
= rStrm
.ReaduInt16();
3011 void XclImpChLabelRange::Convert( ScfPropertySet
& rPropSet
, ScaleData
& rScaleData
, bool bMirrorOrient
) const
3013 // automatic axis type detection
3014 rScaleData
.AutoDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
);
3016 // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
3017 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3019 /* Chart2 requires axis type CATEGORY for automatic category/date axis
3020 (even if it is a date axis currently). */
3021 rScaleData
.AxisType
= rScaleData
.AutoDateAxis
? cssc2::AxisType::CATEGORY
: cssc2::AxisType::DATE
;
3022 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3023 /* Min/max values depend on base time unit, they specify the number of
3024 days, months, or years starting from null date. */
3025 lclConvertTimeValue( GetRoot(), rScaleData
.Minimum
, maDateData
.mnMinDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
), maDateData
.mnBaseUnit
);
3026 lclConvertTimeValue( GetRoot(), rScaleData
.Maximum
, maDateData
.mnMaxDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
), maDateData
.mnBaseUnit
);
3028 cssc::TimeIncrement
& rTimeIncrement
= rScaleData
.TimeIncrement
;
3029 lclConvertTimeInterval( rTimeIncrement
.MajorTimeInterval
, maDateData
.mnMajorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
), maDateData
.mnMajorUnit
);
3030 lclConvertTimeInterval( rTimeIncrement
.MinorTimeInterval
, maDateData
.mnMinorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
), maDateData
.mnMinorUnit
);
3032 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
) )
3033 rTimeIncrement
.TimeResolution
.clear();
3035 rTimeIncrement
.TimeResolution
<<= lclGetApiTimeUnit( maDateData
.mnBaseUnit
);
3039 // do not overlap text unless all labels are visible
3040 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP
, maLabelData
.mnLabelFreq
== 1 );
3041 // do not break text into several lines unless all labels are visible
3042 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTBREAK
, maLabelData
.mnLabelFreq
== 1 );
3043 // do not stagger labels in two lines
3044 rPropSet
.SetProperty( EXC_CHPROP_ARRANGEORDER
, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE
);
3048 bool bReverse
= ::get_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
) != bMirrorOrient
;
3049 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3051 //TODO #i58731# show n-th category
3054 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
, bool b3dChart
) const
3056 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
3057 does not move the Y axis in 3D charts, regardless of actual settings.
3058 But: the Y axis has to be moved to "end", if the X axis is mirrored,
3059 to keep it at the left end of the chart. */
3060 bool bMaxCross
= ::get_flag( maLabelData
.mnFlags
, b3dChart
? EXC_CHLABELRANGE_REVERSE
: EXC_CHLABELRANGE_MAXCROSS
);
3061 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3062 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3064 // crossing position (depending on axis type text/date)
3065 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3067 bool bAutoCross
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
3068 /* Crossing position value depends on base time unit, it specifies the
3069 number of days, months, or years from null date. Note that Excel
3070 2007/2010 write broken BIFF8 files, they always stores the number
3071 of days regardless of the base time unit (and they are reading it
3072 the same way, thus wrongly displaying files written by Excel
3073 97-2003). This filter sticks to the correct behaviour of Excel
3075 double fCrossingPos
= bAutoCross
? 1.0 : lclGetSerialDay( GetRoot(), maDateData
.mnCross
, maDateData
.mnBaseUnit
);
3076 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3080 double fCrossingPos
= b3dChart
? 1.0 : maLabelData
.mnCross
;
3081 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3085 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot
& rRoot
) :
3086 XclImpChRoot( rRoot
)
3090 void XclImpChValueRange::ReadChValueRange( XclImpStream
& rStrm
)
3092 maData
.mfMin
= rStrm
.ReadDouble();
3093 maData
.mfMax
= rStrm
.ReadDouble();
3094 maData
.mfMajorStep
= rStrm
.ReadDouble();
3095 maData
.mfMinorStep
= rStrm
.ReadDouble();
3096 maData
.mfCross
= rStrm
.ReadDouble();
3097 maData
.mnFlags
= rStrm
.ReaduInt16();
3100 void XclImpChValueRange::Convert( ScaleData
& rScaleData
, bool bMirrorOrient
) const
3102 // scaling algorithm
3103 const bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3105 rScaleData
.Scaling
= css::chart2::LogarithmicScaling::create( comphelper::getProcessComponentContext() );
3107 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3110 lclSetExpValueOrClearAny( rScaleData
.Minimum
, maData
.mfMin
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
) );
3111 lclSetExpValueOrClearAny( rScaleData
.Maximum
, maData
.mfMax
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
) );
3114 bool bAutoMajor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
);
3115 bool bAutoMinor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
);
3117 IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
3118 lclSetValueOrClearAny( rIncrementData
.Distance
, maData
.mfMajorStep
, bAutoMajor
);
3120 Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
3121 rSubIncrementSeq
.realloc( 1 );
3122 Any
& rIntervalCount
= rSubIncrementSeq
.getArray()[ 0 ].IntervalCount
;
3123 rIntervalCount
.clear();
3127 rIntervalCount
<<= sal_Int32( 9 );
3129 else if( !bAutoMajor
&& !bAutoMinor
&& (0.0 < maData
.mfMinorStep
) && (maData
.mfMinorStep
<= maData
.mfMajorStep
) )
3131 double fCount
= maData
.mfMajorStep
/ maData
.mfMinorStep
+ 0.5;
3132 if( (1.0 <= fCount
) && (fCount
< 1001.0) )
3133 rIntervalCount
<<= static_cast< sal_Int32
>( fCount
);
3135 else if( bAutoMinor
)
3137 // tdf#114168 If minor unit is not set then set interval to 5, as MS Excel do.
3138 rIntervalCount
<<= static_cast< sal_Int32
>( 5 );
3142 bool bReverse
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
) != bMirrorOrient
;
3143 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3146 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
) const
3148 bool bMaxCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
3149 bool bAutoCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
3150 bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3152 // crossing mode (max-cross flag overrides other crossing settings)
3153 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3154 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3156 // crossing position
3157 double fCrossingPos
= bAutoCross
? 0.0 : maData
.mfCross
;
3158 if( bLogScale
) fCrossingPos
= pow( 10.0, fCrossingPos
);
3159 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3164 sal_Int32
lclGetApiTickmarks( sal_uInt8 nXclTickPos
)
3166 using namespace ::com::sun::star::chart2::TickmarkStyle
;
3167 sal_Int32 nApiTickmarks
= css::chart2::TickmarkStyle::NONE
;
3168 ::set_flag( nApiTickmarks
, INNER
, ::get_flag( nXclTickPos
, EXC_CHTICK_INSIDE
) );
3169 ::set_flag( nApiTickmarks
, OUTER
, ::get_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
) );
3170 return nApiTickmarks
;
3173 cssc::ChartAxisLabelPosition
lclGetApiLabelPosition( sal_Int8 nXclLabelPos
)
3175 using namespace ::com::sun::star::chart
;
3176 switch( nXclLabelPos
)
3178 case EXC_CHTICK_LOW
: return ChartAxisLabelPosition_OUTSIDE_START
;
3179 case EXC_CHTICK_HIGH
: return ChartAxisLabelPosition_OUTSIDE_END
;
3180 case EXC_CHTICK_NEXT
: return ChartAxisLabelPosition_NEAR_AXIS
;
3182 return ChartAxisLabelPosition_NEAR_AXIS
;
3187 XclImpChTick::XclImpChTick( const XclImpChRoot
& rRoot
) :
3188 XclImpChRoot( rRoot
)
3192 void XclImpChTick::ReadChTick( XclImpStream
& rStrm
)
3194 maData
.mnMajor
= rStrm
.ReaduInt8();
3195 maData
.mnMinor
= rStrm
.ReaduInt8();
3196 maData
.mnLabelPos
= rStrm
.ReaduInt8();
3197 maData
.mnBackMode
= rStrm
.ReaduInt8();
3201 maData
.maTextComplexColor
.setColor(aColor
);
3202 maData
.mnFlags
= rStrm
.ReaduInt16();
3204 if( GetBiff() == EXC_BIFF8
)
3206 // BIFF8: index into palette used instead of RGB data
3207 maData
.maTextComplexColor
.setColor(GetPalette().GetColor(rStrm
.ReaduInt16()));
3209 maData
.mnRotation
= rStrm
.ReaduInt16();
3213 // BIFF2-BIFF7: get rotation from text orientation
3214 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 2, 3 );
3215 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
3219 Color
XclImpChTick::GetFontColor() const
3221 return ::get_flag(maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextComplexColor
.getFinalColor();
3224 sal_uInt16
XclImpChTick::GetRotation() const
3226 /* n#720443: Ignore auto-rotation if there is a suggested rotation.
3227 * Better fix would be to improve our axis auto rotation algorithm.
3229 if( maData
.mnRotation
!= EXC_ROT_NONE
)
3230 return maData
.mnRotation
;
3231 return ::get_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
) ? EXC_CHART_AUTOROTATION
: maData
.mnRotation
;
3234 void XclImpChTick::Convert( ScfPropertySet
& rPropSet
) const
3236 rPropSet
.SetProperty( EXC_CHPROP_MAJORTICKS
, lclGetApiTickmarks( maData
.mnMajor
) );
3237 rPropSet
.SetProperty( EXC_CHPROP_MINORTICKS
, lclGetApiTickmarks( maData
.mnMinor
) );
3238 rPropSet
.SetProperty( EXC_CHPROP_LABELPOSITION
, lclGetApiLabelPosition( maData
.mnLabelPos
) );
3239 rPropSet
.SetProperty( EXC_CHPROP_MARKPOSITION
, cssc::ChartAxisMarkPosition_AT_AXIS
);
3242 XclImpChAxis::XclImpChAxis( const XclImpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
3243 XclImpChRoot( rRoot
),
3244 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
3246 maData
.mnType
= nAxisType
;
3249 void XclImpChAxis::ReadHeaderRecord( XclImpStream
& rStrm
)
3251 maData
.mnType
= rStrm
.ReaduInt16();
3254 void XclImpChAxis::ReadSubRecord( XclImpStream
& rStrm
)
3256 switch( rStrm
.GetRecId() )
3258 case EXC_ID_CHLABELRANGE
:
3259 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3260 mxLabelRange
->ReadChLabelRange( rStrm
);
3262 case EXC_ID_CHDATERANGE
:
3264 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3265 mxLabelRange
->ReadChDateRange( rStrm
);
3267 case EXC_ID_CHVALUERANGE
:
3268 mxValueRange
= std::make_shared
<XclImpChValueRange
>( GetChRoot() );
3269 mxValueRange
->ReadChValueRange( rStrm
);
3271 case EXC_ID_CHFORMAT
:
3272 mnNumFmtIdx
= rStrm
.ReaduInt16();
3275 mxTick
= std::make_shared
<XclImpChTick
>( GetChRoot() );
3276 mxTick
->ReadChTick( rStrm
);
3279 mxFont
= std::make_shared
<XclImpChFont
>();
3280 mxFont
->ReadChFont( rStrm
);
3282 case EXC_ID_CHAXISLINE
:
3283 ReadChAxisLine( rStrm
);
3288 void XclImpChAxis::Finalize()
3290 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3292 mxLabelRange
= std::make_shared
<XclImpChLabelRange
>( GetChRoot() );
3294 mxValueRange
= std::make_shared
<XclImpChValueRange
>( GetChRoot() );
3295 // remove invisible grid lines completely
3296 if( mxMajorGrid
&& !mxMajorGrid
->HasLine() )
3297 mxMajorGrid
.clear();
3298 if( mxMinorGrid
&& !mxMinorGrid
->HasLine() )
3299 mxMinorGrid
.clear();
3300 // default tick settings different in OOChart and Excel
3302 mxTick
= std::make_shared
<XclImpChTick
>( GetChRoot() );
3303 // #i4140# different default axis line color
3306 XclChLineFormat aLineFmt
;
3307 // set "show axis" flag, default if line format record is missing
3308 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_SHOWAXIS
);
3309 mxAxisLine
= new XclImpChLineFormat( aLineFmt
);
3311 // add wall/floor frame for 3d charts
3316 sal_uInt16
XclImpChAxis::GetFontIndex() const
3318 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
3321 Color
XclImpChAxis::GetFontColor() const
3323 return mxTick
? mxTick
->GetFontColor() : GetFontAutoColor();
3326 sal_uInt16
XclImpChAxis::GetRotation() const
3328 return mxTick
? mxTick
->GetRotation() : EXC_CHART_AUTOROTATION
;
3331 Reference
< XAxis
> XclImpChAxis::CreateAxis( const XclImpChTypeGroup
& rTypeGroup
, const XclImpChAxis
* pCrossingAxis
) const
3333 // create the axis object (always)
3334 Reference
< XAxis
> xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS
), UNO_QUERY
);
3337 ScfPropertySet
aAxisProp( xAxis
);
3338 // #i58688# axis enabled
3339 aAxisProp
.SetBoolProperty( EXC_CHPROP_SHOW
, !mxAxisLine
|| mxAxisLine
->IsShowAxis() );
3341 // axis line properties
3343 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
3344 // axis ticks properties
3346 mxTick
->Convert( aAxisProp
);
3348 // axis caption text --------------------------------------------------
3350 // radar charts disable their category labels via chart type, not via axis
3351 bool bHasLabels
= (!mxTick
|| mxTick
->HasLabels()) &&
3352 ((GetAxisType() != EXC_CHAXIS_X
) || rTypeGroup
.HasCategoryLabels());
3353 aAxisProp
.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS
, bHasLabels
);
3356 // font settings from CHFONT record or from default text
3358 ConvertFontBase( GetChRoot(), aAxisProp
);
3359 else if( const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL
) )
3360 pDefText
->ConvertFont( aAxisProp
);
3361 // label text rotation
3362 ConvertRotationBase( aAxisProp
, true );
3364 bool bLinkNumberFmtToSource
= true;
3365 if ( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3367 sal_uInt32 nScNumFmt
= GetNumFmtBuffer().GetScFormat( mnNumFmtIdx
);
3368 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
3370 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT
, static_cast< sal_Int32
>( nScNumFmt
) );
3371 bLinkNumberFmtToSource
= false;
3375 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT_LINKSRC
, bLinkNumberFmtToSource
);
3378 // axis scaling and increment -----------------------------------------
3380 const XclChExtTypeInfo
& rTypeInfo
= rTypeGroup
.GetTypeInfo();
3381 ScaleData aScaleData
= xAxis
->getScaleData();
3383 switch( GetAxisType() )
3386 if( rTypeInfo
.mbCategoryAxis
)
3388 aScaleData
.AxisType
= cssc2::AxisType::CATEGORY
;
3389 aScaleData
.Categories
= rTypeGroup
.CreateCategSequence();
3392 aScaleData
.AxisType
= cssc2::AxisType::REALNUMBER
;
3395 aScaleData
.AxisType
= rTypeGroup
.IsPercent() ?
3396 cssc2::AxisType::PERCENT
: cssc2::AxisType::REALNUMBER
;
3399 aScaleData
.AxisType
= cssc2::AxisType::SERIES
;
3402 // axis scaling settings, dependent on axis type
3403 switch( aScaleData
.AxisType
)
3405 case cssc2::AxisType::CATEGORY
:
3406 case cssc2::AxisType::SERIES
:
3407 // #i71684# radar charts have reversed rotation direction
3409 mxLabelRange
->Convert( aAxisProp
, aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
);
3411 SAL_WARN("sc.filter", "missing LabelRange");
3413 case cssc2::AxisType::REALNUMBER
:
3414 case cssc2::AxisType::PERCENT
:
3415 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3417 mxValueRange
->Convert( aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3419 SAL_WARN("sc.filter", "missing ValueRange");
3422 OSL_FAIL( "XclImpChAxis::CreateAxis - unknown axis type" );
3425 /* Do not set a value to the Origin member anymore (will be done via
3426 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3427 aScaleData
.Origin
.clear();
3430 xAxis
->setScaleData( aScaleData
);
3432 // grid ---------------------------------------------------------------
3435 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3436 aGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMajorGrid
) );
3438 mxMajorGrid
->Convert( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3440 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3441 if( aSubGridPropSeq
.hasElements() )
3443 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3444 aSubGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMinorGrid
) );
3446 mxMinorGrid
->Convert( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3449 // position of crossing axis ------------------------------------------
3452 pCrossingAxis
->ConvertAxisPosition( aAxisProp
, rTypeGroup
);
3457 void XclImpChAxis::ConvertWall( ScfPropertySet
& rPropSet
) const
3459 // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3461 mxWallFrame
->Convert( rPropSet
, true );
3464 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet
& rPropSet
, const XclImpChTypeGroup
& rTypeGroup
) const
3466 if( ((GetAxisType() == EXC_CHAXIS_X
) && rTypeGroup
.GetTypeInfo().mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
) )
3469 mxLabelRange
->ConvertAxisPosition( rPropSet
, rTypeGroup
.Is3dChart() );
3471 SAL_WARN("sc.filter", "missing LabelRange");
3476 mxValueRange
->ConvertAxisPosition( rPropSet
);
3478 SAL_WARN("sc.filter", "missing ValueRange");
3482 void XclImpChAxis::ReadChAxisLine( XclImpStream
& rStrm
)
3484 XclImpChLineFormatRef
* pxLineFmt
= nullptr;
3485 bool bWallFrame
= false;
3486 switch( rStrm
.ReaduInt16() )
3488 case EXC_CHAXISLINE_AXISLINE
: pxLineFmt
= &mxAxisLine
; break;
3489 case EXC_CHAXISLINE_MAJORGRID
: pxLineFmt
= &mxMajorGrid
; break;
3490 case EXC_CHAXISLINE_MINORGRID
: pxLineFmt
= &mxMinorGrid
; break;
3491 case EXC_CHAXISLINE_WALLS
: bWallFrame
= true; break;
3496 bool bLoop
= pxLineFmt
|| bWallFrame
;
3499 sal_uInt16 nRecId
= rStrm
.GetNextRecId();
3500 bLoop
= ((nRecId
== EXC_ID_CHLINEFORMAT
) ||
3501 (nRecId
== EXC_ID_CHAREAFORMAT
) ||
3502 (nRecId
== EXC_ID_CHESCHERFORMAT
))
3503 && rStrm
.StartNextRecord();
3506 if( pxLineFmt
&& (nRecId
== EXC_ID_CHLINEFORMAT
) )
3508 (*pxLineFmt
) = new XclImpChLineFormat();
3509 (*pxLineFmt
)->ReadChLineFormat( rStrm
);
3511 else if( bWallFrame
&& mxWallFrame
)
3513 mxWallFrame
->ReadSubRecord( rStrm
);
3519 void XclImpChAxis::CreateWallFrame()
3521 switch( GetAxisType() )
3524 mxWallFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_WALL3D
);
3527 mxWallFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D
);
3530 mxWallFrame
.reset();
3534 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3535 XclImpChRoot( rRoot
)
3537 maData
.mnAxesSetId
= nAxesSetId
;
3540 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream
& rStrm
)
3542 maData
.mnAxesSetId
= rStrm
.ReaduInt16();
3543 rStrm
>> maData
.maRect
;
3546 void XclImpChAxesSet::ReadSubRecord( XclImpStream
& rStrm
)
3548 switch( rStrm
.GetRecId() )
3550 case EXC_ID_CHFRAMEPOS
:
3551 mxFramePos
= std::make_shared
<XclImpChFramePos
>();
3552 mxFramePos
->ReadChFramePos( rStrm
);
3555 ReadChAxis( rStrm
);
3558 ReadChText( rStrm
);
3560 case EXC_ID_CHPLOTFRAME
:
3561 ReadChPlotFrame( rStrm
);
3563 case EXC_ID_CHTYPEGROUP
:
3564 ReadChTypeGroup( rStrm
);
3569 void XclImpChAxesSet::Finalize()
3571 if( IsValidAxesSet() )
3573 // finalize chart type groups, erase empty groups without series
3574 XclImpChTypeGroupMap aValidGroups
;
3575 for (auto const& typeGroup
: maTypeGroups
)
3577 XclImpChTypeGroupRef xTypeGroup
= typeGroup
.second
;
3578 xTypeGroup
->Finalize();
3579 if( xTypeGroup
->IsValidGroup() )
3580 aValidGroups
.emplace(typeGroup
.first
, xTypeGroup
);
3582 maTypeGroups
.swap( aValidGroups
);
3585 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3586 if( !IsValidAxesSet() )
3589 // always create missing axis objects
3591 mxXAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_X
);
3593 mxYAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_Y
);
3594 if( !mxZAxis
&& GetFirstTypeGroup()->Is3dDeepChart() )
3595 mxZAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot(), EXC_CHAXIS_Z
);
3598 if( mxXAxis
) mxXAxis
->Finalize();
3599 if( mxYAxis
) mxYAxis
->Finalize();
3600 if( mxZAxis
) mxZAxis
->Finalize();
3602 // finalize axis titles
3603 const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE
);
3604 OUString
aAutoTitle(ScResId(STR_AXISTITLE
));
3605 lclFinalizeTitle( mxXAxisTitle
, pDefText
, aAutoTitle
);
3606 lclFinalizeTitle( mxYAxisTitle
, pDefText
, aAutoTitle
);
3607 lclFinalizeTitle( mxZAxisTitle
, pDefText
, aAutoTitle
);
3609 // #i47745# missing plot frame -> invisible border and area
3611 mxPlotFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
);
3614 XclImpChTypeGroupRef
XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3616 XclImpChTypeGroupMap::const_iterator itr
= maTypeGroups
.find(nGroupIdx
);
3617 return itr
== maTypeGroups
.end() ? XclImpChTypeGroupRef() : itr
->second
;
3620 XclImpChTypeGroupRef
XclImpChAxesSet::GetFirstTypeGroup() const
3622 XclImpChTypeGroupRef xTypeGroup
;
3623 if( !maTypeGroups
.empty() )
3624 xTypeGroup
= maTypeGroups
.begin()->second
;
3628 XclImpChLegendRef
XclImpChAxesSet::GetLegend() const
3630 XclImpChLegendRef xLegend
;
3631 for( const auto& rEntry
: maTypeGroups
)
3633 xLegend
= rEntry
.second
->GetLegend();
3640 OUString
XclImpChAxesSet::GetSingleSeriesTitle() const
3642 return (maTypeGroups
.size() == 1) ? maTypeGroups
.begin()->second
->GetSingleSeriesTitle() : OUString();
3645 void XclImpChAxesSet::Convert( Reference
< XDiagram
> const & xDiagram
) const
3647 if( !(IsValidAxesSet() && xDiagram
.is()) )
3650 // diagram background formatting
3651 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY
)
3652 ConvertBackground( xDiagram
);
3654 // create the coordinate system, this inserts all chart types and series
3655 Reference
< XCoordinateSystem
> xCoordSystem
= CreateCoordSystem( xDiagram
);
3656 if( !xCoordSystem
.is() )
3659 // insert coordinate system, if not already done
3662 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY_THROW
);
3663 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3664 if( !aCoordSystems
.hasElements() )
3665 xCoordSystemCont
->addCoordinateSystem( xCoordSystem
);
3669 OSL_FAIL( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3672 // create the axes with grids and axis titles and insert them into the diagram
3673 ConvertAxis( mxXAxis
, mxXAxisTitle
, xCoordSystem
, mxYAxis
.get() );
3674 ConvertAxis( mxYAxis
, mxYAxisTitle
, xCoordSystem
, mxXAxis
.get() );
3675 ConvertAxis( mxZAxis
, mxZAxisTitle
, xCoordSystem
, nullptr );
3678 void XclImpChAxesSet::ConvertTitlePositions() const
3681 mxXAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_X
) );
3683 mxYAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Y
) );
3685 mxZAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Z
) );
3688 void XclImpChAxesSet::ReadChAxis( XclImpStream
& rStrm
)
3690 XclImpChAxisRef xAxis
= std::make_shared
<XclImpChAxis
>( GetChRoot() );
3691 xAxis
->ReadRecordGroup( rStrm
);
3693 switch( xAxis
->GetAxisType() )
3695 case EXC_CHAXIS_X
: mxXAxis
= xAxis
; break;
3696 case EXC_CHAXIS_Y
: mxYAxis
= xAxis
; break;
3697 case EXC_CHAXIS_Z
: mxZAxis
= xAxis
; break;
3701 void XclImpChAxesSet::ReadChText( XclImpStream
& rStrm
)
3703 XclImpChTextRef xText
= std::make_shared
<XclImpChText
>( GetChRoot() );
3704 xText
->ReadRecordGroup( rStrm
);
3706 switch( xText
->GetLinkTarget() )
3708 case EXC_CHOBJLINK_XAXIS
: mxXAxisTitle
= xText
; break;
3709 case EXC_CHOBJLINK_YAXIS
: mxYAxisTitle
= xText
; break;
3710 case EXC_CHOBJLINK_ZAXIS
: mxZAxisTitle
= xText
; break;
3714 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream
& rStrm
)
3716 if( (rStrm
.GetNextRecId() == EXC_ID_CHFRAME
) && rStrm
.StartNextRecord() )
3718 mxPlotFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
);
3719 mxPlotFrame
->ReadRecordGroup( rStrm
);
3723 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream
& rStrm
)
3725 XclImpChTypeGroupRef xTypeGroup
= std::make_shared
<XclImpChTypeGroup
>( GetChRoot() );
3726 xTypeGroup
->ReadRecordGroup( rStrm
);
3727 sal_uInt16 nGroupIdx
= xTypeGroup
->GetGroupIdx();
3728 XclImpChTypeGroupMap::iterator itr
= maTypeGroups
.lower_bound(nGroupIdx
);
3729 if (itr
!= maTypeGroups
.end() && !maTypeGroups
.key_comp()(nGroupIdx
, itr
->first
))
3731 // Overwrite the existing element.
3732 itr
->second
= std::move(xTypeGroup
);
3735 maTypeGroups
.insert(
3736 itr
, XclImpChTypeGroupMap::value_type(nGroupIdx
, xTypeGroup
));
3739 Reference
< XCoordinateSystem
> XclImpChAxesSet::CreateCoordSystem( Reference
< XDiagram
> const & xDiagram
) const
3741 Reference
< XCoordinateSystem
> xCoordSystem
;
3743 /* Try to get existing coordinate system. For now, all series from primary
3744 and secondary axes sets are inserted into one coordinate system. Later,
3745 this should be changed to use one coordinate system for each axes set. */
3746 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY
);
3747 if( xCoordSystemCont
.is() )
3749 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3750 OSL_ENSURE( aCoordSystems
.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3751 if( aCoordSystems
.hasElements() )
3752 xCoordSystem
= aCoordSystems
[ 0 ];
3755 // create the coordinate system according to the first chart type
3756 if( !xCoordSystem
.is() )
3758 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3761 xCoordSystem
= xTypeGroup
->CreateCoordSystem();
3762 // convert 3d chart settings
3763 ScfPropertySet
aDiaProp( xDiagram
);
3764 xTypeGroup
->ConvertChart3d( aDiaProp
);
3768 /* Create XChartType objects for all chart type groups. Each group will
3769 add its series to the data provider attached to the chart document. */
3770 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3771 if( xChartTypeCont
.is() )
3773 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3774 for( const auto& rEntry
: maTypeGroups
)
3778 Reference
< XChartType
> xChartType
= rEntry
.second
->CreateChartType( xDiagram
, nApiAxesSetIdx
);
3779 if( xChartType
.is() )
3780 xChartTypeCont
->addChartType( xChartType
);
3784 OSL_FAIL( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3789 return xCoordSystem
;
3792 void XclImpChAxesSet::ConvertAxis(
3793 XclImpChAxisRef
const & xChAxis
, XclImpChTextRef
const & xChAxisTitle
,
3794 Reference
< XCoordinateSystem
> const & xCoordSystem
, const XclImpChAxis
* pCrossingAxis
) const
3799 // create and attach the axis object
3800 Reference
< XAxis
> xAxis
= CreateAxis( *xChAxis
, pCrossingAxis
);
3804 // create and attach the axis title
3805 if( xChAxisTitle
) try
3807 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY_THROW
);
3808 Reference
< XTitle
> xTitle( xChAxisTitle
->CreateTitle(), UNO_SET_THROW
);
3809 xTitled
->setTitleObject( xTitle
);
3813 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3816 // insert axis into coordinate system
3819 sal_Int32 nApiAxisDim
= xChAxis
->GetApiAxisDimension();
3820 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3821 xCoordSystem
->setAxisByDimension( nApiAxisDim
, xAxis
, nApiAxesSetIdx
);
3825 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3829 Reference
< XAxis
> XclImpChAxesSet::CreateAxis( const XclImpChAxis
& rChAxis
, const XclImpChAxis
* pCrossingAxis
) const
3831 Reference
< XAxis
> xAxis
;
3832 if( const XclImpChTypeGroup
* pTypeGroup
= GetFirstTypeGroup().get() )
3833 xAxis
= rChAxis
.CreateAxis( *pTypeGroup
, pCrossingAxis
);
3837 void XclImpChAxesSet::ConvertBackground( Reference
< XDiagram
> const & xDiagram
) const
3839 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3840 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3842 // wall/floor formatting (3D charts)
3845 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3846 mxXAxis
->ConvertWall( aWallProp
);
3850 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3851 mxYAxis
->ConvertWall( aFloorProp
);
3854 else if( mxPlotFrame
)
3856 // diagram background formatting
3857 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3858 mxPlotFrame
->Convert( aWallProp
);
3862 // The chart object ===========================================================
3864 XclImpChChart::XclImpChChart( const XclImpRoot
& rRoot
) :
3865 XclImpChRoot( rRoot
, *this )
3867 mxPrimAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_PRIMARY
);
3868 mxSecnAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_SECONDARY
);
3871 XclImpChChart::~XclImpChChart()
3875 void XclImpChChart::ReadHeaderRecord( XclImpStream
& rStrm
)
3877 // coordinates are stored as 16.16 fixed point
3881 void XclImpChChart::ReadSubRecord( XclImpStream
& rStrm
)
3883 switch( rStrm
.GetRecId() )
3885 case EXC_ID_CHFRAME
:
3886 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
3887 mxFrame
->ReadRecordGroup( rStrm
);
3889 case EXC_ID_CHSERIES
:
3890 ReadChSeries( rStrm
);
3892 case EXC_ID_CHPROPERTIES
:
3893 ReadChProperties( rStrm
);
3895 case EXC_ID_CHDEFAULTTEXT
:
3896 ReadChDefaultText( rStrm
);
3898 case EXC_ID_CHAXESSET
:
3899 ReadChAxesSet( rStrm
);
3902 ReadChText( rStrm
);
3905 Finalize(); // finalize the entire chart object
3910 void XclImpChChart::ReadChDefaultText( XclImpStream
& rStrm
)
3912 sal_uInt16 nTextId
= rStrm
.ReaduInt16();
3913 if( (rStrm
.GetNextRecId() == EXC_ID_CHTEXT
) && rStrm
.StartNextRecord() )
3915 unique_ptr
<XclImpChText
> pText(new XclImpChText(GetChRoot()));
3916 pText
->ReadRecordGroup(rStrm
);
3917 m_DefTexts
.insert(std::make_pair(nTextId
, std::move(pText
)));
3921 void XclImpChChart::ReadChDataFormat( XclImpStream
& rStrm
)
3923 XclImpChDataFormatRef xDataFmt
= std::make_shared
<XclImpChDataFormat
>( GetChRoot() );
3924 xDataFmt
->ReadRecordGroup( rStrm
);
3925 if( xDataFmt
->GetPointPos().mnSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3927 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
3928 XclImpChDataFormatMap::iterator itr
= maDataFmts
.lower_bound(rPos
);
3929 if (itr
== maDataFmts
.end() || maDataFmts
.key_comp()(rPos
, itr
->first
))
3930 // No element exists for this data point. Insert it.
3932 itr
, XclImpChDataFormatMap::value_type(rPos
, xDataFmt
));
3934 /* Do not overwrite existing data format group, Excel always uses the
3935 first data format group occurring in any CHSERIES group. */
3939 void XclImpChChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
3942 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
3943 mxFrame
->UpdateObjFrame( rLineData
, rFillData
);
3946 XclImpChTypeGroupRef
XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3948 XclImpChTypeGroupRef xTypeGroup
= mxPrimAxesSet
->GetTypeGroup( nGroupIdx
);
3949 if( !xTypeGroup
) xTypeGroup
= mxSecnAxesSet
->GetTypeGroup( nGroupIdx
);
3950 if( !xTypeGroup
) xTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup();
3954 const XclImpChText
* XclImpChChart::GetDefaultText( XclChTextType eTextType
) const
3956 sal_uInt16 nDefTextId
= EXC_CHDEFTEXT_GLOBAL
;
3957 bool bBiff8
= GetBiff() == EXC_BIFF8
;
3960 case EXC_CHTEXTTYPE_TITLE
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3961 case EXC_CHTEXTTYPE_LEGEND
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3962 case EXC_CHTEXTTYPE_AXISTITLE
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3963 case EXC_CHTEXTTYPE_AXISLABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3964 case EXC_CHTEXTTYPE_DATALABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3967 XclImpChTextMap::const_iterator
const itr
= m_DefTexts
.find(nDefTextId
);
3968 return itr
== m_DefTexts
.end() ? nullptr : itr
->second
.get();
3971 bool XclImpChChart::IsManualPlotArea() const
3973 // there is no real automatic mode in BIFF5 charts
3974 return (GetBiff() <= EXC_BIFF5
) || ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3977 void XclImpChChart::Convert( const Reference
<XChartDocument
>& xChartDoc
,
3978 XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
3980 // initialize conversion (locks the model to suppress any internal updates)
3981 InitConversion( xChartDoc
, rChartRect
);
3983 // chart frame formatting
3986 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3987 mxFrame
->Convert( aFrameProp
);
3993 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY_THROW
);
3994 Reference
< XTitle
> xTitle( mxTitle
->CreateTitle(), UNO_SET_THROW
);
3995 xTitled
->setTitleObject( xTitle
);
4001 /* Create the diagram object and attach it to the chart document. Currently,
4002 one diagram is used to carry all coordinate systems and data series. */
4003 Reference
< XDiagram
> xDiagram
= CreateDiagram();
4004 xChartDoc
->setFirstDiagram( xDiagram
);
4006 // coordinate systems and chart types, convert axis settings
4007 mxPrimAxesSet
->Convert( xDiagram
);
4008 mxSecnAxesSet
->Convert( xDiagram
);
4011 if( xDiagram
.is() && mxLegend
)
4012 xDiagram
->setLegend( mxLegend
->CreateLegend() );
4014 /* Following all conversions needing the old Chart1 API that involves full
4015 initialization of the chart view. */
4016 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY
);
4017 if( xChart1Doc
.is() )
4019 Reference
< cssc::XDiagram
> xDiagram1
= xChart1Doc
->getDiagram();
4021 /* Set the 'IncludeHiddenCells' property via the old API as only this
4022 ensures that the data provider and all created sequences get this
4024 ScfPropertySet
aDiaProp( xDiagram1
);
4025 bool bShowVisCells
= ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
);
4026 aDiaProp
.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
, !bShowVisCells
);
4028 // plot area position and size (there is no real automatic mode in BIFF5 charts)
4029 XclImpChFramePosRef xPlotAreaPos
= mxPrimAxesSet
->GetPlotAreaFramePos();
4030 if( IsManualPlotArea() && xPlotAreaPos
) try
4032 const XclChFramePos
& rFramePos
= xPlotAreaPos
->GetFramePosData();
4033 if( (rFramePos
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rFramePos
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
) )
4035 Reference
< cssc::XDiagramPositioning
> xPositioning( xDiagram1
, UNO_QUERY_THROW
);
4036 css::awt::Rectangle aDiagramRect
= CalcHmmFromChartRect( rFramePos
.maRect
);
4037 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
4038 const XclImpChTypeGroup
* pFirstTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup().get();
4039 if( pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
4040 xPositioning
->setDiagramPositionExcludingAxes( aDiagramRect
);
4041 else if( pFirstTypeGroup
&& pFirstTypeGroup
->Is3dChart() )
4042 xPositioning
->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect
);
4044 xPositioning
->setDiagramPositionIncludingAxes( aDiagramRect
);
4051 // positions of all title objects
4053 mxTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE
) );
4054 mxPrimAxesSet
->ConvertTitlePositions();
4055 mxSecnAxesSet
->ConvertTitlePositions();
4059 FinishConversion( rDffConv
);
4061 // start listening to this chart
4062 ScDocument
& rDoc
= GetRoot().GetDoc();
4063 ScChartListenerCollection
* pChartCollection
= rDoc
.GetChartListenerCollection();
4064 if(!pChartCollection
)
4067 std::vector
< ScTokenRef
> aRefTokens
;
4068 for( const auto& rxSeries
: maSeries
)
4069 rxSeries
->FillAllSourceLinks( aRefTokens
);
4070 if( !aRefTokens
.empty() )
4072 ::std::unique_ptr
< ScChartListener
> xListener( new ScChartListener( rObjName
, rDoc
, std::move(aRefTokens
) ) );
4073 xListener
->SetUsed( true );
4074 xListener
->StartListeningTo();
4075 pChartCollection
->insert( xListener
.release() );
4079 void XclImpChChart::ReadChSeries( XclImpStream
& rStrm
)
4081 sal_uInt16 nNewSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.size() );
4082 XclImpChSeriesRef xSeries
= std::make_shared
<XclImpChSeries
>( GetChRoot(), nNewSeriesIdx
);
4083 xSeries
->ReadRecordGroup( rStrm
);
4084 maSeries
.push_back( xSeries
);
4087 void XclImpChChart::ReadChProperties( XclImpStream
& rStrm
)
4089 maProps
.mnFlags
= rStrm
.ReaduInt16();
4090 maProps
.mnEmptyMode
= rStrm
.ReaduInt8();
4093 void XclImpChChart::ReadChAxesSet( XclImpStream
& rStrm
)
4095 XclImpChAxesSetRef xAxesSet
= std::make_shared
<XclImpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_NONE
);
4096 xAxesSet
->ReadRecordGroup( rStrm
);
4097 switch( xAxesSet
->GetAxesSetId() )
4099 case EXC_CHAXESSET_PRIMARY
: mxPrimAxesSet
= xAxesSet
; break;
4100 case EXC_CHAXESSET_SECONDARY
: mxSecnAxesSet
= xAxesSet
; break;
4104 void XclImpChChart::ReadChText( XclImpStream
& rStrm
)
4106 XclImpChTextRef xText
= std::make_shared
<XclImpChText
>( GetChRoot() );
4107 xText
->ReadRecordGroup( rStrm
);
4108 switch( xText
->GetLinkTarget() )
4110 case EXC_CHOBJLINK_TITLE
:
4113 case EXC_CHOBJLINK_DATA
:
4115 sal_uInt16 nSeriesIdx
= xText
->GetPointPos().mnSeriesIdx
;
4116 if( nSeriesIdx
< maSeries
.size() )
4117 maSeries
[ nSeriesIdx
]->SetDataLabel( xText
);
4123 void XclImpChChart::Finalize()
4125 // finalize series (must be done first)
4127 // #i49218# legend may be attached to primary or secondary axes set
4128 mxLegend
= mxPrimAxesSet
->GetLegend();
4130 mxLegend
= mxSecnAxesSet
->GetLegend();
4132 mxLegend
->Finalize();
4133 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
4134 mxPrimAxesSet
->Finalize();
4135 mxSecnAxesSet
->Finalize();
4136 // formatting of all series
4137 FinalizeDataFormats();
4138 // #i47745# missing frame -> invisible border and area
4140 mxFrame
= std::make_shared
<XclImpChFrame
>( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
);
4145 void XclImpChChart::FinalizeSeries()
4147 for( const XclImpChSeriesRef
& xSeries
: maSeries
)
4149 if( xSeries
->HasParentSeries() )
4151 /* Process child series (trend lines and error bars). Data of
4152 child series will be set at the connected parent series. */
4153 if( xSeries
->GetParentIdx() < maSeries
.size() )
4154 maSeries
[ xSeries
->GetParentIdx() ]->AddChildSeries( *xSeries
);
4158 // insert the series into the related chart type group
4159 if( XclImpChTypeGroup
* pTypeGroup
= GetTypeGroup( xSeries
->GetGroupIdx() ).get() )
4160 pTypeGroup
->AddSeries( xSeries
);
4165 void XclImpChChart::FinalizeDataFormats()
4167 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4168 Each CHDATAFORMAT group specifies the series and data point it is
4169 assigned to. This makes it possible to have a data format that is
4170 related to another series, e.g. a CHDATAFORMAT group for series 2 is
4171 part of a CHSERIES group that describes series 1. Therefore the chart
4172 itself has collected all CHDATAFORMAT groups to be able to store data
4173 format groups for series that have not been imported at that time. This
4174 loop finally assigns these groups to the related series. */
4175 for( const auto& [rPos
, rDataFmt
] : maDataFmts
)
4177 sal_uInt16 nSeriesIdx
= rPos
.mnSeriesIdx
;
4178 if( nSeriesIdx
< maSeries
.size() )
4179 maSeries
[ nSeriesIdx
]->SetDataFormat( rDataFmt
);
4182 /* #i51639# (part 2): Finalize data formats of all series. This adds for
4183 example missing CHDATAFORMAT groups for entire series that are needed
4184 for automatic colors of lines and areas. */
4185 for( auto& rxSeries
: maSeries
)
4186 rxSeries
->FinalizeDataFormats();
4189 void XclImpChChart::FinalizeTitle()
4191 // special handling for auto-generated title
4192 OUString aAutoTitle
;
4193 if( !mxTitle
|| (!mxTitle
->IsDeleted() && !mxTitle
->HasString()) )
4195 // automatic title from first series name (if there are no series on secondary axes set)
4196 if( !mxSecnAxesSet
->IsValidAxesSet() )
4197 aAutoTitle
= mxPrimAxesSet
->GetSingleSeriesTitle();
4198 if( mxTitle
|| (!aAutoTitle
.isEmpty()) )
4201 mxTitle
= std::make_shared
<XclImpChText
>( GetChRoot() );
4202 if( aAutoTitle
.isEmpty() )
4203 aAutoTitle
= ScResId(STR_CHARTTITLE
);
4207 // will reset mxTitle, if it does not contain a string and no auto title exists
4208 lclFinalizeTitle( mxTitle
, GetDefaultText( EXC_CHTEXTTYPE_TITLE
), aAutoTitle
);
4211 Reference
< XDiagram
> XclImpChChart::CreateDiagram() const
4213 // create a diagram object
4214 Reference
< XDiagram
> xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM
), UNO_QUERY
);
4216 // convert global chart settings
4217 ScfPropertySet
aDiaProp( xDiagram
);
4219 // treatment of missing values
4220 using namespace cssc::MissingValueTreatment
;
4221 sal_Int32 nMissingValues
= LEAVE_GAP
;
4222 switch( maProps
.mnEmptyMode
)
4224 case EXC_CHPROPS_EMPTY_SKIP
: nMissingValues
= LEAVE_GAP
; break;
4225 case EXC_CHPROPS_EMPTY_ZERO
: nMissingValues
= USE_ZERO
; break;
4226 case EXC_CHPROPS_EMPTY_INTERPOLATE
: nMissingValues
= CONTINUE
; break;
4228 aDiaProp
.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT
, nMissingValues
);
4233 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4234 XclImpDrawing( rRoot
, bOwnTab
), // sheet charts may contain OLE objects
4235 mnScTab( rRoot
.GetCurrScTab() ),
4240 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter
& rDffConv
,
4241 const Reference
< XModel
>& rxModel
, const tools::Rectangle
& rChartRect
)
4243 maChartRect
= rChartRect
; // needed in CalcAnchorRect() callback
4245 SdrModel
* pSdrModel
= nullptr;
4246 SdrPage
* pSdrPage
= nullptr;
4249 // chart sheet: insert all shapes into the sheet, not into the chart object
4250 pSdrModel
= GetDoc().GetDrawLayer();
4251 pSdrPage
= GetSdrPage( mnScTab
);
4255 // embedded chart object: insert all shapes into the chart
4258 Reference
< XDrawPageSupplier
> xDrawPageSupp( rxModel
, UNO_QUERY_THROW
);
4259 Reference
< XDrawPage
> xDrawPage( xDrawPageSupp
->getDrawPage(), UNO_SET_THROW
);
4260 pSdrPage
= ::GetSdrPageFromXDrawPage( xDrawPage
);
4261 pSdrModel
= pSdrPage
? &pSdrPage
->getSdrModelFromSdrPage() : nullptr;
4268 if( pSdrModel
&& pSdrPage
)
4269 ImplConvertObjects( rDffConv
, *pSdrModel
, *pSdrPage
);
4272 tools::Rectangle
XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor
& rAnchor
, bool bDffAnchor
) const
4274 /* In objects with DFF client anchor, the position of the shape is stored
4275 in the cell address components of the client anchor. In old BIFF3-BIFF5
4276 objects, the position is stored in the offset components of the anchor. */
4277 tools::Rectangle
aRect(
4278 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnCol
: rAnchor
.mnLX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4279 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnRow
: rAnchor
.mnTY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ),
4280 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnCol
: rAnchor
.mnRX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4281 static_cast< tools::Long
>( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnRow
: rAnchor
.mnBY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ) );
4283 // move shapes into chart area for sheet charts
4285 aRect
.Move( maChartRect
.Left(), maChartRect
.Top() );
4289 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase
& )
4293 XclImpChart::XclImpChart( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4294 XclImpRoot( rRoot
),
4295 mbOwnTab( bOwnTab
),
4296 mbIsPivotChart( false )
4300 XclImpChart::~XclImpChart()
4304 void XclImpChart::ReadChartSubStream( XclImpStream
& rStrm
)
4306 XclImpPageSettings
& rPageSett
= GetPageSettings();
4307 XclImpTabViewSettings
& rTabViewSett
= GetTabViewSettings();
4310 while( bLoop
&& rStrm
.StartNextRecord() )
4312 // page settings - only for charts in entire sheet
4313 if( mbOwnTab
) switch( rStrm
.GetRecId() )
4315 case EXC_ID_HORPAGEBREAKS
:
4316 case EXC_ID_VERPAGEBREAKS
: rPageSett
.ReadPageBreaks( rStrm
); break;
4318 case EXC_ID_FOOTER
: rPageSett
.ReadHeaderFooter( rStrm
); break;
4319 case EXC_ID_LEFTMARGIN
:
4320 case EXC_ID_RIGHTMARGIN
:
4321 case EXC_ID_TOPMARGIN
:
4322 case EXC_ID_BOTTOMMARGIN
: rPageSett
.ReadMargin( rStrm
); break;
4323 case EXC_ID_PRINTHEADERS
: rPageSett
.ReadPrintHeaders( rStrm
); break;
4324 case EXC_ID_PRINTGRIDLINES
: rPageSett
.ReadPrintGridLines( rStrm
); break;
4325 case EXC_ID_HCENTER
:
4326 case EXC_ID_VCENTER
: rPageSett
.ReadCenter( rStrm
); break;
4327 case EXC_ID_SETUP
: rPageSett
.ReadSetup( rStrm
); break;
4328 case EXC_ID8_IMGDATA
: rPageSett
.ReadImgData( rStrm
); break;
4330 case EXC_ID_WINDOW2
: rTabViewSett
.ReadWindow2( rStrm
, true );break;
4331 case EXC_ID_SCL
: rTabViewSett
.ReadScl( rStrm
); break;
4333 case EXC_ID_SHEETEXT
: //0x0862
4335 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4336 XclImpPalette
& rPal
= GetPalette();
4337 rTabViewSett
.ReadTabBgColor( rStrm
, rPal
);
4341 case EXC_ID_CODENAME
: ReadCodeName( rStrm
, false ); break;
4345 switch( rStrm
.GetRecId() )
4347 case EXC_ID_EOF
: bLoop
= false; break;
4349 // #i31882# ignore embedded chart objects
4353 case EXC_ID5_BOF
: XclTools::SkipSubStream( rStrm
); break;
4355 case EXC_ID_CHCHART
: ReadChChart( rStrm
); break;
4357 case EXC_ID8_CHPIVOTREF
:
4358 GetTracer().TracePivotChartExists();
4359 mbIsPivotChart
= true;
4362 // BIFF specific records
4363 default: switch( GetBiff() )
4365 case EXC_BIFF5
: switch( rStrm
.GetRecId() )
4367 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4370 case EXC_BIFF8
: switch( rStrm
.GetRecId() )
4372 case EXC_ID_MSODRAWING
: GetChartDrawing().ReadMsoDrawing( rStrm
); break;
4373 // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4374 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4383 void XclImpChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
4386 mxChartData
= std::make_shared
<XclImpChChart
>( GetRoot() );
4387 mxChartData
->UpdateObjFrame( rLineData
, rFillData
);
4390 std::size_t XclImpChart::GetProgressSize() const
4393 (mxChartData
? XclImpChChart::GetProgressSize() : 0) +
4394 (mxChartDrawing
? mxChartDrawing
->GetProgressSize() : 0);
4397 void XclImpChart::Convert( Reference
< XModel
> const & xModel
, XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
4399 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
4400 if( xChartDoc
.is() )
4403 mxChartData
->Convert( xChartDoc
, rDffConv
, rObjName
, rChartRect
);
4404 if( mxChartDrawing
)
4405 mxChartDrawing
->ConvertObjects( rDffConv
, xModel
, rChartRect
);
4409 XclImpChartDrawing
& XclImpChart::GetChartDrawing()
4411 if( !mxChartDrawing
)
4412 mxChartDrawing
= std::make_shared
<XclImpChartDrawing
>( GetRoot(), mbOwnTab
);
4413 return *mxChartDrawing
;
4416 void XclImpChart::ReadChChart( XclImpStream
& rStrm
)
4418 mxChartData
= std::make_shared
<XclImpChChart
>( GetRoot() );
4419 mxChartData
->ReadRecordGroup( rStrm
);
4422 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */