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 <sfx2/objsh.hxx>
80 #include <svx/svdpage.hxx>
81 #include <svx/unoapi.hxx>
82 #include <sal/log.hxx>
83 #include <tools/helpers.hxx>
85 #include <document.hxx>
86 #include <drwlayer.hxx>
87 #include <tokenarray.hxx>
88 #include <compiler.hxx>
89 #include <reftokenhelper.hxx>
90 #include <chartlis.hxx>
91 #include <globstr.hrc>
92 #include <scresid.hxx>
93 #include <xltracer.hxx>
94 #include <xltools.hxx>
95 #include <xistream.hxx>
96 #include <xiformula.hxx>
97 #include <xistyle.hxx>
101 using ::com::sun::star::uno::Any
;
102 using ::com::sun::star::uno::Reference
;
103 using ::com::sun::star::uno::Sequence
;
104 using ::com::sun::star::uno::UNO_QUERY
;
105 using ::com::sun::star::uno::UNO_QUERY_THROW
;
106 using ::com::sun::star::uno::UNO_SET_THROW
;
107 using ::com::sun::star::uno::Exception
;
108 using ::com::sun::star::beans::XPropertySet
;
109 using ::com::sun::star::frame::XModel
;
110 using ::com::sun::star::util::XNumberFormatsSupplier
;
111 using ::com::sun::star::drawing::XDrawPage
;
112 using ::com::sun::star::drawing::XDrawPageSupplier
;
113 using ::com::sun::star::drawing::XShape
;
115 using namespace ::com::sun::star::chart2
;
117 using ::com::sun::star::chart2::data::XDataProvider
;
118 using ::com::sun::star::chart2::data::XDataReceiver
;
119 using ::com::sun::star::chart2::data::XDataSequence
;
120 using ::com::sun::star::chart2::data::XDataSink
;
121 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
122 using ::com::sun::star::chart2::data::LabeledDataSequence
;
124 using ::formula::FormulaToken
;
125 using ::formula::FormulaTokenArrayPlainIterator
;
126 using ::std::unique_ptr
;
128 namespace cssc
= ::com::sun::star::chart
;
129 namespace cssc2
= ::com::sun::star::chart2
;
131 // Helpers ====================================================================
135 XclImpStream
& operator>>( XclImpStream
& rStrm
, XclChRectangle
& rRect
)
137 rRect
.mnX
= rStrm
.ReadInt32();
138 rRect
.mnY
= rStrm
.ReadInt32();
139 rRect
.mnWidth
= rStrm
.ReadInt32();
140 rRect
.mnHeight
= rStrm
.ReadInt32();
144 void lclSetValueOrClearAny( Any
& rAny
, double fValue
, bool bClear
)
152 void lclSetExpValueOrClearAny( Any
& rAny
, double fValue
, bool bLogScale
, bool bClear
)
154 if( !bClear
&& bLogScale
)
155 fValue
= pow( 10.0, fValue
);
156 lclSetValueOrClearAny( rAny
, fValue
, bClear
);
159 double lclGetSerialDay( const XclImpRoot
& rRoot
, sal_uInt16 nValue
, sal_uInt16 nTimeUnit
)
163 case EXC_CHDATERANGE_DAYS
:
165 case EXC_CHDATERANGE_MONTHS
:
166 return rRoot
.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16
>( 1 + nValue
% 12 ), static_cast< sal_uInt16
>( rRoot
.GetBaseYear() + nValue
/ 12 ) ) );
167 case EXC_CHDATERANGE_YEARS
:
168 return rRoot
.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16
>( rRoot
.GetBaseYear() + nValue
) ) );
170 OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
175 void lclConvertTimeValue( const XclImpRoot
& rRoot
, Any
& rAny
, sal_uInt16 nValue
, bool bAuto
, sal_uInt16 nTimeUnit
)
180 rAny
<<= lclGetSerialDay( rRoot
, nValue
, nTimeUnit
);
183 sal_Int32
lclGetApiTimeUnit( sal_uInt16 nTimeUnit
)
187 case EXC_CHDATERANGE_DAYS
: return cssc::TimeUnit::DAY
;
188 case EXC_CHDATERANGE_MONTHS
: return cssc::TimeUnit::MONTH
;
189 case EXC_CHDATERANGE_YEARS
: return cssc::TimeUnit::YEAR
;
190 default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
192 return cssc::TimeUnit::DAY
;
195 void lclConvertTimeInterval( Any
& rInterval
, sal_uInt16 nValue
, bool bAuto
, sal_uInt16 nTimeUnit
)
197 if( bAuto
|| (nValue
== 0) )
200 rInterval
<<= cssc::TimeInterval( nValue
, lclGetApiTimeUnit( nTimeUnit
) );
205 // Common =====================================================================
207 /** Stores global data needed in various classes of the Chart import filter. */
208 struct XclImpChRootData
: public XclChRootData
210 XclImpChChart
& mrChartData
; /// The chart data object.
212 explicit XclImpChRootData( XclImpChChart
& rChartData
) : mrChartData( rChartData
) {}
215 XclImpChRoot::XclImpChRoot( const XclImpRoot
& rRoot
, XclImpChChart
& rChartData
) :
217 mxChData( new XclImpChRootData( rChartData
) )
221 XclImpChRoot::~XclImpChRoot()
225 XclImpChChart
& XclImpChRoot::GetChartData() const
227 return mxChData
->mrChartData
;
230 const XclChTypeInfo
& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType
) const
232 return mxChData
->mxTypeInfoProv
->GetTypeInfo( eType
);
235 const XclChTypeInfo
& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId
) const
237 return mxChData
->mxTypeInfoProv
->GetTypeInfoFromRecId( nRecId
);
240 const XclChFormatInfo
& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType
) const
242 return mxChData
->mxFmtInfoProv
->GetFormatInfo( eObjType
);
245 Color
XclImpChRoot::GetFontAutoColor() const
247 return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT
);
250 Color
XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx
) const
252 return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx
) );
255 Color
XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx
) const
257 const XclImpPalette
& rPal
= GetPalette();
258 Color aColor
= rPal
.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx
) );
259 sal_uInt8 nTrans
= XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx
);
260 return ScfTools::GetMixedColor( aColor
, rPal
.GetColor( EXC_COLOR_CHWINDOWBACK
), nTrans
);
263 void XclImpChRoot::InitConversion( const Reference
<XChartDocument
>& xChartDoc
, const tools::Rectangle
& rChartRect
) const
265 // create formatting object tables
266 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
268 // lock the model to suppress any internal updates
270 xChartDoc
->lockControllers();
272 SfxObjectShell
* pDocShell
= GetDocShell();
273 Reference
< XDataReceiver
> xDataRec( xChartDoc
, UNO_QUERY
);
274 if( pDocShell
&& xDataRec
.is() )
276 // create and register a data provider
277 Reference
< XDataProvider
> xDataProv(
278 ScfApiHelper::CreateInstance( pDocShell
, SERVICE_CHART2_DATAPROVIDER
), UNO_QUERY
);
280 xDataRec
->attachDataProvider( xDataProv
);
281 // attach the number formatter
282 Reference
< XNumberFormatsSupplier
> xNumFmtSupp( pDocShell
->GetModel(), UNO_QUERY
);
283 if( xNumFmtSupp
.is() )
284 xDataRec
->attachNumberFormatsSupplier( xNumFmtSupp
);
288 void XclImpChRoot::FinishConversion( XclImpDffConverter
& rDffConv
) const
290 rDffConv
.Progress( EXC_CHART_PROGRESS_SIZE
);
292 Reference
< XModel
> xModel
= mxChData
->mxChartDoc
;
294 xModel
->unlockControllers();
295 rDffConv
.Progress( EXC_CHART_PROGRESS_SIZE
);
297 mxChData
->FinishConversion();
300 Reference
< XDataProvider
> XclImpChRoot::GetDataProvider() const
302 return mxChData
->mxChartDoc
->getDataProvider();
305 Reference
< XShape
> XclImpChRoot::GetTitleShape( const XclChTextKey
& rTitleKey
) const
307 return mxChData
->GetTitleShape( rTitleKey
);
310 sal_Int32
XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX
) const
312 return static_cast< sal_Int32
>( mxChData
->mfUnitSizeX
* nPosX
+ mxChData
->mnBorderGapX
+ 0.5 );
315 sal_Int32
XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY
) const
317 return static_cast< sal_Int32
>( mxChData
->mfUnitSizeY
* nPosY
+ mxChData
->mnBorderGapY
+ 0.5 );
320 css::awt::Rectangle
XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle
& rRect
) const
322 return css::awt::Rectangle(
323 CalcHmmFromChartX( rRect
.mnX
),
324 CalcHmmFromChartY( rRect
.mnY
),
325 CalcHmmFromChartX( rRect
.mnWidth
),
326 CalcHmmFromChartY( rRect
.mnHeight
) );
329 double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX
) const
331 const long nWidth
= mxChData
->maChartRect
.GetWidth();
333 throw o3tl::divide_by_zero();
334 return static_cast<double>(nPosX
) / nWidth
;
337 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY
) const
339 const long nHeight
= mxChData
->maChartRect
.GetHeight();
341 throw o3tl::divide_by_zero();
342 return static_cast<double >(nPosY
) / nHeight
;
345 double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX
) const
347 return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX
) );
350 double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY
) const
352 return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY
) );
355 void XclImpChRoot::ConvertLineFormat( ScfPropertySet
& rPropSet
,
356 const XclChLineFormat
& rLineFmt
, XclChPropertyMode ePropMode
) const
358 GetChartPropSetHelper().WriteLineProperties(
359 rPropSet
, *mxChData
->mxLineDashTable
, rLineFmt
, ePropMode
);
362 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet
& rPropSet
,
363 const XclChAreaFormat
& rAreaFmt
, XclChPropertyMode ePropMode
) const
365 GetChartPropSetHelper().WriteAreaProperties( rPropSet
, rAreaFmt
, ePropMode
);
368 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet
& rPropSet
,
369 const XclChEscherFormat
& rEscherFmt
, const XclChPicFormat
* pPicFmt
,
370 sal_uInt32 nDffFillType
, XclChPropertyMode ePropMode
) const
372 GetChartPropSetHelper().WriteEscherProperties( rPropSet
,
373 *mxChData
->mxGradientTable
, *mxChData
->mxBitmapTable
,
374 rEscherFmt
, pPicFmt
, nDffFillType
, ePropMode
);
377 void XclImpChRoot::ConvertFont( ScfPropertySet
& rPropSet
,
378 sal_uInt16 nFontIdx
, const Color
* pFontColor
) const
380 GetFontBuffer().WriteFontProperties( rPropSet
, EXC_FONTPROPSET_CHART
, nFontIdx
, pFontColor
);
383 void XclImpChRoot::ConvertPieRotation( ScfPropertySet
& rPropSet
, sal_uInt16 nAngle
)
385 sal_Int32 nApiRot
= (450 - (nAngle
% 360)) % 360;
386 rPropSet
.SetProperty( EXC_CHPROP_STARTINGANGLE
, nApiRot
);
389 XclImpChGroupBase::~XclImpChGroupBase()
393 void XclImpChGroupBase::ReadRecordGroup( XclImpStream
& rStrm
)
395 // read contents of the header record
396 ReadHeaderRecord( rStrm
);
398 // only read sub records, if the next record is a CHBEGIN
399 if( rStrm
.GetNextRecId() == EXC_ID_CHBEGIN
)
401 // read the CHBEGIN record, may be used for special initial processing
402 rStrm
.StartNextRecord();
403 ReadSubRecord( rStrm
);
405 // read the nested records
407 while( bLoop
&& rStrm
.StartNextRecord() )
409 sal_uInt16 nRecId
= rStrm
.GetRecId();
410 bLoop
= nRecId
!= EXC_ID_CHEND
;
411 // skip unsupported nested blocks
412 if( nRecId
== EXC_ID_CHBEGIN
)
415 ReadSubRecord( rStrm
);
418 /* Returns with current CHEND record or unchanged stream, if no record
419 group present. In every case another call to StartNextRecord() will go
420 to next record of interest. */
423 void XclImpChGroupBase::SkipBlock( XclImpStream
& rStrm
)
425 OSL_ENSURE( rStrm
.GetRecId() == EXC_ID_CHBEGIN
, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
426 // do nothing if current record is not CHBEGIN
427 bool bLoop
= rStrm
.GetRecId() == EXC_ID_CHBEGIN
;
428 while( bLoop
&& rStrm
.StartNextRecord() )
430 sal_uInt16 nRecId
= rStrm
.GetRecId();
431 bLoop
= nRecId
!= EXC_ID_CHEND
;
432 // skip nested record groups
433 if( nRecId
== EXC_ID_CHBEGIN
)
438 // Frame formatting ===========================================================
440 void XclImpChFramePos::ReadChFramePos( XclImpStream
& rStrm
)
442 maData
.mnTLMode
= rStrm
.ReaduInt16();
443 maData
.mnBRMode
= rStrm
.ReaduInt16();
444 /* According to the spec, the upper 16 bits of all members in the
445 rectangle are unused and may contain garbage. */
446 maData
.maRect
.mnX
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
447 maData
.maRect
.mnY
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
448 maData
.maRect
.mnWidth
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
449 maData
.maRect
.mnHeight
= rStrm
.ReadInt16(); rStrm
.Ignore( 2 );
452 void XclImpChLineFormat::ReadChLineFormat( XclImpStream
& rStrm
)
454 rStrm
>> maData
.maColor
;
455 maData
.mnPattern
= rStrm
.ReaduInt16();
456 maData
.mnWeight
= rStrm
.ReadInt16();
457 maData
.mnFlags
= rStrm
.ReaduInt16();
459 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
460 if( rRoot
.GetBiff() == EXC_BIFF8
)
461 // BIFF8: index into palette used instead of RGB data
462 maData
.maColor
= rRoot
.GetPalette().GetColor( rStrm
.ReaduInt16() );
465 void XclImpChLineFormat::Convert( const XclImpChRoot
& rRoot
,
466 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
468 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
471 XclChLineFormat aLineFmt
;
472 aLineFmt
.maColor
= (eObjType
== EXC_CHOBJTYPE_LINEARSERIES
) ?
473 rRoot
.GetSeriesLineAutoColor( nFormatIdx
) :
474 rRoot
.GetPalette().GetColor( rFmtInfo
.mnAutoLineColorIdx
);
475 aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
;
476 aLineFmt
.mnWeight
= rFmtInfo
.mnAutoLineWeight
;
477 rRoot
.ConvertLineFormat( rPropSet
, aLineFmt
, rFmtInfo
.mePropMode
);
481 rRoot
.ConvertLineFormat( rPropSet
, maData
, rFmtInfo
.mePropMode
);
485 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream
& rStrm
)
487 rStrm
>> maData
.maPattColor
>> maData
.maBackColor
;
488 maData
.mnPattern
= rStrm
.ReaduInt16();
489 maData
.mnFlags
= rStrm
.ReaduInt16();
491 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
492 if( rRoot
.GetBiff() == EXC_BIFF8
)
494 // BIFF8: index into palette used instead of RGB data
495 const XclImpPalette
& rPal
= rRoot
.GetPalette();
496 maData
.maPattColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
497 maData
.maBackColor
= rPal
.GetColor( rStrm
.ReaduInt16());
501 void XclImpChAreaFormat::Convert( const XclImpChRoot
& rRoot
,
502 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
504 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
507 XclChAreaFormat aAreaFmt
;
508 aAreaFmt
.maPattColor
= (eObjType
== EXC_CHOBJTYPE_FILLEDSERIES
) ?
509 rRoot
.GetSeriesFillAutoColor( nFormatIdx
) :
510 rRoot
.GetPalette().GetColor( rFmtInfo
.mnAutoPattColorIdx
);
511 aAreaFmt
.mnPattern
= EXC_PATT_SOLID
;
512 rRoot
.ConvertAreaFormat( rPropSet
, aAreaFmt
, rFmtInfo
.mePropMode
);
516 rRoot
.ConvertAreaFormat( rPropSet
, maData
, rFmtInfo
.mePropMode
);
520 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot
& rRoot
) :
521 mnDffFillType( mso_fillSolid
)
523 maData
.mxItemSet
.reset(
524 new SfxItemSet( rRoot
.GetDoc().GetDrawLayer()->GetItemPool() ) );
527 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream
& rStrm
)
529 // read from stream - CHESCHERFORMAT uses own ID for record continuation
530 XclImpDffPropSet
aPropSet( rStrm
.GetRoot() );
531 rStrm
.ResetRecord( true, rStrm
.GetRecId() );
534 aPropSet
.FillToItemSet( *maData
.mxItemSet
);
535 // get fill type from DFF property set
536 mnDffFillType
= aPropSet
.GetPropertyValue( DFF_Prop_fillType
);
539 void XclImpChEscherFormat::ReadSubRecord( XclImpStream
& rStrm
)
541 switch( rStrm
.GetRecId() )
543 case EXC_ID_CHPICFORMAT
:
544 maPicFmt
.mnBmpMode
= rStrm
.ReaduInt16();
546 maPicFmt
.mnFlags
= rStrm
.ReaduInt16();
547 maPicFmt
.mfScale
= rStrm
.ReadDouble();
552 void XclImpChEscherFormat::Convert( const XclImpChRoot
& rRoot
,
553 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, bool bUsePicFmt
) const
555 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
556 rRoot
.ConvertEscherFormat( rPropSet
, maData
, bUsePicFmt
? &maPicFmt
: nullptr, mnDffFillType
, rFmtInfo
.mePropMode
);
559 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo
& rFmtInfo
)
561 if( rFmtInfo
.mbCreateDefFrame
) switch( rFmtInfo
.meDefFrameType
)
563 case EXC_CHFRAMETYPE_AUTO
:
564 mxLineFmt
.reset( new XclImpChLineFormat
);
565 if( rFmtInfo
.mbIsFrame
)
566 mxAreaFmt
.reset( new XclImpChAreaFormat
);
568 case EXC_CHFRAMETYPE_INVISIBLE
:
570 XclChLineFormat aLineFmt
;
571 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, false );
572 aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
573 mxLineFmt
.reset( new XclImpChLineFormat( aLineFmt
) );
574 if( rFmtInfo
.mbIsFrame
)
576 XclChAreaFormat aAreaFmt
;
577 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, false );
578 aAreaFmt
.mnPattern
= EXC_PATT_NONE
;
579 mxAreaFmt
.reset( new XclImpChAreaFormat( aAreaFmt
) );
584 OSL_FAIL( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
588 void XclImpChFrameBase::ReadSubRecord( XclImpStream
& rStrm
)
590 switch( rStrm
.GetRecId() )
592 case EXC_ID_CHLINEFORMAT
:
593 mxLineFmt
.reset( new XclImpChLineFormat
);
594 mxLineFmt
->ReadChLineFormat( rStrm
);
596 case EXC_ID_CHAREAFORMAT
:
597 mxAreaFmt
.reset( new XclImpChAreaFormat
);
598 mxAreaFmt
->ReadChAreaFormat( rStrm
);
600 case EXC_ID_CHESCHERFORMAT
:
601 mxEscherFmt
.reset( new XclImpChEscherFormat( rStrm
.GetRoot() ) );
602 mxEscherFmt
->ReadRecordGroup( rStrm
);
607 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot
& rRoot
,
608 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
) const
611 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
614 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot
& rRoot
,
615 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
617 if( rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
619 // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
621 mxEscherFmt
->Convert( rRoot
, rPropSet
, eObjType
, bUsePicFmt
);
623 mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
627 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot
& rRoot
,
628 ScfPropertySet
& rPropSet
, XclChObjectType eObjType
, sal_uInt16 nFormatIdx
, bool bUsePicFmt
) const
630 ConvertLineBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
);
631 ConvertAreaBase( rRoot
, rPropSet
, eObjType
, nFormatIdx
, bUsePicFmt
);
634 XclImpChFrame::XclImpChFrame( const XclImpChRoot
& rRoot
, XclChObjectType eObjType
) :
635 XclImpChFrameBase( rRoot
.GetFormatInfo( eObjType
) ),
636 XclImpChRoot( rRoot
),
637 meObjType( eObjType
)
641 void XclImpChFrame::ReadHeaderRecord( XclImpStream
& rStrm
)
643 maData
.mnFormat
= rStrm
.ReaduInt16();
644 maData
.mnFlags
= rStrm
.ReaduInt16();
647 void XclImpChFrame::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
649 const XclImpPalette
& rPal
= GetPalette();
651 if( rLineData
.IsVisible() && (!mxLineFmt
|| !mxLineFmt
->HasLine()) )
654 XclChLineFormat aLineFmt
;
655 aLineFmt
.maColor
= rPal
.GetColor( rLineData
.mnColorIdx
);
656 switch( rLineData
.mnStyle
)
658 case EXC_OBJ_LINE_SOLID
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
; break;
659 case EXC_OBJ_LINE_DASH
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASH
; break;
660 case EXC_OBJ_LINE_DOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DOT
; break;
661 case EXC_OBJ_LINE_DASHDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOT
; break;
662 case EXC_OBJ_LINE_DASHDOTDOT
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DASHDOTDOT
; break;
663 case EXC_OBJ_LINE_MEDTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_MEDTRANS
; break;
664 case EXC_OBJ_LINE_DARKTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_DARKTRANS
; break;
665 case EXC_OBJ_LINE_LIGHTTRANS
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_LIGHTTRANS
; break;
666 case EXC_OBJ_LINE_NONE
: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_NONE
; break;
667 default: aLineFmt
.mnPattern
= EXC_CHLINEFORMAT_SOLID
;
669 switch( rLineData
.mnWidth
)
671 case EXC_OBJ_LINE_HAIR
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
; break;
672 case EXC_OBJ_LINE_THIN
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_SINGLE
; break;
673 case EXC_OBJ_LINE_MEDIUM
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_DOUBLE
; break;
674 case EXC_OBJ_LINE_THICK
: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_TRIPLE
; break;
675 default: aLineFmt
.mnWeight
= EXC_CHLINEFORMAT_HAIR
;
677 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, rLineData
.IsAuto() );
678 mxLineFmt
.reset( new XclImpChLineFormat( aLineFmt
) );
681 if( rFillData
.IsFilled() && (!mxAreaFmt
|| !mxAreaFmt
->HasArea()) && !mxEscherFmt
)
684 XclChAreaFormat aAreaFmt
;
685 aAreaFmt
.maPattColor
= rPal
.GetColor( rFillData
.mnPattColorIdx
);
686 aAreaFmt
.maBackColor
= rPal
.GetColor( rFillData
.mnBackColorIdx
);
687 aAreaFmt
.mnPattern
= rFillData
.mnPattern
;
688 ::set_flag( aAreaFmt
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, rFillData
.IsAuto() );
689 mxAreaFmt
.reset( new XclImpChAreaFormat( aAreaFmt
) );
693 void XclImpChFrame::Convert( ScfPropertySet
& rPropSet
, bool bUsePicFmt
) const
695 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
, EXC_CHDATAFORMAT_UNKNOWN
, bUsePicFmt
);
698 // Source links ===============================================================
702 /** Creates a labeled data sequence object, adds link for series title if present. */
703 Reference
< XLabeledDataSequence
> lclCreateLabeledDataSequence(
704 const XclImpChSourceLinkRef
& xValueLink
, const OUString
& rValueRole
,
705 const XclImpChSourceLink
* pTitleLink
= nullptr )
707 // create data sequence for values and title
708 Reference
< XDataSequence
> xValueSeq
;
710 xValueSeq
= xValueLink
->CreateDataSequence( rValueRole
);
711 Reference
< XDataSequence
> xTitleSeq
;
713 xTitleSeq
= pTitleLink
->CreateDataSequence( EXC_CHPROP_ROLE_LABEL
);
715 // create the labeled data sequence, if values or title are present
716 Reference
< XLabeledDataSequence
> xLabeledSeq
;
717 if( xValueSeq
.is() || xTitleSeq
.is() )
718 xLabeledSeq
= LabeledDataSequence::create(comphelper::getProcessComponentContext());
719 if( xLabeledSeq
.is() )
722 xLabeledSeq
->setValues( xValueSeq
);
724 xLabeledSeq
->setLabel( xTitleSeq
);
731 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot
& rRoot
) :
732 XclImpChRoot( rRoot
)
736 XclImpChSourceLink::~XclImpChSourceLink()
740 void XclImpChSourceLink::ReadChSourceLink( XclImpStream
& rStrm
)
742 maData
.mnDestType
= rStrm
.ReaduInt8();
743 maData
.mnLinkType
= rStrm
.ReaduInt8();
744 maData
.mnFlags
= rStrm
.ReaduInt16();
745 maData
.mnNumFmtIdx
= rStrm
.ReaduInt16();
747 mxTokenArray
.reset();
748 if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET
)
751 XclTokenArray aXclTokArr
;
754 // convert BIFF formula tokens to Calc token array
755 if( std::unique_ptr
<ScTokenArray
> pTokens
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aXclTokArr
) )
756 mxTokenArray
= std::move( pTokens
);
759 // try to read a following CHSTRING record
760 if( (rStrm
.GetNextRecId() == EXC_ID_CHSTRING
) && rStrm
.StartNextRecord() )
762 mxString
.reset( new XclImpString
);
764 mxString
->Read( rStrm
, XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
768 void XclImpChSourceLink::SetString( const OUString
& rString
)
771 mxString
.reset( new XclImpString
);
772 mxString
->SetText( rString
);
775 void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec
& rFormats
)
778 mxString
->SetFormats( rFormats
);
781 sal_uInt16
XclImpChSourceLink::GetCellCount() const
783 sal_uInt32 nCellCount
= 0;
786 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
787 for( const FormulaToken
* pToken
= aIter
.First(); pToken
; pToken
= aIter
.Next() )
789 switch( pToken
->GetType() )
791 case ::formula::svSingleRef
:
792 case ::formula::svExternalSingleRef
:
796 case ::formula::svDoubleRef
:
797 case ::formula::svExternalDoubleRef
:
800 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
801 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(ScAddress());
802 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(ScAddress());
803 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
804 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
805 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
806 nCellCount
+= nCols
* nRows
* nTabs
;
813 return limit_cast
< sal_uInt16
>( nCellCount
);
816 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
818 bool bLinkToSource
= ::get_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
819 sal_uInt32 nScNumFmt
= bLinkToSource
? GetNumFmtBuffer().GetScFormat( maData
.mnNumFmtIdx
) : NUMBERFORMAT_ENTRY_NOT_FOUND
;
820 OUString aPropName
= bPercent
? OUString( EXC_CHPROP_PERCENTAGENUMFMT
) : OUString( EXC_CHPROP_NUMBERFORMAT
);
821 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
822 rPropSet
.SetProperty( aPropName
, static_cast< sal_Int32
>( nScNumFmt
) );
824 // restore 'link to source' at data point (series may contain manual number format)
825 rPropSet
.SetAnyProperty( aPropName
, Any() );
828 Reference
< XDataSequence
> XclImpChSourceLink::CreateDataSequence( const OUString
& rRole
) const
830 Reference
< XDataSequence
> xDataSeq
;
831 Reference
< XDataProvider
> xDataProv
= GetDataProvider();
836 ScCompiler
aComp( &GetDoc(), ScAddress(), *mxTokenArray
, GetDoc().GetGrammar() );
837 OUStringBuffer aRangeRep
;
838 aComp
.CreateStringFromTokenArray( aRangeRep
);
841 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aRangeRep
.makeStringAndClear() );
843 ScfPropertySet
aSeqProp( xDataSeq
);
844 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
848 // OSL_FAIL( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
851 else if( rRole
== EXC_CHPROP_ROLE_LABEL
&& mxString
&& !mxString
->GetText().isEmpty() )
855 OUString
aString("\"");
856 xDataSeq
= xDataProv
->createDataSequenceByRangeRepresentation( aString
+ mxString
->GetText() + aString
);
858 ScfPropertySet
aSeqProp( xDataSeq
);
859 aSeqProp
.SetProperty( EXC_CHPROP_ROLE
, rRole
);
861 catch( Exception
& ) { }
867 Sequence
< Reference
< XFormattedString
> > XclImpChSourceLink::CreateStringSequence(
868 const XclImpChRoot
& rRoot
, sal_uInt16 nLeadFontIdx
, const Color
& rLeadFontColor
) const
870 ::std::vector
< Reference
< XFormattedString
> > aStringVec
;
873 for( XclImpStringIterator
aIt( *mxString
); aIt
.Is(); ++aIt
)
875 Reference
< css::chart2::XFormattedString2
> xFmtStr
= css::chart2::FormattedString::create( comphelper::getProcessComponentContext() );
877 xFmtStr
->setString( aIt
.GetPortionText() );
879 // set font formatting and font color
880 ScfPropertySet
aStringProp( xFmtStr
);
881 sal_uInt16 nFontIdx
= aIt
.GetPortionFont();
882 if( (nFontIdx
== EXC_FONT_NOTFOUND
) && (aIt
.GetPortionIndex() == 0) )
883 // leading unformatted portion - use passed font settings
884 rRoot
.ConvertFont( aStringProp
, nLeadFontIdx
, &rLeadFontColor
);
886 rRoot
.ConvertFont( aStringProp
, nFontIdx
);
888 // add string to vector of strings
889 aStringVec
.emplace_back(xFmtStr
);
892 return ScfApiHelper::VectorToSequence( aStringVec
);
895 void XclImpChSourceLink::FillSourceLink( ::std::vector
< ScTokenRef
>& rTokens
) const
901 FormulaTokenArrayPlainIterator
aIter(*mxTokenArray
);
902 for (FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
904 ScTokenRef
pToken(p
->Clone());
905 if (ScRefTokenHelper::isRef(pToken
))
906 // This is a reference token. Store it.
907 ScRefTokenHelper::join(rTokens
, pToken
, ScAddress());
911 // Text =======================================================================
913 XclImpChFontBase::~XclImpChFontBase()
917 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
919 Color aFontColor
= GetFontColor();
920 rRoot
.ConvertFont( rPropSet
, GetFontIndex(), &aFontColor
);
923 void XclImpChFontBase::ConvertRotationBase( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
925 XclChPropSetHelper::WriteRotationProperties( rPropSet
, GetRotation(), bSupportsStacked
);
928 XclImpChFont::XclImpChFont() :
929 mnFontIdx( EXC_FONT_NOTFOUND
)
933 void XclImpChFont::ReadChFont( XclImpStream
& rStrm
)
935 mnFontIdx
= rStrm
.ReaduInt16();
938 XclImpChText::XclImpChText( const XclImpChRoot
& rRoot
) :
939 XclImpChRoot( rRoot
)
943 void XclImpChText::ReadHeaderRecord( XclImpStream
& rStrm
)
945 maData
.mnHAlign
= rStrm
.ReaduInt8();
946 maData
.mnVAlign
= rStrm
.ReaduInt8();
947 maData
.mnBackMode
= rStrm
.ReaduInt16();
948 rStrm
>> maData
.maTextColor
950 maData
.mnFlags
= rStrm
.ReaduInt16();
952 if( GetBiff() == EXC_BIFF8
)
954 // BIFF8: index into palette used instead of RGB data
955 maData
.maTextColor
= GetPalette().GetColor( rStrm
.ReaduInt16() );
956 // placement and rotation
957 maData
.mnFlags2
= rStrm
.ReaduInt16();
958 maData
.mnRotation
= rStrm
.ReaduInt16();
962 // BIFF2-BIFF7: get rotation from text orientation
963 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 8, 3 );
964 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
968 void XclImpChText::ReadSubRecord( XclImpStream
& rStrm
)
970 switch( rStrm
.GetRecId() )
972 case EXC_ID_CHFRAMEPOS
:
973 mxFramePos
.reset( new XclImpChFramePos
);
974 mxFramePos
->ReadChFramePos( rStrm
);
977 mxFont
.reset( new XclImpChFont
);
978 mxFont
->ReadChFont( rStrm
);
980 case EXC_ID_CHFORMATRUNS
:
981 if( GetBiff() == EXC_BIFF8
)
982 XclImpString::ReadFormats( rStrm
, maFormats
);
984 case EXC_ID_CHSOURCELINK
:
985 mxSrcLink
.reset( new XclImpChSourceLink( GetChRoot() ) );
986 mxSrcLink
->ReadChSourceLink( rStrm
);
989 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT
) );
990 mxFrame
->ReadRecordGroup( rStrm
);
992 case EXC_ID_CHOBJECTLINK
:
993 maObjLink
.mnTarget
= rStrm
.ReaduInt16();
994 maObjLink
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
995 maObjLink
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
997 case EXC_ID_CHFRLABELPROPS
:
998 ReadChFrLabelProps( rStrm
);
1001 if( mxSrcLink
&& !maFormats
.empty() )
1002 mxSrcLink
->SetTextFormats( maFormats
);
1007 sal_uInt16
XclImpChText::GetFontIndex() const
1009 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
1012 Color
XclImpChText::GetFontColor() const
1014 return ::get_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextColor
;
1017 sal_uInt16
XclImpChText::GetRotation() const
1019 return maData
.mnRotation
;
1022 void XclImpChText::SetString( const OUString
& rString
)
1025 mxSrcLink
.reset( new XclImpChSourceLink( GetChRoot() ) );
1026 mxSrcLink
->SetString( rString
);
1029 void XclImpChText::UpdateText( const XclImpChText
* pParentText
)
1033 // update missing members
1035 mxFrame
= pParentText
->mxFrame
;
1038 mxFont
= pParentText
->mxFont
;
1039 // text color is taken from CHTEXT record, not from font in CHFONT
1040 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, ::get_flag( pParentText
->maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
) );
1041 maData
.maTextColor
= pParentText
->maData
.maTextColor
;
1046 void XclImpChText::UpdateDataLabel( bool bCateg
, bool bValue
, bool bPercent
)
1048 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bCateg
);
1049 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bValue
);
1050 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bPercent
);
1051 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bCateg
&& bPercent
);
1052 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bCateg
&& !bValue
&& !bPercent
);
1055 void XclImpChText::ConvertFont( ScfPropertySet
& rPropSet
) const
1057 ConvertFontBase( GetChRoot(), rPropSet
);
1060 void XclImpChText::ConvertRotation( ScfPropertySet
& rPropSet
, bool bSupportsStacked
) const
1062 ConvertRotationBase( rPropSet
, bSupportsStacked
);
1065 void XclImpChText::ConvertFrame( ScfPropertySet
& rPropSet
) const
1068 mxFrame
->Convert( rPropSet
);
1071 void XclImpChText::ConvertNumFmt( ScfPropertySet
& rPropSet
, bool bPercent
) const
1074 mxSrcLink
->ConvertNumFmt( rPropSet
, bPercent
);
1077 void XclImpChText::ConvertDataLabel( ScfPropertySet
& rPropSet
, const XclChTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1079 // existing CHFRLABELPROPS record wins over flags from CHTEXT
1080 sal_uInt16 nShowFlags
= mxLabelProps
? mxLabelProps
->mnFlags
: maData
.mnFlags
;
1081 sal_uInt16 SHOWANYCATEG
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWCATEG
: (EXC_CHTEXT_SHOWCATEGPERC
| EXC_CHTEXT_SHOWCATEG
);
1082 sal_uInt16 SHOWANYVALUE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWVALUE
: EXC_CHTEXT_SHOWVALUE
;
1083 sal_uInt16 SHOWANYPERCENT
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWPERCENT
: (EXC_CHTEXT_SHOWPERCENT
| EXC_CHTEXT_SHOWCATEGPERC
);
1084 sal_uInt16 SHOWANYBUBBLE
= mxLabelProps
? EXC_CHFRLABELPROPS_SHOWBUBBLE
: EXC_CHTEXT_SHOWBUBBLE
;
1086 // get raw flags for label values
1087 bool bShowNone
= IsDeleted();
1088 bool bShowCateg
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYCATEG
);
1089 bool bShowPercent
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYPERCENT
);
1090 bool bShowValue
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYVALUE
);
1091 bool bShowBubble
= !bShowNone
&& ::get_flag( nShowFlags
, SHOWANYBUBBLE
);
1093 // adjust to Chart2 behaviour
1094 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
1095 bShowValue
= bShowBubble
; // Chart2 bubble charts show bubble size if 'ShowValue' is set
1098 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
;
1099 bool bShowSymbol
= bShowAny
&& ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
);
1101 // create API struct for label values, set API label separator
1102 cssc2::DataPointLabel
aPointLabel( bShowValue
, bShowPercent
, bShowCateg
, bShowSymbol
);
1103 rPropSet
.SetProperty( EXC_CHPROP_LABEL
, aPointLabel
);
1104 OUString aSep
= mxLabelProps
? mxLabelProps
->maSeparator
: OUString('\n');
1105 if( aSep
.isEmpty() )
1107 rPropSet
.SetStringProperty( EXC_CHPROP_LABELSEPARATOR
, aSep
);
1109 // text properties of attached label
1112 ConvertFont( rPropSet
);
1113 ConvertRotation( rPropSet
, false );
1115 using namespace cssc::DataLabelPlacement
;
1116 sal_Int32 nPlacement
= rTypeInfo
.mnDefaultLabelPos
;
1117 switch( ::extract_value
< sal_uInt16
>( maData
.mnFlags2
, 0, 4 ) )
1119 case EXC_CHTEXT_POS_DEFAULT
: nPlacement
= rTypeInfo
.mnDefaultLabelPos
; break;
1120 case EXC_CHTEXT_POS_OUTSIDE
: nPlacement
= OUTSIDE
; break;
1121 case EXC_CHTEXT_POS_INSIDE
: nPlacement
= INSIDE
; break;
1122 case EXC_CHTEXT_POS_CENTER
: nPlacement
= CENTER
; break;
1123 case EXC_CHTEXT_POS_AXIS
: nPlacement
= NEAR_ORIGIN
; break;
1124 case EXC_CHTEXT_POS_ABOVE
: nPlacement
= TOP
; break;
1125 case EXC_CHTEXT_POS_BELOW
: nPlacement
= BOTTOM
; break;
1126 case EXC_CHTEXT_POS_LEFT
: nPlacement
= LEFT
; break;
1127 case EXC_CHTEXT_POS_RIGHT
: nPlacement
= RIGHT
; break;
1128 case EXC_CHTEXT_POS_AUTO
: nPlacement
= AVOID_OVERLAP
; break;
1130 sal_Int32 nGlobalPlacement
= 0;
1131 if ( ( nPlacement
== rTypeInfo
.mnDefaultLabelPos
) && pGlobalPropSet
&&
1132 pGlobalPropSet
->GetProperty( nGlobalPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1133 nPlacement
= nGlobalPlacement
;
1135 rPropSet
.SetProperty( EXC_CHPROP_LABELPLACEMENT
, nPlacement
);
1136 // label number format (percentage format wins over value format)
1137 if( bShowPercent
|| bShowValue
)
1138 ConvertNumFmt( rPropSet
, bShowPercent
);
1142 Reference
< XTitle
> XclImpChText::CreateTitle() const
1144 Reference
< XTitle
> xTitle
;
1145 if( mxSrcLink
&& mxSrcLink
->HasString() )
1147 // create the formatted strings
1148 Sequence
< Reference
< XFormattedString
> > aStringSeq(
1149 mxSrcLink
->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1150 if( aStringSeq
.hasElements() )
1152 // create the title object
1153 xTitle
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE
), UNO_QUERY
);
1156 // set the formatted strings
1157 xTitle
->setText( aStringSeq
);
1158 // more title formatting properties
1159 ScfPropertySet
aTitleProp( xTitle
);
1160 ConvertFrame( aTitleProp
);
1161 ConvertRotation( aTitleProp
, true );
1168 void XclImpChText::ConvertTitlePosition( const XclChTextKey
& rTitleKey
) const
1170 if( !mxFramePos
) return;
1172 const XclChFramePos
& rPosData
= mxFramePos
->GetFramePosData();
1173 OSL_ENSURE( (rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rPosData
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
),
1174 "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1176 /* Check if title is moved manually. To get the actual position of the
1177 title, we do some kind of hack and use the values from the CHTEXT
1178 record, effectively ignoring the contents of the CHFRAMEPOS record
1179 which contains the position relative to the default title position
1180 (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1181 Especially when it comes to axis titles, things would become very
1182 complicated here, because the relative title position is stored in a
1183 measurement unit that is dependent on the size of the inner plot area,
1184 the interpretation of the X and Y coordinate is dependent on the
1185 direction of the axis, and in 3D charts, and the title default
1186 positions are dependent on the 3D view settings (rotation, elevation,
1187 and perspective). Thus, it is easier to assume that the creator has
1188 written out the correct absolute position and size of the title in the
1189 CHTEXT record. This is assured by checking that the shape size stored
1190 in the CHTEXT record is non-zero. */
1191 if( (rPosData
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) &&
1192 ((rPosData
.maRect
.mnX
!= 0) || (rPosData
.maRect
.mnY
!= 0)) &&
1193 (maData
.maRect
.mnWidth
> 0) && (maData
.maRect
.mnHeight
> 0) ) try
1195 Reference
< XShape
> xTitleShape( GetTitleShape( rTitleKey
), UNO_SET_THROW
);
1196 // the call to XShape.getSize() may recalc the chart view
1197 css::awt::Size aTitleSize
= xTitleShape
->getSize();
1198 // rotated titles need special handling...
1199 sal_Int32 nScRot
= XclTools::GetScRotation( GetRotation(), 0 );
1200 double fRad
= nScRot
* F_PI18000
;
1201 double fSin
= fabs( sin( fRad
) );
1202 // calculate the title position from the values in the CHTEXT record
1203 css::awt::Point
aTitlePos(
1204 CalcHmmFromChartX( maData
.maRect
.mnX
),
1205 CalcHmmFromChartY( maData
.maRect
.mnY
) );
1206 // add part of height to X direction, if title is rotated down (clockwise)
1207 if( nScRot
> 18000 )
1208 aTitlePos
.X
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Height
+ 0.5 );
1209 // add part of width to Y direction, if title is rotated up (counterclockwise)
1210 else if( nScRot
> 0 )
1211 aTitlePos
.Y
+= static_cast< sal_Int32
>( fSin
* aTitleSize
.Width
+ 0.5 );
1212 // set the resulting position at the title shape
1213 xTitleShape
->setPosition( aTitlePos
);
1220 void XclImpChText::ReadChFrLabelProps( XclImpStream
& rStrm
)
1222 if( GetBiff() == EXC_BIFF8
)
1224 mxLabelProps
.reset( new XclChFrLabelProps
);
1227 mxLabelProps
->mnFlags
= rStrm
.ReaduInt16();
1228 nSepLen
= rStrm
.ReaduInt16();
1230 mxLabelProps
->maSeparator
= rStrm
.ReadUniString( nSepLen
);
1236 void lclUpdateText( XclImpChTextRef
& rxText
, const XclImpChText
* xDefText
)
1239 rxText
->UpdateText( xDefText
);
1242 XclImpChTextRef
xNew(new XclImpChText(*xDefText
));
1247 void lclFinalizeTitle( XclImpChTextRef
& rxTitle
, const XclImpChText
* pDefText
, const OUString
& rAutoTitle
)
1249 /* Do not update a title, if it is not visible (if rxTitle is null).
1250 Existing reference indicates enabled title. */
1253 if( !rxTitle
->HasString() )
1254 rxTitle
->SetString( rAutoTitle
);
1255 if( rxTitle
->HasString() )
1256 rxTitle
->UpdateText(pDefText
);
1264 // Data series ================================================================
1266 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream
& rStrm
)
1268 rStrm
>> maData
.maLineColor
>> maData
.maFillColor
;
1269 maData
.mnMarkerType
= rStrm
.ReaduInt16();
1270 maData
.mnFlags
= rStrm
.ReaduInt16();
1272 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
1273 if( rRoot
.GetBiff() == EXC_BIFF8
)
1275 // BIFF8: index into palette used instead of RGB data
1276 const XclImpPalette
& rPal
= rRoot
.GetPalette();
1277 maData
.maLineColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1278 maData
.maFillColor
= rPal
.GetColor( rStrm
.ReaduInt16() );
1280 maData
.mnMarkerSize
= rStrm
.ReaduInt32();
1284 void XclImpChMarkerFormat::Convert( const XclImpChRoot
& rRoot
,
1285 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
, sal_Int16 nLineWeight
) const
1289 XclChMarkerFormat aMarkerFmt
;
1290 // line and fill color of the symbol are equal to series line color
1291 //TODO: Excel sets no fill color for specific symbols (e.g. cross)
1292 aMarkerFmt
.maLineColor
= aMarkerFmt
.maFillColor
= rRoot
.GetSeriesLineAutoColor( nFormatIdx
);
1293 switch( nLineWeight
)
1295 case EXC_CHLINEFORMAT_HAIR
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_HAIRSIZE
; break;
1296 case EXC_CHLINEFORMAT_SINGLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
; break;
1297 case EXC_CHLINEFORMAT_DOUBLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
; break;
1298 case EXC_CHLINEFORMAT_TRIPLE
: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_TRIPLESIZE
; break;
1299 default: aMarkerFmt
.mnMarkerSize
= EXC_CHMARKERFORMAT_SINGLESIZE
;
1301 aMarkerFmt
.mnMarkerType
= XclChartHelper::GetAutoMarkerType( nFormatIdx
);
1302 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, aMarkerFmt
);
1306 XclChPropSetHelper::WriteMarkerProperties( rPropSet
, maData
);
1310 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot
& rRoot
,
1311 ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1313 Color aLineColor
= IsAuto() ? rRoot
.GetSeriesLineAutoColor( nFormatIdx
) : maData
.maFillColor
;
1314 rPropSet
.SetColorProperty( EXC_CHPROP_COLOR
, aLineColor
);
1317 XclImpChPieFormat::XclImpChPieFormat() :
1322 void XclImpChPieFormat::ReadChPieFormat( XclImpStream
& rStrm
)
1324 mnPieDist
= rStrm
.ReaduInt16();
1327 void XclImpChPieFormat::Convert( ScfPropertySet
& rPropSet
) const
1329 double fApiDist
= ::std::min
< double >( mnPieDist
/ 100.0, 1.0 );
1330 rPropSet
.SetProperty( EXC_CHPROP_OFFSET
, fApiDist
);
1333 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1338 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream
& rStrm
)
1340 mnFlags
= rStrm
.ReaduInt16();
1343 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream
& rStrm
)
1345 maData
.mnBase
= rStrm
.ReaduInt8();
1346 maData
.mnTop
= rStrm
.ReaduInt8();
1349 void XclImpCh3dDataFormat::Convert( ScfPropertySet
& rPropSet
) const
1351 using namespace ::com::sun::star::chart2::DataPointGeometry3D
;
1352 sal_Int32 nApiType
= (maData
.mnBase
== EXC_CH3DDATAFORMAT_RECT
) ?
1353 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CUBOID
: PYRAMID
) :
1354 ((maData
.mnTop
== EXC_CH3DDATAFORMAT_STRAIGHT
) ? CYLINDER
: CONE
);
1355 rPropSet
.SetProperty( EXC_CHPROP_GEOMETRY3D
, nApiType
);
1358 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot
& rRoot
) :
1359 XclImpChRoot( rRoot
),
1364 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream
& rStrm
)
1366 mnFlags
= rStrm
.ReaduInt16();
1369 XclImpChTextRef
XclImpChAttachedLabel::CreateDataLabel( const XclImpChText
* pParent
) const
1371 const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE
= EXC_CHATTLABEL_SHOWVALUE
;
1372 const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT
= EXC_CHATTLABEL_SHOWPERCENT
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1373 const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG
= EXC_CHATTLABEL_SHOWCATEG
| EXC_CHATTLABEL_SHOWCATEGPERC
;
1375 XclImpChTextRef
xLabel( pParent
? new XclImpChText( *pParent
) : new XclImpChText( GetChRoot() ) );
1376 xLabel
->UpdateDataLabel(
1377 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYCATEG
),
1378 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYVALUE
),
1379 ::get_flag( mnFlags
, EXC_CHATTLABEL_SHOWANYPERCENT
) );
1383 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot
& rRoot
) :
1384 XclImpChRoot( rRoot
)
1388 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream
& rStrm
)
1390 maData
.maPointPos
.mnPointIdx
= rStrm
.ReaduInt16();
1391 maData
.maPointPos
.mnSeriesIdx
= rStrm
.ReaduInt16();
1392 maData
.mnFormatIdx
= rStrm
.ReaduInt16();
1393 maData
.mnFlags
= rStrm
.ReaduInt16();
1396 void XclImpChDataFormat::ReadSubRecord( XclImpStream
& rStrm
)
1398 switch( rStrm
.GetRecId() )
1400 case EXC_ID_CHMARKERFORMAT
:
1401 mxMarkerFmt
.reset( new XclImpChMarkerFormat
);
1402 mxMarkerFmt
->ReadChMarkerFormat( rStrm
);
1404 case EXC_ID_CHPIEFORMAT
:
1405 mxPieFmt
.reset( new XclImpChPieFormat
);
1406 mxPieFmt
->ReadChPieFormat( rStrm
);
1408 case EXC_ID_CHSERIESFORMAT
:
1409 mxSeriesFmt
.reset( new XclImpChSeriesFormat
);
1410 mxSeriesFmt
->ReadChSeriesFormat( rStrm
);
1412 case EXC_ID_CH3DDATAFORMAT
:
1413 mx3dDataFmt
.reset( new XclImpCh3dDataFormat
);
1414 mx3dDataFmt
->ReadCh3dDataFormat( rStrm
);
1416 case EXC_ID_CHATTACHEDLABEL
:
1417 mxAttLabel
.reset( new XclImpChAttachedLabel( GetChRoot() ) );
1418 mxAttLabel
->ReadChAttachedLabel( rStrm
);
1421 XclImpChFrameBase::ReadSubRecord( rStrm
);
1425 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
)
1427 maData
.maPointPos
= rPointPos
;
1428 maData
.mnFormatIdx
= nFormatIdx
;
1431 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo
& rTypeInfo
)
1433 // remove formats not used for the current chart type
1434 RemoveUnusedFormats( rTypeInfo
);
1437 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pGroupFmt
)
1439 // update missing formats from passed chart type group format
1443 mxLineFmt
= pGroupFmt
->mxLineFmt
;
1444 if( !mxAreaFmt
&& !mxEscherFmt
)
1446 mxAreaFmt
= pGroupFmt
->mxAreaFmt
;
1447 mxEscherFmt
= pGroupFmt
->mxEscherFmt
;
1450 mxMarkerFmt
= pGroupFmt
->mxMarkerFmt
;
1452 mxPieFmt
= pGroupFmt
->mxPieFmt
;
1454 mxSeriesFmt
= pGroupFmt
->mxSeriesFmt
;
1456 mx3dDataFmt
= pGroupFmt
->mx3dDataFmt
;
1458 mxAttLabel
= pGroupFmt
->mxAttLabel
;
1461 /* Create missing but required formats. Existing line, area, and marker
1462 format objects are needed to create automatic series formatting. */
1464 mxLineFmt
.reset( new XclImpChLineFormat
);
1465 if( !mxAreaFmt
&& !mxEscherFmt
)
1466 mxAreaFmt
.reset( new XclImpChAreaFormat
);
1468 mxMarkerFmt
.reset( new XclImpChMarkerFormat
);
1470 // remove formats not used for the current chart type
1471 RemoveUnusedFormats( rTypeInfo
);
1472 // update data label
1473 UpdateDataLabel( pGroupFmt
);
1476 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo
& rTypeInfo
, const XclImpChDataFormat
* pSeriesFmt
)
1478 // remove formats if they are automatic in this and in the passed series format
1481 if( IsAutoLine() && pSeriesFmt
->IsAutoLine() )
1483 if( IsAutoArea() && pSeriesFmt
->IsAutoArea() )
1485 if( IsAutoMarker() && pSeriesFmt
->IsAutoMarker() )
1486 mxMarkerFmt
.reset();
1487 mxSeriesFmt
.reset();
1490 // Excel ignores 3D bar format for single data points
1491 mx3dDataFmt
.reset();
1492 // remove point line formats for linear chart types, TODO: implement in OOChart
1493 if( !rTypeInfo
.IsSeriesFrameFormat() )
1496 // remove formats not used for the current chart type
1497 RemoveUnusedFormats( rTypeInfo
);
1498 // update data label
1499 UpdateDataLabel( pSeriesFmt
);
1502 void XclImpChDataFormat::UpdateTrendLineFormat()
1505 mxLineFmt
.reset( new XclImpChLineFormat
);
1507 mxEscherFmt
.reset();
1508 mxMarkerFmt
.reset();
1510 mxSeriesFmt
.reset();
1511 mx3dDataFmt
.reset();
1513 // update data label
1514 UpdateDataLabel( nullptr );
1517 void XclImpChDataFormat::Convert( ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, const ScfPropertySet
* pGlobalPropSet
) const
1519 /* Line and area format.
1520 #i71810# If the data points are filled with bitmaps, textures, or
1521 patterns, then only bar charts will use the CHPICFORMAT record to
1522 determine stacking/stretching mode. All other chart types ignore this
1523 record and always use the property 'fill-type' from the DFF property
1524 set (stretched for bitmaps, and stacked for textures and patterns). */
1525 bool bUsePicFmt
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
;
1526 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType(), maData
.mnFormatIdx
, bUsePicFmt
);
1528 // #i83151# only hair lines in 3D charts with filled data points
1529 if( rTypeInfo
.mb3dChart
&& rTypeInfo
.IsSeriesFrameFormat() && mxLineFmt
&& mxLineFmt
->HasLine() )
1530 rPropSet
.SetProperty
< sal_Int32
>( "BorderWidth", 0 );
1534 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
, GetLineWeight() );
1536 mxPieFmt
->Convert( rPropSet
);
1538 mx3dDataFmt
->Convert( rPropSet
);
1540 mxLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, pGlobalPropSet
);
1543 rPropSet
.SetProperty
< sal_Int16
>( EXC_CHPROP_PERCENTDIAGONAL
, 0 );
1545 /* Special case: set marker color as line color, if series line is not
1546 visible. This makes the color visible in the marker area.
1547 TODO: remove this if OOChart supports own colors in markers. */
1548 if( !rTypeInfo
.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt
)
1549 mxMarkerFmt
->ConvertColor( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1552 void XclImpChDataFormat::ConvertLine( ScfPropertySet
& rPropSet
, XclChObjectType eObjType
) const
1554 ConvertLineBase( GetChRoot(), rPropSet
, eObjType
);
1557 void XclImpChDataFormat::ConvertArea( ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
) const
1559 ConvertAreaBase( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_FILLEDSERIES
, nFormatIdx
);
1562 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo
& rTypeInfo
)
1564 // data point marker only in linear 2D charts
1565 if( rTypeInfo
.IsSeriesFrameFormat() )
1566 mxMarkerFmt
.reset();
1567 // pie format only in pie/donut charts
1568 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
1570 // 3D format only in 3D bar charts
1571 if( !rTypeInfo
.mb3dChart
|| (rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
1572 mx3dDataFmt
.reset();
1575 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat
* pParentFmt
)
1577 /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1578 records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1579 group, the contents of the CHATTACHEDLABEL record are used. In this
1580 case a new CHTEXT group is created and filled with the settings from
1581 the CHATTACHEDLABEL record. */
1582 const XclImpChText
* pDefText
= nullptr;
1584 pDefText
= pParentFmt
->GetDataLabel();
1586 pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL
);
1588 mxLabel
->UpdateText(pDefText
);
1589 else if (mxAttLabel
)
1590 mxLabel
= mxAttLabel
->CreateDataLabel( pDefText
);
1593 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot
& rRoot
) :
1594 XclImpChRoot( rRoot
)
1598 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream
& rStrm
)
1600 maData
.mnLineType
= rStrm
.ReaduInt8();
1601 maData
.mnOrder
= rStrm
.ReaduInt8();
1602 maData
.mfIntercept
= rStrm
.ReadDouble();
1603 maData
.mnShowEquation
= rStrm
.ReaduInt8();
1604 maData
.mnShowRSquared
= rStrm
.ReaduInt8();
1605 maData
.mfForecastFor
= rStrm
.ReadDouble();
1606 maData
.mfForecastBack
= rStrm
.ReadDouble();
1609 Reference
< XRegressionCurve
> XclImpChSerTrendLine::CreateRegressionCurve() const
1612 Reference
< XRegressionCurve
> xRegCurve
;
1613 switch( maData
.mnLineType
)
1615 case EXC_CHSERTREND_POLYNOMIAL
:
1616 if( maData
.mnOrder
== 1 )
1618 xRegCurve
= LinearRegressionCurve::create( comphelper::getProcessComponentContext() );
1620 xRegCurve
= PolynomialRegressionCurve::create( comphelper::getProcessComponentContext() );
1623 case EXC_CHSERTREND_EXPONENTIAL
:
1624 xRegCurve
= ExponentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1626 case EXC_CHSERTREND_LOGARITHMIC
:
1627 xRegCurve
= LogarithmicRegressionCurve::create( comphelper::getProcessComponentContext() );
1629 case EXC_CHSERTREND_POWER
:
1630 xRegCurve
= PotentialRegressionCurve::create( comphelper::getProcessComponentContext() );
1632 case EXC_CHSERTREND_MOVING_AVG
:
1633 xRegCurve
= MovingAverageRegressionCurve::create( comphelper::getProcessComponentContext() );
1637 // trend line formatting
1638 if( xRegCurve
.is() && mxDataFmt
)
1640 ScfPropertySet
aPropSet( xRegCurve
);
1641 mxDataFmt
->ConvertLine( aPropSet
, EXC_CHOBJTYPE_TRENDLINE
);
1643 aPropSet
.SetProperty(EXC_CHPROP_CURVENAME
, maTrendLineName
);
1644 aPropSet
.SetProperty(EXC_CHPROP_POLYNOMIAL_DEGREE
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1645 aPropSet
.SetProperty(EXC_CHPROP_MOVING_AVERAGE_PERIOD
, static_cast<sal_Int32
> (maData
.mnOrder
) );
1646 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_FORWARD
, maData
.mfForecastFor
);
1647 aPropSet
.SetProperty(EXC_CHPROP_EXTRAPOLATE_BACKWARD
, maData
.mfForecastBack
);
1649 bool bForceIntercept
= rtl::math::isFinite(maData
.mfIntercept
);
1650 aPropSet
.SetProperty(EXC_CHPROP_FORCE_INTERCEPT
, bForceIntercept
);
1651 if (bForceIntercept
)
1653 aPropSet
.SetProperty(EXC_CHPROP_INTERCEPT_VALUE
, maData
.mfIntercept
);
1656 // #i83100# show equation and correlation coefficient
1657 ScfPropertySet
aLabelProp( xRegCurve
->getEquationProperties() );
1658 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWEQUATION
, maData
.mnShowEquation
!= 0 );
1659 aLabelProp
.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION
, maData
.mnShowRSquared
!= 0 );
1661 // #i83100# formatting of the equation text box
1662 if (const XclImpChText
* pLabel
= mxDataFmt
->GetDataLabel())
1664 pLabel
->ConvertFont( aLabelProp
);
1665 pLabel
->ConvertFrame( aLabelProp
);
1666 pLabel
->ConvertNumFmt( aLabelProp
, false );
1673 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot
& rRoot
) :
1674 XclImpChRoot( rRoot
)
1678 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream
& rStrm
)
1680 maData
.mnBarType
= rStrm
.ReaduInt8();
1681 maData
.mnSourceType
= rStrm
.ReaduInt8();
1682 maData
.mnLineEnd
= rStrm
.ReaduInt8();
1684 maData
.mfValue
= rStrm
.ReadDouble();
1685 maData
.mnValueCount
= rStrm
.ReaduInt16();
1688 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef
const & xValueLink
, XclImpChDataFormatRef
const & xDataFmt
)
1690 mxValueLink
= xValueLink
;
1691 mxDataFmt
= xDataFmt
;
1694 Reference
< XLabeledDataSequence
> XclImpChSerErrorBar::CreateValueSequence() const
1696 return lclCreateLabeledDataSequence( mxValueLink
, XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
) );
1699 Reference
< XPropertySet
> XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar
* pPosBar
, const XclImpChSerErrorBar
* pNegBar
)
1701 Reference
< XPropertySet
> xErrorBar
;
1703 if( const XclImpChSerErrorBar
* pPrimaryBar
= pPosBar
? pPosBar
: pNegBar
)
1705 xErrorBar
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR
), UNO_QUERY
);
1706 ScfPropertySet
aBarProp( xErrorBar
);
1708 // plus/minus bars visible?
1709 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR
, pPosBar
!= nullptr );
1710 aBarProp
.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR
, pNegBar
!= nullptr );
1712 // type of displayed error
1713 switch( pPrimaryBar
->maData
.mnSourceType
)
1715 case EXC_CHSERERR_PERCENT
:
1716 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::RELATIVE
);
1717 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1718 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1720 case EXC_CHSERERR_FIXED
:
1721 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::ABSOLUTE
);
1722 aBarProp
.SetProperty( EXC_CHPROP_POSITIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1723 aBarProp
.SetProperty( EXC_CHPROP_NEGATIVEERROR
, pPrimaryBar
->maData
.mfValue
);
1725 case EXC_CHSERERR_STDDEV
:
1726 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_DEVIATION
);
1727 aBarProp
.SetProperty( EXC_CHPROP_WEIGHT
, pPrimaryBar
->maData
.mfValue
);
1729 case EXC_CHSERERR_STDERR
:
1730 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::STANDARD_ERROR
);
1732 case EXC_CHSERERR_CUSTOM
:
1734 aBarProp
.SetProperty( EXC_CHPROP_ERRORBARSTYLE
, cssc::ErrorBarStyle::FROM_DATA
);
1735 // attach data sequences to error bar
1736 Reference
< XDataSink
> xDataSink( xErrorBar
, UNO_QUERY
);
1737 if( xDataSink
.is() )
1739 // create vector of all value sequences
1740 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
1741 // add positive values
1744 Reference
< XLabeledDataSequence
> xValueSeq
= pPosBar
->CreateValueSequence();
1745 if( xValueSeq
.is() )
1746 aLabeledSeqVec
.push_back( xValueSeq
);
1748 // add negative values
1751 Reference
< XLabeledDataSequence
> xValueSeq
= pNegBar
->CreateValueSequence();
1752 if( xValueSeq
.is() )
1753 aLabeledSeqVec
.push_back( xValueSeq
);
1755 // attach labeled data sequences to series
1756 if( aLabeledSeqVec
.empty() )
1759 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
1767 // error bar formatting
1768 if( pPrimaryBar
->mxDataFmt
&& xErrorBar
.is() )
1769 pPrimaryBar
->mxDataFmt
->ConvertLine( aBarProp
, EXC_CHOBJTYPE_ERRORBAR
);
1775 XclImpChSeries::XclImpChSeries( const XclImpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1776 XclImpChRoot( rRoot
),
1777 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1778 mnSeriesIdx( nSeriesIdx
),
1779 mnParentIdx( EXC_CHSERIES_INVALID
),
1780 mbLabelDeleted( false )
1784 void XclImpChSeries::ReadHeaderRecord( XclImpStream
& rStrm
)
1786 maData
.mnCategType
= rStrm
.ReaduInt16();
1787 maData
.mnValueType
= rStrm
.ReaduInt16();
1788 maData
.mnCategCount
= rStrm
.ReaduInt16();
1789 maData
.mnValueCount
= rStrm
.ReaduInt16();
1790 if( GetBiff() == EXC_BIFF8
)
1792 maData
.mnBubbleType
= rStrm
.ReaduInt16();
1793 maData
.mnBubbleCount
= rStrm
.ReaduInt16();
1797 void XclImpChSeries::ReadSubRecord( XclImpStream
& rStrm
)
1799 switch( rStrm
.GetRecId() )
1801 case EXC_ID_CHSOURCELINK
:
1802 ReadChSourceLink( rStrm
);
1804 case EXC_ID_CHDATAFORMAT
:
1805 ReadChDataFormat( rStrm
);
1807 case EXC_ID_CHSERGROUP
:
1808 mnGroupIdx
= rStrm
.ReaduInt16();
1810 case EXC_ID_CHSERPARENT
:
1811 ReadChSerParent( rStrm
);
1813 case EXC_ID_CHSERTRENDLINE
:
1814 ReadChSerTrendLine( rStrm
);
1816 case EXC_ID_CHSERERRORBAR
:
1817 ReadChSerErrorBar( rStrm
);
1819 case EXC_ID_CHLEGENDEXCEPTION
:
1820 ReadChLegendException( rStrm
);
1825 void XclImpChSeries::SetDataFormat( const XclImpChDataFormatRef
& xDataFmt
)
1830 sal_uInt16 nPointIdx
= xDataFmt
->GetPointPos().mnPointIdx
;
1831 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1834 // Don't overwrite the existing format.
1837 mxSeriesFmt
= xDataFmt
;
1838 if (HasParentSeries())
1841 XclImpChTypeGroupRef pTypeGroup
= GetChartData().GetTypeGroup(mnGroupIdx
);
1843 pTypeGroup
->SetUsedFormatIndex(xDataFmt
->GetFormatIdx());
1848 if (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1849 // Above the max point count. Bail out.
1852 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1853 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1855 // No object exists at this point index position. Insert it.
1856 itr
= maPointFmts
.insert(itr
, XclImpChDataFormatMap::value_type(nPointIdx
, xDataFmt
));
1860 void XclImpChSeries::SetDataLabel( const XclImpChTextRef
& xLabel
)
1865 sal_uInt16 nPointIdx
= xLabel
->GetPointPos().mnPointIdx
;
1866 if ((nPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
) && (nPointIdx
>= EXC_CHDATAFORMAT_MAXPOINTCOUNT
))
1867 // Above the maximum allowed data points. Bail out.
1870 XclImpChTextMap::iterator itr
= maLabels
.lower_bound(nPointIdx
);
1871 if (itr
== maLabels
.end() || maLabels
.key_comp()(nPointIdx
, itr
->first
))
1873 // No object exists at this point index position. Insert it.
1874 itr
= maLabels
.insert(itr
, XclImpChTextMap::value_type(nPointIdx
, xLabel
));
1878 void XclImpChSeries::AddChildSeries( const XclImpChSeries
& rSeries
)
1880 OSL_ENSURE( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1881 if (&rSeries
== this)
1883 SAL_WARN("sc.filter", "self add attempt");
1887 /* In Excel, trend lines and error bars are stored as own series. In Calc,
1888 these are properties of the parent series. This function adds the
1889 settings of the passed series to this series. */
1890 maTrendLines
.insert( maTrendLines
.end(), rSeries
.maTrendLines
.begin(), rSeries
.maTrendLines
.end() );
1891 for (auto const& it
: rSeries
.m_ErrorBars
)
1893 m_ErrorBars
.insert(std::make_pair(it
.first
, std::make_unique
<XclImpChSerErrorBar
>(*it
.second
)));
1897 void XclImpChSeries::FinalizeDataFormats()
1899 if( HasParentSeries() )
1901 // *** series is a child series, e.g. trend line or error bar ***
1903 // create missing series format
1905 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, 0 );
1909 // #i83100# set text label format, e.g. for trend line equations
1910 XclImpChTextRef xLabel
;
1911 XclImpChTextMap::iterator itr
= maLabels
.find(EXC_CHDATAFORMAT_ALLPOINTS
);
1912 if (itr
!= maLabels
.end())
1913 xLabel
= itr
->second
;
1914 mxSeriesFmt
->SetDataLabel(xLabel
);
1915 // create missing automatic formats
1916 mxSeriesFmt
->UpdateTrendLineFormat();
1919 // copy series formatting to child objects
1920 for (auto const& trendLine
: maTrendLines
)
1922 trendLine
->SetDataFormat(mxSeriesFmt
);
1923 if (mxTitleLink
&& mxTitleLink
->HasString())
1925 trendLine
->SetTrendlineName(mxTitleLink
->GetString());
1928 for (auto const& it
: m_ErrorBars
)
1930 it
.second
->SetSeriesData( mxValueLink
, mxSeriesFmt
);
1933 else if( XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
1935 // *** series is a regular data series ***
1937 // create missing series format
1940 // #i51639# use a new unused format index to create series default format
1941 sal_uInt16 nFormatIdx
= pTypeGroup
->PopUnusedFormatIndex();
1942 mxSeriesFmt
= CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS
, nFormatIdx
);
1945 // set text labels to data formats
1946 for (auto const& label
: maLabels
)
1948 sal_uInt16 nPointIdx
= label
.first
;
1949 if (nPointIdx
== EXC_CHDATAFORMAT_ALLPOINTS
)
1952 mxSeriesFmt
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1953 mxSeriesFmt
->SetDataLabel(label
.second
);
1955 else if (nPointIdx
< EXC_CHDATAFORMAT_MAXPOINTCOUNT
)
1957 XclImpChDataFormatRef p
;
1958 XclImpChDataFormatMap::iterator itr
= maPointFmts
.lower_bound(nPointIdx
);
1959 if (itr
== maPointFmts
.end() || maPointFmts
.key_comp()(nPointIdx
, itr
->first
))
1961 // No object exists at this point index position. Insert
1963 p
= CreateDataFormat(nPointIdx
, EXC_CHDATAFORMAT_DEFAULT
);
1964 itr
= maPointFmts
.insert(
1965 itr
, XclImpChDataFormatMap::value_type(nPointIdx
, p
));
1969 p
->SetDataLabel(label
.second
);
1973 // update series format (copy missing formatting from group default format)
1975 mxSeriesFmt
->UpdateSeriesFormat( pTypeGroup
->GetTypeInfo(), pTypeGroup
->GetGroupFormat().get() );
1977 // update data point formats (removes unchanged automatic formatting)
1978 for (auto const& pointFormat
: maPointFmts
)
1979 pointFormat
.second
->UpdatePointFormat( pTypeGroup
->GetTypeInfo(), mxSeriesFmt
.get() );
1985 /** Returns the property set of the specified data point. */
1986 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> const & xDataSeries
, sal_uInt16 nPointIdx
)
1988 ScfPropertySet aPropSet
;
1991 aPropSet
.Set( xDataSeries
->getDataPointByIndex( static_cast< sal_Int32
>( nPointIdx
) ) );
1995 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
2002 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateValueSequence( const OUString
& rValueRole
) const
2004 return lclCreateLabeledDataSequence( mxValueLink
, rValueRole
, mxTitleLink
.get() );
2007 Reference
< XLabeledDataSequence
> XclImpChSeries::CreateCategSequence( const OUString
& rCategRole
) const
2009 return lclCreateLabeledDataSequence( mxCategLink
, rCategRole
);
2012 Reference
< XDataSeries
> XclImpChSeries::CreateDataSeries() const
2014 Reference
< XDataSeries
> xDataSeries
;
2015 if( const XclImpChTypeGroup
* pTypeGroup
= GetChartData().GetTypeGroup( mnGroupIdx
).get() )
2017 const XclChExtTypeInfo
& rTypeInfo
= pTypeGroup
->GetTypeInfo();
2019 // create the data series object
2020 xDataSeries
.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2022 // attach data and title sequences to series
2023 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2024 if( xDataSink
.is() )
2026 // create vector of all value sequences
2027 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2029 Reference
< XLabeledDataSequence
> xYValueSeq
=
2030 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES
);
2031 if( xYValueSeq
.is() )
2032 aLabeledSeqVec
.push_back( xYValueSeq
);
2034 if( !rTypeInfo
.mbCategoryAxis
)
2036 Reference
< XLabeledDataSequence
> xXValueSeq
=
2037 CreateCategSequence( EXC_CHPROP_ROLE_XVALUES
);
2038 if( xXValueSeq
.is() )
2039 aLabeledSeqVec
.push_back( xXValueSeq
);
2040 // add size values of bubble charts
2041 if( rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
)
2043 Reference
< XLabeledDataSequence
> xSizeValueSeq
=
2044 lclCreateLabeledDataSequence( mxBubbleLink
, EXC_CHPROP_ROLE_SIZEVALUES
, mxTitleLink
.get() );
2045 if( xSizeValueSeq
.is() )
2046 aLabeledSeqVec
.push_back( xSizeValueSeq
);
2049 // attach labeled data sequences to series
2050 if( !aLabeledSeqVec
.empty() )
2051 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2054 // series formatting
2055 ScfPropertySet
aSeriesProp( xDataSeries
);
2057 mxSeriesFmt
->Convert( aSeriesProp
, rTypeInfo
);
2060 aSeriesProp
.SetProperty(EXC_CHPROP_SHOWLEGENDENTRY
, false);
2063 ConvertTrendLines( xDataSeries
);
2066 Reference
< XPropertySet
> xErrorBarX
= CreateErrorBar( EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
2067 if( xErrorBarX
.is() )
2068 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARX
, xErrorBarX
);
2069 Reference
< XPropertySet
> xErrorBarY
= CreateErrorBar( EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
2070 if( xErrorBarY
.is() )
2071 aSeriesProp
.SetProperty( EXC_CHPROP_ERRORBARY
, xErrorBarY
);
2073 // own area formatting for every data point (TODO: varying line color not supported)
2074 bool bVarPointFmt
= pTypeGroup
->HasVarPointFormat() && rTypeInfo
.IsSeriesFrameFormat();
2075 aSeriesProp
.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
2076 // #i91271# always set area formatting for every point in pie/doughnut charts
2077 if (mxSeriesFmt
&& mxValueLink
&& ((bVarPointFmt
&& mxSeriesFmt
->IsAutoArea()) || (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)))
2079 for( sal_uInt16 nPointIdx
= 0, nPointCount
= mxValueLink
->GetCellCount(); nPointIdx
< nPointCount
; ++nPointIdx
)
2081 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
2082 mxSeriesFmt
->ConvertArea( aPointProp
, bVarPointFmt
? nPointIdx
: mnSeriesIdx
);
2086 // data point formatting
2087 for (auto const& pointFormat
: maPointFmts
)
2089 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, pointFormat
.first
);
2090 pointFormat
.second
->Convert( aPointProp
, rTypeInfo
, &aSeriesProp
);
2096 void XclImpChSeries::FillAllSourceLinks( ::std::vector
< ScTokenRef
>& rTokens
) const
2099 mxValueLink
->FillSourceLink( rTokens
);
2101 mxCategLink
->FillSourceLink( rTokens
);
2103 mxTitleLink
->FillSourceLink( rTokens
);
2105 mxBubbleLink
->FillSourceLink( rTokens
);
2108 void XclImpChSeries::ReadChSourceLink( XclImpStream
& rStrm
)
2110 XclImpChSourceLinkRef
xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
2111 xSrcLink
->ReadChSourceLink( rStrm
);
2112 switch( xSrcLink
->GetDestType() )
2114 case EXC_CHSRCLINK_TITLE
: mxTitleLink
= xSrcLink
; break;
2115 case EXC_CHSRCLINK_VALUES
: mxValueLink
= xSrcLink
; break;
2116 case EXC_CHSRCLINK_CATEGORY
: mxCategLink
= xSrcLink
; break;
2117 case EXC_CHSRCLINK_BUBBLES
: mxBubbleLink
= xSrcLink
; break;
2121 void XclImpChSeries::ReadChDataFormat( XclImpStream
& rStrm
)
2123 // #i51639# chart stores all data formats and assigns them later to the series
2124 GetChartData().ReadChDataFormat( rStrm
);
2127 void XclImpChSeries::ReadChSerParent( XclImpStream
& rStrm
)
2129 mnParentIdx
= rStrm
.ReaduInt16();
2130 // index to parent series is 1-based, convert it to 0-based
2131 if( mnParentIdx
> 0 )
2134 mnParentIdx
= EXC_CHSERIES_INVALID
;
2137 void XclImpChSeries::ReadChSerTrendLine( XclImpStream
& rStrm
)
2139 XclImpChSerTrendLineRef
xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
2140 xTrendLine
->ReadChSerTrendLine( rStrm
);
2141 maTrendLines
.push_back( xTrendLine
);
2144 void XclImpChSeries::ReadChSerErrorBar( XclImpStream
& rStrm
)
2146 unique_ptr
<XclImpChSerErrorBar
> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
2147 pErrorBar
->ReadChSerErrorBar(rStrm
);
2148 sal_uInt8 nBarType
= pErrorBar
->GetBarType();
2149 m_ErrorBars
.insert(std::make_pair(nBarType
, std::move(pErrorBar
)));
2152 XclImpChDataFormatRef
XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx
, sal_uInt16 nFormatIdx
)
2154 XclImpChDataFormatRef
xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2155 xDataFmt
->SetPointPos( XclChDataPointPos( mnSeriesIdx
, nPointIdx
), nFormatIdx
);
2159 void XclImpChSeries::ConvertTrendLines( Reference
< XDataSeries
> const & xDataSeries
) const
2161 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2162 if( xRegCurveCont
.is() )
2164 for (auto const& trendLine
: maTrendLines
)
2168 Reference
< XRegressionCurve
> xRegCurve
= trendLine
->CreateRegressionCurve();
2169 if( xRegCurve
.is() )
2171 xRegCurveCont
->addRegressionCurve( xRegCurve
);
2176 OSL_FAIL( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2182 Reference
< XPropertySet
> XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
) const
2184 XclImpChSerErrorBarMap::const_iterator itrPosBar
= m_ErrorBars
.find(nPosBarId
);
2185 XclImpChSerErrorBarMap::const_iterator itrNegBar
= m_ErrorBars
.find(nNegBarId
);
2186 XclImpChSerErrorBarMap::const_iterator itrEnd
= m_ErrorBars
.end();
2187 if (itrPosBar
== itrEnd
|| itrNegBar
== itrEnd
)
2188 return Reference
<XPropertySet
>();
2190 return XclImpChSerErrorBar::CreateErrorBar(itrPosBar
->second
.get(), itrNegBar
->second
.get());
2193 void XclImpChSeries::ReadChLegendException(XclImpStream
& rStrm
)
2196 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
2197 mbLabelDeleted
= (nFlags
& EXC_CHLEGENDEXCEPTION_DELETED
);
2200 // Chart type groups ==========================================================
2202 XclImpChType::XclImpChType( const XclImpChRoot
& rRoot
) :
2203 XclImpChRoot( rRoot
),
2204 mnRecId( EXC_ID_CHUNKNOWN
),
2205 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2209 void XclImpChType::ReadChType( XclImpStream
& rStrm
)
2211 sal_uInt16 nRecId
= rStrm
.GetRecId();
2212 bool bKnownType
= true;
2217 maData
.mnOverlap
= rStrm
.ReadInt16();
2218 maData
.mnGap
= rStrm
.ReadInt16();
2219 maData
.mnFlags
= rStrm
.ReaduInt16();
2224 case EXC_ID_CHRADARLINE
:
2225 case EXC_ID_CHRADARAREA
:
2226 maData
.mnFlags
= rStrm
.ReaduInt16();
2230 maData
.mnRotation
= rStrm
.ReaduInt16();
2231 maData
.mnPieHole
= rStrm
.ReaduInt16();
2232 if( GetBiff() == EXC_BIFF8
)
2233 maData
.mnFlags
= rStrm
.ReaduInt16();
2238 case EXC_ID_CHPIEEXT
:
2239 maData
.mnRotation
= 0;
2240 maData
.mnPieHole
= 0;
2244 case EXC_ID_CHSCATTER
:
2245 if( GetBiff() == EXC_BIFF8
)
2247 maData
.mnBubbleSize
= rStrm
.ReaduInt16();
2248 maData
.mnBubbleType
= rStrm
.ReaduInt16();
2249 maData
.mnFlags
= rStrm
.ReaduInt16();
2255 case EXC_ID_CHSURFACE
:
2256 maData
.mnFlags
= rStrm
.ReaduInt16();
2267 void XclImpChType::Finalize( bool bStockChart
)
2272 maTypeInfo
= GetChartTypeInfo( bStockChart
?
2273 EXC_CHTYPEID_STOCK
: EXC_CHTYPEID_LINE
);
2276 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2277 maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
,
2278 EXC_CHTYPEID_HORBAR
, EXC_CHTYPEID_BAR
) );
2281 maTypeInfo
= GetChartTypeInfo( (maData
.mnPieHole
> 0) ?
2282 EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2284 case EXC_ID_CHSCATTER
:
2285 maTypeInfo
= GetChartTypeInfo( ::get_flagvalue(
2286 maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
,
2287 EXC_CHTYPEID_BUBBLES
, EXC_CHTYPEID_SCATTER
) );
2290 maTypeInfo
= GetChartTypeInfo( mnRecId
);
2293 switch( maTypeInfo
.meTypeId
)
2295 case EXC_CHTYPEID_PIEEXT
:
2296 case EXC_CHTYPEID_BUBBLES
:
2297 case EXC_CHTYPEID_SURFACE
:
2298 case EXC_CHTYPEID_UNKNOWN
:
2299 GetTracer().TraceChartUnKnownType();
2305 bool XclImpChType::IsStacked() const
2307 bool bStacked
= false;
2308 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2310 case EXC_CHTYPECATEG_LINE
:
2312 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2313 !::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2315 case EXC_CHTYPECATEG_BAR
:
2317 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2318 !::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2325 bool XclImpChType::IsPercent() const
2327 bool bPercent
= false;
2328 if( maTypeInfo
.mbSupportsStacking
) switch( maTypeInfo
.meTypeCateg
)
2330 case EXC_CHTYPECATEG_LINE
:
2332 ::get_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
) &&
2333 ::get_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
);
2335 case EXC_CHTYPECATEG_BAR
:
2337 ::get_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
) &&
2338 ::get_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
);
2345 bool XclImpChType::HasCategoryLabels() const
2347 // radar charts disable category labels in chart type, not in CHTICK of X axis
2348 return (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) || ::get_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
);
2351 Reference
< XCoordinateSystem
> XclImpChType::CreateCoordSystem( bool b3dChart
) const
2353 // create the coordinate system object
2354 Reference
< css::uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
2355 Reference
< XCoordinateSystem
> xCoordSystem
;
2356 if( maTypeInfo
.mbPolarCoordSystem
)
2359 xCoordSystem
= css::chart2::PolarCoordinateSystem3d::create(xContext
);
2361 xCoordSystem
= css::chart2::PolarCoordinateSystem2d::create(xContext
);
2366 xCoordSystem
= css::chart2::CartesianCoordinateSystem3d::create(xContext
);
2368 xCoordSystem
= css::chart2::CartesianCoordinateSystem2d::create(xContext
);
2371 // swap X and Y axis
2372 if( maTypeInfo
.mbSwappedAxesSet
)
2374 ScfPropertySet
aCoordSysProp( xCoordSystem
);
2375 aCoordSysProp
.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
, true );
2378 return xCoordSystem
;
2381 Reference
< XChartType
> XclImpChType::CreateChartType( Reference
< XDiagram
> const & xDiagram
, bool b3dChart
) const
2383 OUString aService
= OUString::createFromAscii( maTypeInfo
.mpcServiceName
);
2384 Reference
< XChartType
> xChartType( ScfApiHelper::CreateInstance( aService
), UNO_QUERY
);
2386 // additional properties
2387 switch( maTypeInfo
.meTypeCateg
)
2389 case EXC_CHTYPECATEG_BAR
:
2391 ScfPropertySet
aTypeProp( xChartType
);
2392 Sequence
< sal_Int32
> aInt32Seq( 2 );
2393 aInt32Seq
[ 0 ] = aInt32Seq
[ 1 ] = -maData
.mnOverlap
;
2394 aTypeProp
.SetProperty( EXC_CHPROP_OVERLAPSEQ
, aInt32Seq
);
2395 aInt32Seq
[ 0 ] = aInt32Seq
[ 1 ] = maData
.mnGap
;
2396 aTypeProp
.SetProperty( EXC_CHPROP_GAPWIDTHSEQ
, aInt32Seq
);
2399 case EXC_CHTYPECATEG_PIE
:
2401 ScfPropertySet
aTypeProp( xChartType
);
2402 aTypeProp
.SetBoolProperty( EXC_CHPROP_USERINGS
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_DONUT
);
2403 /* #i85166# starting angle of first pie slice. 3D pie charts use Y
2404 rotation setting in view3D element. Of-pie charts do not
2405 support pie rotation. */
2406 if( !b3dChart
&& (maTypeInfo
.meTypeId
!= EXC_CHTYPEID_PIEEXT
) )
2408 ScfPropertySet
aDiaProp( xDiagram
);
2409 XclImpChRoot::ConvertPieRotation( aDiaProp
, maData
.mnRotation
);
2419 void XclImpChChart3d::ReadChChart3d( XclImpStream
& rStrm
)
2421 maData
.mnRotation
= rStrm
.ReaduInt16();
2422 maData
.mnElevation
= rStrm
.ReadInt16();
2423 maData
.mnEyeDist
= rStrm
.ReaduInt16();
2424 maData
.mnRelHeight
= rStrm
.ReaduInt16();
2425 maData
.mnRelDepth
= rStrm
.ReaduInt16();
2426 maData
.mnDepthGap
= rStrm
.ReaduInt16();
2427 maData
.mnFlags
= rStrm
.ReaduInt16();
2430 void XclImpChChart3d::Convert( ScfPropertySet
& rPropSet
, bool b3dWallChart
) const
2432 namespace cssd
= ::com::sun::star::drawing
;
2434 // #i104057# do not assert this, written by broken external generators
2435 // OSL_ENSURE( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2437 sal_Int32 nRotationY
= 0;
2438 sal_Int32 nRotationX
= 0;
2439 sal_Int32 nPerspective
= 15;
2440 bool bRightAngled
= false;
2441 cssd::ProjectionMode eProjMode
= cssd::ProjectionMode_PERSPECTIVE
;
2442 Color aAmbientColor
, aLightColor
;
2446 // Y rotation (Excel [0..359], Chart2 [-179,180])
2447 nRotationY
= NormAngle180
<sal_Int32
>(maData
.mnRotation
);
2448 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2449 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, -90, 90 );
2450 // perspective (Excel and Chart2 [0,100])
2451 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2452 // right-angled axes
2453 bRightAngled
= !::get_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
);
2454 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2455 bool bParallel
= bRightAngled
|| (nPerspective
== 0);
2456 eProjMode
= bParallel
? cssd::ProjectionMode_PARALLEL
: cssd::ProjectionMode_PERSPECTIVE
;
2457 // ambient color (Gray 20%)
2458 aAmbientColor
= Color( 204, 204, 204 );
2459 // light color (Gray 60%)
2460 aLightColor
= Color( 102, 102, 102 );
2464 // Y rotation not used in pie charts, but 'first pie slice angle'
2466 XclImpChRoot::ConvertPieRotation( rPropSet
, maData
.mnRotation
);
2467 // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2468 nRotationX
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnElevation
, 10, 80 ) - 90;
2469 // perspective (Excel and Chart2 [0,100])
2470 nPerspective
= limit_cast
< sal_Int32
, sal_Int32
>( maData
.mnEyeDist
, 0, 100 );
2471 // no right-angled axes in pie charts, but parallel projection
2472 bRightAngled
= false;
2473 eProjMode
= cssd::ProjectionMode_PARALLEL
;
2474 // ambient color (Gray 30%)
2475 aAmbientColor
= Color( 179, 179, 179 );
2476 // light color (Gray 70%)
2477 aLightColor
= Color( 76, 76, 76 );
2481 rPropSet
.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT
, static_cast<sal_Int32
>(maData
.mnRelHeight
/ 2)); // seems to be 200%, change to 100%
2482 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONVERTICAL
, nRotationY
);
2483 rPropSet
.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL
, nRotationX
);
2484 rPropSet
.SetProperty( EXC_CHPROP_PERSPECTIVE
, nPerspective
);
2485 rPropSet
.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
, bRightAngled
);
2486 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE
, eProjMode
);
2489 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE
, cssd::ShadeMode_FLAT
);
2490 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR
, aAmbientColor
);
2491 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1
, false );
2492 rPropSet
.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2
, true );
2493 rPropSet
.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2
, aLightColor
);
2494 rPropSet
.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2
, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2497 XclImpChLegend::XclImpChLegend( const XclImpChRoot
& rRoot
) :
2498 XclImpChRoot( rRoot
)
2502 void XclImpChLegend::ReadHeaderRecord( XclImpStream
& rStrm
)
2504 rStrm
>> maData
.maRect
;
2505 maData
.mnDockMode
= rStrm
.ReaduInt8();
2506 maData
.mnSpacing
= rStrm
.ReaduInt8();
2507 maData
.mnFlags
= rStrm
.ReaduInt16();
2509 // trace unsupported features
2510 if( GetTracer().IsEnabled() )
2512 if( maData
.mnDockMode
== EXC_CHLEGEND_NOTDOCKED
)
2513 GetTracer().TraceChartLegendPosition();
2514 if( ::get_flag( maData
.mnFlags
, EXC_CHLEGEND_DATATABLE
) )
2515 GetTracer().TraceChartDataTable();
2519 void XclImpChLegend::ReadSubRecord( XclImpStream
& rStrm
)
2521 switch( rStrm
.GetRecId() )
2523 case EXC_ID_CHFRAMEPOS
:
2524 mxFramePos
.reset( new XclImpChFramePos
);
2525 mxFramePos
->ReadChFramePos( rStrm
);
2528 mxText
.reset( new XclImpChText( GetChRoot() ) );
2529 mxText
->ReadRecordGroup( rStrm
);
2531 case EXC_ID_CHFRAME
:
2532 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND
) );
2533 mxFrame
->ReadRecordGroup( rStrm
);
2538 void XclImpChLegend::Finalize()
2540 // legend default formatting differs in OOChart and Excel, missing frame means automatic
2542 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND
) );
2543 // Update text formatting. If mxText is empty, the passed default text is used.
2544 lclUpdateText( mxText
, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND
) );
2547 Reference
< XLegend
> XclImpChLegend::CreateLegend() const
2549 Reference
< XLegend
> xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND
), UNO_QUERY
);
2552 ScfPropertySet
aLegendProp( xLegend
);
2553 aLegendProp
.SetBoolProperty( EXC_CHPROP_SHOW
, true );
2557 mxFrame
->Convert( aLegendProp
);
2560 mxText
->ConvertFont( aLegendProp
);
2562 /* Legend position and size. Default positions are used only if the
2563 plot area is positioned automatically (Excel sets the plot area to
2564 manual mode, if the legend is moved or resized). With manual plot
2565 areas, Excel ignores the value in maData.mnDockMode completely. */
2566 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_CUSTOM
;
2567 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2568 if( !GetChartData().IsManualPlotArea() ) switch( maData
.mnDockMode
)
2570 case EXC_CHLEGEND_LEFT
:
2571 eApiPos
= cssc2::LegendPosition_LINE_START
;
2572 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2574 case EXC_CHLEGEND_RIGHT
:
2575 // top-right not supported
2576 case EXC_CHLEGEND_CORNER
:
2577 eApiPos
= cssc2::LegendPosition_LINE_END
;
2578 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2580 case EXC_CHLEGEND_TOP
:
2581 eApiPos
= cssc2::LegendPosition_PAGE_START
;
2582 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2584 case EXC_CHLEGEND_BOTTOM
:
2585 eApiPos
= cssc2::LegendPosition_PAGE_END
;
2586 eApiExpand
= cssc::ChartLegendExpansion_WIDE
;
2590 // no automatic position/size: try to find the correct position and size
2591 if( eApiPos
== cssc2::LegendPosition_CUSTOM
)
2593 const XclChFramePos
* pFramePos
= mxFramePos
? &mxFramePos
->GetFramePosData() : nullptr;
2595 /* Legend position. Only the settings from the CHFRAMEPOS record
2596 are used by Excel, the position in the CHLEGEND record will be
2600 RelativePosition
aRelPos(
2601 CalcRelativeFromChartX( pFramePos
->maRect
.mnX
),
2602 CalcRelativeFromChartY( pFramePos
->maRect
.mnY
),
2603 css::drawing::Alignment_TOP_LEFT
);
2604 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVEPOSITION
, aRelPos
);
2608 // no manual position/size found, just go for the default
2609 eApiPos
= cssc2::LegendPosition_LINE_END
;
2612 /* Legend size. The member mnBRMode specifies whether size is
2613 automatic or changes manually. Manual size is given in points,
2614 not in chart units. */
2615 if( pFramePos
&& (pFramePos
->mnBRMode
== EXC_CHFRAMEPOS_ABSSIZE_POINTS
) &&
2616 (pFramePos
->maRect
.mnWidth
> 0) && (pFramePos
->maRect
.mnHeight
> 0) )
2618 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2619 sal_Int32 nWidthHmm
= static_cast< sal_Int32
>( pFramePos
->maRect
.mnWidth
/ EXC_POINTS_PER_HMM
);
2620 sal_Int32 nHeightHmm
= static_cast< sal_Int32
>( pFramePos
->maRect
.mnHeight
/ EXC_POINTS_PER_HMM
);
2621 RelativeSize
aRelSize( CalcRelativeFromHmmX( nWidthHmm
), CalcRelativeFromHmmY( nHeightHmm
) );
2622 aLegendProp
.SetProperty( EXC_CHPROP_RELATIVESIZE
, aRelSize
);
2626 // automatic size: determine entry direction from flags
2627 eApiExpand
= ::get_flagvalue( maData
.mnFlags
, EXC_CHLEGEND_STACKED
,
2628 cssc::ChartLegendExpansion_HIGH
, cssc::ChartLegendExpansion_WIDE
);
2631 aLegendProp
.SetProperty( EXC_CHPROP_ANCHORPOSITION
, eApiPos
);
2632 aLegendProp
.SetProperty( EXC_CHPROP_EXPANSION
, eApiExpand
);
2637 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar
) :
2638 mnDropBar( nDropBar
),
2643 void XclImpChDropBar::ReadHeaderRecord( XclImpStream
& rStrm
)
2645 mnBarDist
= rStrm
.ReaduInt16();
2648 void XclImpChDropBar::Convert( const XclImpChRoot
& rRoot
, ScfPropertySet
& rPropSet
) const
2650 XclChObjectType eObjType
= EXC_CHOBJTYPE_BACKGROUND
;
2653 case EXC_CHDROPBAR_UP
: eObjType
= EXC_CHOBJTYPE_WHITEDROPBAR
; break;
2654 case EXC_CHDROPBAR_DOWN
: eObjType
= EXC_CHOBJTYPE_BLACKDROPBAR
; break;
2656 ConvertFrameBase( rRoot
, rPropSet
, eObjType
);
2659 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot
& rRoot
) :
2660 XclImpChRoot( rRoot
),
2662 maTypeInfo( maType
.GetTypeInfo() )
2664 // Initialize unused format indexes set. At this time, all formats are unused.
2665 for( sal_uInt16 nFormatIdx
= 0; nFormatIdx
<= EXC_CHSERIES_MAXSERIES
; ++nFormatIdx
)
2666 maUnusedFormats
.insert( maUnusedFormats
.end(), nFormatIdx
);
2669 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream
& rStrm
)
2672 maData
.mnFlags
= rStrm
.ReaduInt16();
2673 maData
.mnGroupIdx
= rStrm
.ReaduInt16();
2676 void XclImpChTypeGroup::ReadSubRecord( XclImpStream
& rStrm
)
2678 switch( rStrm
.GetRecId() )
2680 case EXC_ID_CHCHART3D
:
2681 mxChart3d
.reset( new XclImpChChart3d
);
2682 mxChart3d
->ReadChChart3d( rStrm
);
2684 case EXC_ID_CHLEGEND
:
2685 mxLegend
.reset( new XclImpChLegend( GetChRoot() ) );
2686 mxLegend
->ReadRecordGroup( rStrm
);
2688 case EXC_ID_CHDEFAULTTEXT
:
2689 GetChartData().ReadChDefaultText( rStrm
);
2691 case EXC_ID_CHDROPBAR
:
2692 ReadChDropBar( rStrm
);
2694 case EXC_ID_CHCHARTLINE
:
2695 ReadChChartLine( rStrm
);
2697 case EXC_ID_CHDATAFORMAT
:
2698 ReadChDataFormat( rStrm
);
2701 maType
.ReadChType( rStrm
);
2705 void XclImpChTypeGroup::Finalize()
2707 // check and set valid chart type
2709 (maType
.GetRecId() == EXC_ID_CHLINE
) && // must be a line chart
2710 !mxChart3d
&& // must be a 2d chart
2711 m_ChartLines
.find(EXC_CHCHARTLINE_HILO
) != m_ChartLines
.end() && // must contain hi-lo lines
2712 (maSeries
.size() == static_cast<XclImpChSeriesVec::size_type
>(HasDropBars() ? 4 : 3)); // correct series count
2713 maType
.Finalize( bStockChart
);
2715 // extended type info
2716 maTypeInfo
.Set( maType
.GetTypeInfo(), static_cast< bool >(mxChart3d
), false );
2718 // reverse series order for some unstacked 2D chart types
2719 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() && !maType
.IsStacked() && !maType
.IsPercent() )
2720 ::std::reverse( maSeries
.begin(), maSeries
.end() );
2722 // update chart type group format, may depend on chart type finalized above
2724 mxGroupFmt
->UpdateGroupFormat( maTypeInfo
);
2727 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef
const & xSeries
)
2730 maSeries
.push_back( xSeries
);
2731 // store first inserted series separately, series order may be reversed later
2732 if( !mxFirstSeries
)
2733 mxFirstSeries
= xSeries
;
2736 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx
)
2738 maUnusedFormats
.erase( nFormatIdx
);
2741 sal_uInt16
XclImpChTypeGroup::PopUnusedFormatIndex()
2743 OSL_ENSURE( !maUnusedFormats
.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2744 sal_uInt16 nFormatIdx
= maUnusedFormats
.empty() ? 0 : *maUnusedFormats
.begin();
2745 SetUsedFormatIndex( nFormatIdx
);
2749 bool XclImpChTypeGroup::HasVarPointFormat() const
2751 return ::get_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
) &&
2752 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_MULTI
) || // multiple series allowed
2753 ((maTypeInfo
.meVarPointMode
== EXC_CHVARPOINT_SINGLE
) && // or exactly 1 series?
2754 (maSeries
.size() == 1)));
2757 bool XclImpChTypeGroup::HasConnectorLines() const
2759 // existence of connector lines (only in stacked bar charts)
2760 if ( !(maType
.IsStacked() || maType
.IsPercent()) || (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_BAR
) )
2762 XclImpChLineFormatMap::const_iterator aConLine
= m_ChartLines
.find(EXC_CHCHARTLINE_CONNECT
);
2763 return (aConLine
!= m_ChartLines
.end() && aConLine
->second
.HasLine());
2766 OUString
XclImpChTypeGroup::GetSingleSeriesTitle() const
2768 // no automatic title for series with trendlines or error bars
2769 // pie charts always show an automatic title, even if more series exist
2770 return (mxFirstSeries
&& !mxFirstSeries
->HasChildSeries() && (maTypeInfo
.mbSingleSeriesVis
|| (maSeries
.size() == 1))) ?
2771 mxFirstSeries
->GetTitle() : OUString();
2774 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet
& rPropSet
) const
2777 mxChart3d
->Convert( rPropSet
, Is3dWallChart() );
2780 Reference
< XCoordinateSystem
> XclImpChTypeGroup::CreateCoordSystem() const
2782 return maType
.CreateCoordSystem( Is3dChart() );
2785 Reference
< XChartType
> XclImpChTypeGroup::CreateChartType( Reference
< XDiagram
> const & xDiagram
, sal_Int32 nApiAxesSetIdx
) const
2787 OSL_ENSURE( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2789 // create the chart type object
2790 Reference
< XChartType
> xChartType
= maType
.CreateChartType( xDiagram
, Is3dChart() );
2792 // bar chart connector lines
2793 if( HasConnectorLines() )
2795 ScfPropertySet
aDiaProp( xDiagram
);
2796 aDiaProp
.SetBoolProperty( EXC_CHPROP_CONNECTBARS
, true );
2799 /* Stock chart needs special processing. Create one 'big' series with
2800 data sequences of different roles. */
2801 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2802 CreateStockSeries( xChartType
, nApiAxesSetIdx
);
2804 CreateDataSeries( xChartType
, nApiAxesSetIdx
);
2809 Reference
< XLabeledDataSequence
> XclImpChTypeGroup::CreateCategSequence() const
2811 Reference
< XLabeledDataSequence
> xLabeledSeq
;
2812 // create category sequence from first visible series
2814 xLabeledSeq
= mxFirstSeries
->CreateCategSequence( EXC_CHPROP_ROLE_CATEG
);
2818 void XclImpChTypeGroup::ReadChDropBar( XclImpStream
& rStrm
)
2820 if (m_DropBars
.find(EXC_CHDROPBAR_UP
) == m_DropBars
.end())
2822 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_UP
));
2823 p
->ReadRecordGroup(rStrm
);
2824 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_UP
, std::move(p
)));
2826 else if (m_DropBars
.find(EXC_CHDROPBAR_DOWN
) == m_DropBars
.end())
2828 unique_ptr
<XclImpChDropBar
> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN
));
2829 p
->ReadRecordGroup(rStrm
);
2830 m_DropBars
.insert(std::make_pair(EXC_CHDROPBAR_DOWN
, std::move(p
)));
2834 void XclImpChTypeGroup::ReadChChartLine( XclImpStream
& rStrm
)
2836 sal_uInt16 nLineId
= rStrm
.ReaduInt16();
2837 if( (rStrm
.GetNextRecId() == EXC_ID_CHLINEFORMAT
) && rStrm
.StartNextRecord() )
2839 XclImpChLineFormat aLineFmt
;
2840 aLineFmt
.ReadChLineFormat( rStrm
);
2841 m_ChartLines
[ nLineId
] = aLineFmt
;
2845 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream
& rStrm
)
2847 // global series and data point format
2848 XclImpChDataFormatRef
xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2849 xDataFmt
->ReadRecordGroup( rStrm
);
2850 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
2851 if( (rPos
.mnSeriesIdx
== 0) && (rPos
.mnPointIdx
== 0) &&
2852 (xDataFmt
->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT
) )
2853 mxGroupFmt
= xDataFmt
;
2856 void XclImpChTypeGroup::InsertDataSeries( Reference
< XChartType
> const & xChartType
,
2857 Reference
< XDataSeries
> const & xSeries
, sal_Int32 nApiAxesSetIdx
) const
2859 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2860 if( xSeriesCont
.is() && xSeries
.is() )
2862 // series stacking mode
2863 cssc2::StackingDirection eStacking
= cssc2::StackingDirection_NO_STACKING
;
2864 // stacked overrides deep-3d
2865 if( maType
.IsStacked() || maType
.IsPercent() )
2866 eStacking
= cssc2::StackingDirection_Y_STACKING
;
2867 else if( Is3dDeepChart() )
2868 eStacking
= cssc2::StackingDirection_Z_STACKING
;
2870 // additional series properties
2871 ScfPropertySet
aSeriesProp( xSeries
);
2872 aSeriesProp
.SetProperty( EXC_CHPROP_STACKINGDIR
, eStacking
);
2873 aSeriesProp
.SetProperty( EXC_CHPROP_ATTAXISINDEX
, nApiAxesSetIdx
);
2875 // insert series into container
2878 xSeriesCont
->addDataSeries( xSeries
);
2882 OSL_FAIL( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2887 void XclImpChTypeGroup::CreateDataSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2889 bool bSpline
= false;
2890 for (auto const& elem
: maSeries
)
2892 Reference
< XDataSeries
> xDataSeries
= elem
->CreateDataSeries();
2893 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2894 bSpline
|= elem
->HasSpline();
2896 // spline - TODO: set at single series (#i66858#)
2897 if( bSpline
&& !maTypeInfo
.IsSeriesFrameFormat() && (maTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_RADAR
) )
2899 ScfPropertySet
aTypeProp( xChartType
);
2900 aTypeProp
.SetProperty( EXC_CHPROP_CURVESTYLE
, css::chart2::CurveStyle_CUBIC_SPLINES
);
2904 void XclImpChTypeGroup::CreateStockSeries( Reference
< XChartType
> const & xChartType
, sal_Int32 nApiAxesSetIdx
) const
2906 // create the data series object
2907 Reference
< XDataSeries
> xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES
), UNO_QUERY
);
2908 Reference
< XDataSink
> xDataSink( xDataSeries
, UNO_QUERY
);
2909 if( xDataSink
.is() )
2911 // create a list of data sequences from all series
2912 ::std::vector
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
;
2913 OSL_ENSURE( maSeries
.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2914 int nRoleIdx
= (maSeries
.size() == 3) ? 1 : 0;
2915 for( const auto& rxSeries
: maSeries
)
2917 // create a data sequence with a specific role
2921 case 0: aRole
= EXC_CHPROP_ROLE_OPENVALUES
; break;
2922 case 1: aRole
= EXC_CHPROP_ROLE_HIGHVALUES
; break;
2923 case 2: aRole
= EXC_CHPROP_ROLE_LOWVALUES
; break;
2924 case 3: aRole
= EXC_CHPROP_ROLE_CLOSEVALUES
; break;
2926 Reference
< XLabeledDataSequence
> xDataSeq
= rxSeries
->CreateValueSequence( aRole
);
2928 aLabeledSeqVec
.push_back( xDataSeq
);
2934 // attach labeled data sequences to series and insert series into chart type
2935 xDataSink
->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec
) );
2937 // formatting of special stock chart elements
2938 ScfPropertySet
aTypeProp( xChartType
);
2939 aTypeProp
.SetBoolProperty( EXC_CHPROP_JAPANESE
, HasDropBars() );
2940 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWFIRST
, HasDropBars() );
2941 aTypeProp
.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
, true );
2942 // hi-lo line format
2943 XclImpChLineFormatMap::const_iterator aHiLoLine
= m_ChartLines
.find( EXC_CHCHARTLINE_HILO
);
2944 if (aHiLoLine
!= m_ChartLines
.end())
2946 ScfPropertySet
aSeriesProp( xDataSeries
);
2947 aHiLoLine
->second
.Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2949 // white dropbar format
2950 XclImpChDropBarMap::const_iterator itr
= m_DropBars
.find(EXC_CHDROPBAR_UP
);
2951 Reference
<XPropertySet
> xWhitePropSet
;
2952 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xWhitePropSet
, EXC_CHPROP_WHITEDAY
))
2954 ScfPropertySet
aBarProp( xWhitePropSet
);
2955 itr
->second
->Convert(GetChRoot(), aBarProp
);
2957 // black dropbar format
2958 itr
= m_DropBars
.find(EXC_CHDROPBAR_DOWN
);
2959 Reference
<XPropertySet
> xBlackPropSet
;
2960 if (itr
!= m_DropBars
.end() && aTypeProp
.GetProperty(xBlackPropSet
, EXC_CHPROP_BLACKDAY
))
2962 ScfPropertySet
aBarProp( xBlackPropSet
);
2963 itr
->second
->Convert(GetChRoot(), aBarProp
);
2966 // insert the series into the chart type object
2967 InsertDataSeries( xChartType
, xDataSeries
, nApiAxesSetIdx
);
2971 // Axes =======================================================================
2973 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot
& rRoot
) :
2974 XclImpChRoot( rRoot
)
2978 void XclImpChLabelRange::ReadChLabelRange( XclImpStream
& rStrm
)
2980 maLabelData
.mnCross
= rStrm
.ReaduInt16();
2981 maLabelData
.mnLabelFreq
= rStrm
.ReaduInt16();
2982 maLabelData
.mnTickFreq
= rStrm
.ReaduInt16();
2983 maLabelData
.mnFlags
= rStrm
.ReaduInt16();
2986 void XclImpChLabelRange::ReadChDateRange( XclImpStream
& rStrm
)
2988 maDateData
.mnMinDate
= rStrm
.ReaduInt16();
2989 maDateData
.mnMaxDate
= rStrm
.ReaduInt16();
2990 maDateData
.mnMajorStep
= rStrm
.ReaduInt16();
2991 maDateData
.mnMajorUnit
= rStrm
.ReaduInt16();
2992 maDateData
.mnMinorStep
= rStrm
.ReaduInt16();
2993 maDateData
.mnMinorUnit
= rStrm
.ReaduInt16();
2994 maDateData
.mnBaseUnit
= rStrm
.ReaduInt16();
2995 maDateData
.mnCross
= rStrm
.ReaduInt16();
2996 maDateData
.mnFlags
= rStrm
.ReaduInt16();
2999 void XclImpChLabelRange::Convert( ScfPropertySet
& rPropSet
, ScaleData
& rScaleData
, bool bMirrorOrient
) const
3001 // automatic axis type detection
3002 rScaleData
.AutoDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
);
3004 // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
3005 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3007 /* Chart2 requires axis type CATEGORY for automatic category/date axis
3008 (even if it is a date axis currently). */
3009 rScaleData
.AxisType
= rScaleData
.AutoDateAxis
? cssc2::AxisType::CATEGORY
: cssc2::AxisType::DATE
;
3010 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3011 /* Min/max values depend on base time unit, they specify the number of
3012 days, months, or years starting from null date. */
3013 lclConvertTimeValue( GetRoot(), rScaleData
.Minimum
, maDateData
.mnMinDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
), maDateData
.mnBaseUnit
);
3014 lclConvertTimeValue( GetRoot(), rScaleData
.Maximum
, maDateData
.mnMaxDate
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
), maDateData
.mnBaseUnit
);
3016 cssc::TimeIncrement
& rTimeIncrement
= rScaleData
.TimeIncrement
;
3017 lclConvertTimeInterval( rTimeIncrement
.MajorTimeInterval
, maDateData
.mnMajorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
), maDateData
.mnMajorUnit
);
3018 lclConvertTimeInterval( rTimeIncrement
.MinorTimeInterval
, maDateData
.mnMinorStep
, ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
), maDateData
.mnMinorUnit
);
3020 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
) )
3021 rTimeIncrement
.TimeResolution
.clear();
3023 rTimeIncrement
.TimeResolution
<<= lclGetApiTimeUnit( maDateData
.mnBaseUnit
);
3027 // do not overlap text unless all labels are visible
3028 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP
, maLabelData
.mnLabelFreq
== 1 );
3029 // do not break text into several lines unless all labels are visible
3030 rPropSet
.SetBoolProperty( EXC_CHPROP_TEXTBREAK
, maLabelData
.mnLabelFreq
== 1 );
3031 // do not stagger labels in two lines
3032 rPropSet
.SetProperty( EXC_CHPROP_ARRANGEORDER
, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE
);
3036 bool bReverse
= ::get_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
) != bMirrorOrient
;
3037 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3039 //TODO #i58731# show n-th category
3042 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
, bool b3dChart
) const
3044 /* Crossing mode (max-cross flag overrides other crossing settings). Excel
3045 does not move the Y axis in 3D charts, regardless of actual settings.
3046 But: the Y axis has to be moved to "end", if the X axis is mirrored,
3047 to keep it at the left end of the chart. */
3048 bool bMaxCross
= ::get_flag( maLabelData
.mnFlags
, b3dChart
? EXC_CHLABELRANGE_REVERSE
: EXC_CHLABELRANGE_MAXCROSS
);
3049 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3050 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3052 // crossing position (depending on axis type text/date)
3053 if( ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
) )
3055 bool bAutoCross
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
3056 /* Crossing position value depends on base time unit, it specifies the
3057 number of days, months, or years from null date. Note that Excel
3058 2007/2010 write broken BIFF8 files, they always stores the number
3059 of days regardless of the base time unit (and they are reading it
3060 the same way, thus wrongly displaying files written by Excel
3061 97-2003). This filter sticks to the correct behaviour of Excel
3063 double fCrossingPos
= bAutoCross
? 1.0 : lclGetSerialDay( GetRoot(), maDateData
.mnCross
, maDateData
.mnBaseUnit
);
3064 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3068 double fCrossingPos
= b3dChart
? 1.0 : maLabelData
.mnCross
;
3069 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3073 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot
& rRoot
) :
3074 XclImpChRoot( rRoot
)
3078 void XclImpChValueRange::ReadChValueRange( XclImpStream
& rStrm
)
3080 maData
.mfMin
= rStrm
.ReadDouble();
3081 maData
.mfMax
= rStrm
.ReadDouble();
3082 maData
.mfMajorStep
= rStrm
.ReadDouble();
3083 maData
.mfMinorStep
= rStrm
.ReadDouble();
3084 maData
.mfCross
= rStrm
.ReadDouble();
3085 maData
.mnFlags
= rStrm
.ReaduInt16();
3088 void XclImpChValueRange::Convert( ScaleData
& rScaleData
, bool bMirrorOrient
) const
3090 // scaling algorithm
3091 const bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3093 rScaleData
.Scaling
= css::chart2::LogarithmicScaling::create( comphelper::getProcessComponentContext() );
3095 rScaleData
.Scaling
= css::chart2::LinearScaling::create( comphelper::getProcessComponentContext() );
3098 lclSetExpValueOrClearAny( rScaleData
.Minimum
, maData
.mfMin
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
) );
3099 lclSetExpValueOrClearAny( rScaleData
.Maximum
, maData
.mfMax
, bLogScale
, ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
) );
3102 bool bAutoMajor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
);
3103 bool bAutoMinor
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
);
3105 IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
3106 lclSetValueOrClearAny( rIncrementData
.Distance
, maData
.mfMajorStep
, bAutoMajor
);
3108 Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
3109 rSubIncrementSeq
.realloc( 1 );
3110 Any
& rIntervalCount
= rSubIncrementSeq
[ 0 ].IntervalCount
;
3111 rIntervalCount
.clear();
3115 rIntervalCount
<<= sal_Int32( 9 );
3117 else if( !bAutoMajor
&& !bAutoMinor
&& (0.0 < maData
.mfMinorStep
) && (maData
.mfMinorStep
<= maData
.mfMajorStep
) )
3119 double fCount
= maData
.mfMajorStep
/ maData
.mfMinorStep
+ 0.5;
3120 if( (1.0 <= fCount
) && (fCount
< 1001.0) )
3121 rIntervalCount
<<= static_cast< sal_Int32
>( fCount
);
3123 else if( bAutoMinor
)
3125 // tdf#114168 If minor unit is not set then set interval to 5, as MS Excel do.
3126 rIntervalCount
<<= static_cast< sal_Int32
>( 5 );
3130 bool bReverse
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
) != bMirrorOrient
;
3131 rScaleData
.Orientation
= bReverse
? cssc2::AxisOrientation_REVERSE
: cssc2::AxisOrientation_MATHEMATICAL
;
3134 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet
& rPropSet
) const
3136 bool bMaxCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
3137 bool bAutoCross
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
3138 bool bLogScale
= ::get_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
);
3140 // crossing mode (max-cross flag overrides other crossing settings)
3141 cssc::ChartAxisPosition eAxisPos
= bMaxCross
? cssc::ChartAxisPosition_END
: cssc::ChartAxisPosition_VALUE
;
3142 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERPOSITION
, eAxisPos
);
3144 // crossing position
3145 double fCrossingPos
= bAutoCross
? 0.0 : maData
.mfCross
;
3146 if( bLogScale
) fCrossingPos
= pow( 10.0, fCrossingPos
);
3147 rPropSet
.SetProperty( EXC_CHPROP_CROSSOVERVALUE
, fCrossingPos
);
3152 sal_Int32
lclGetApiTickmarks( sal_uInt8 nXclTickPos
)
3154 using namespace ::com::sun::star::chart2::TickmarkStyle
;
3155 sal_Int32 nApiTickmarks
= css::chart2::TickmarkStyle::NONE
;
3156 ::set_flag( nApiTickmarks
, INNER
, ::get_flag( nXclTickPos
, EXC_CHTICK_INSIDE
) );
3157 ::set_flag( nApiTickmarks
, OUTER
, ::get_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
) );
3158 return nApiTickmarks
;
3161 cssc::ChartAxisLabelPosition
lclGetApiLabelPosition( sal_Int8 nXclLabelPos
)
3163 using namespace ::com::sun::star::chart
;
3164 switch( nXclLabelPos
)
3166 case EXC_CHTICK_LOW
: return ChartAxisLabelPosition_OUTSIDE_START
;
3167 case EXC_CHTICK_HIGH
: return ChartAxisLabelPosition_OUTSIDE_END
;
3168 case EXC_CHTICK_NEXT
: return ChartAxisLabelPosition_NEAR_AXIS
;
3170 return ChartAxisLabelPosition_NEAR_AXIS
;
3175 XclImpChTick::XclImpChTick( const XclImpChRoot
& rRoot
) :
3176 XclImpChRoot( rRoot
)
3180 void XclImpChTick::ReadChTick( XclImpStream
& rStrm
)
3182 maData
.mnMajor
= rStrm
.ReaduInt8();
3183 maData
.mnMinor
= rStrm
.ReaduInt8();
3184 maData
.mnLabelPos
= rStrm
.ReaduInt8();
3185 maData
.mnBackMode
= rStrm
.ReaduInt8();
3187 rStrm
>> maData
.maTextColor
;
3188 maData
.mnFlags
= rStrm
.ReaduInt16();
3190 if( GetBiff() == EXC_BIFF8
)
3192 // BIFF8: index into palette used instead of RGB data
3193 maData
.maTextColor
= GetPalette().GetColor( rStrm
.ReaduInt16() );
3195 maData
.mnRotation
= rStrm
.ReaduInt16();
3199 // BIFF2-BIFF7: get rotation from text orientation
3200 sal_uInt8 nOrient
= ::extract_value
< sal_uInt8
>( maData
.mnFlags
, 2, 3 );
3201 maData
.mnRotation
= XclTools::GetXclRotFromOrient( nOrient
);
3205 Color
XclImpChTick::GetFontColor() const
3207 return ::get_flag( maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
) ? GetFontAutoColor() : maData
.maTextColor
;
3210 sal_uInt16
XclImpChTick::GetRotation() const
3212 /* n#720443: Ignore auto-rotation if there is a suggested rotation.
3213 * Better fix would be to improve our axis auto rotation algorithm.
3215 if( maData
.mnRotation
!= EXC_ROT_NONE
)
3216 return maData
.mnRotation
;
3217 return ::get_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
) ? EXC_CHART_AUTOROTATION
: maData
.mnRotation
;
3220 void XclImpChTick::Convert( ScfPropertySet
& rPropSet
) const
3222 rPropSet
.SetProperty( EXC_CHPROP_MAJORTICKS
, lclGetApiTickmarks( maData
.mnMajor
) );
3223 rPropSet
.SetProperty( EXC_CHPROP_MINORTICKS
, lclGetApiTickmarks( maData
.mnMinor
) );
3224 rPropSet
.SetProperty( EXC_CHPROP_LABELPOSITION
, lclGetApiLabelPosition( maData
.mnLabelPos
) );
3225 rPropSet
.SetProperty( EXC_CHPROP_MARKPOSITION
, cssc::ChartAxisMarkPosition_AT_AXIS
);
3228 XclImpChAxis::XclImpChAxis( const XclImpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
3229 XclImpChRoot( rRoot
),
3230 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
3232 maData
.mnType
= nAxisType
;
3235 void XclImpChAxis::ReadHeaderRecord( XclImpStream
& rStrm
)
3237 maData
.mnType
= rStrm
.ReaduInt16();
3240 void XclImpChAxis::ReadSubRecord( XclImpStream
& rStrm
)
3242 switch( rStrm
.GetRecId() )
3244 case EXC_ID_CHLABELRANGE
:
3245 mxLabelRange
.reset( new XclImpChLabelRange( GetChRoot() ) );
3246 mxLabelRange
->ReadChLabelRange( rStrm
);
3248 case EXC_ID_CHDATERANGE
:
3250 mxLabelRange
.reset( new XclImpChLabelRange( GetChRoot() ) );
3251 mxLabelRange
->ReadChDateRange( rStrm
);
3253 case EXC_ID_CHVALUERANGE
:
3254 mxValueRange
.reset( new XclImpChValueRange( GetChRoot() ) );
3255 mxValueRange
->ReadChValueRange( rStrm
);
3257 case EXC_ID_CHFORMAT
:
3258 mnNumFmtIdx
= rStrm
.ReaduInt16();
3261 mxTick
.reset( new XclImpChTick( GetChRoot() ) );
3262 mxTick
->ReadChTick( rStrm
);
3265 mxFont
.reset( new XclImpChFont
);
3266 mxFont
->ReadChFont( rStrm
);
3268 case EXC_ID_CHAXISLINE
:
3269 ReadChAxisLine( rStrm
);
3274 void XclImpChAxis::Finalize()
3276 // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3278 mxLabelRange
.reset( new XclImpChLabelRange( GetChRoot() ) );
3280 mxValueRange
.reset( new XclImpChValueRange( GetChRoot() ) );
3281 // remove invisible grid lines completely
3282 if( mxMajorGrid
&& !mxMajorGrid
->HasLine() )
3283 mxMajorGrid
.reset();
3284 if( mxMinorGrid
&& !mxMinorGrid
->HasLine() )
3285 mxMinorGrid
.reset();
3286 // default tick settings different in OOChart and Excel
3288 mxTick
.reset( new XclImpChTick( GetChRoot() ) );
3289 // #i4140# different default axis line color
3292 XclChLineFormat aLineFmt
;
3293 // set "show axis" flag, default if line format record is missing
3294 ::set_flag( aLineFmt
.mnFlags
, EXC_CHLINEFORMAT_SHOWAXIS
);
3295 mxAxisLine
.reset( new XclImpChLineFormat( aLineFmt
) );
3297 // add wall/floor frame for 3d charts
3302 sal_uInt16
XclImpChAxis::GetFontIndex() const
3304 return mxFont
? mxFont
->GetFontIndex() : EXC_FONT_NOTFOUND
;
3307 Color
XclImpChAxis::GetFontColor() const
3309 return mxTick
? mxTick
->GetFontColor() : GetFontAutoColor();
3312 sal_uInt16
XclImpChAxis::GetRotation() const
3314 return mxTick
? mxTick
->GetRotation() : EXC_CHART_AUTOROTATION
;
3317 Reference
< XAxis
> XclImpChAxis::CreateAxis( const XclImpChTypeGroup
& rTypeGroup
, const XclImpChAxis
* pCrossingAxis
) const
3319 // create the axis object (always)
3320 Reference
< XAxis
> xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS
), UNO_QUERY
);
3323 ScfPropertySet
aAxisProp( xAxis
);
3324 // #i58688# axis enabled
3325 aAxisProp
.SetBoolProperty( EXC_CHPROP_SHOW
, !mxAxisLine
|| mxAxisLine
->IsShowAxis() );
3327 // axis line properties
3329 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
3330 // axis ticks properties
3332 mxTick
->Convert( aAxisProp
);
3334 // axis caption text --------------------------------------------------
3336 // radar charts disable their category labels via chart type, not via axis
3337 bool bHasLabels
= (!mxTick
|| mxTick
->HasLabels()) &&
3338 ((GetAxisType() != EXC_CHAXIS_X
) || rTypeGroup
.HasCategoryLabels());
3339 aAxisProp
.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS
, bHasLabels
);
3342 // font settings from CHFONT record or from default text
3344 ConvertFontBase( GetChRoot(), aAxisProp
);
3345 else if( const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL
) )
3346 pDefText
->ConvertFont( aAxisProp
);
3347 // label text rotation
3348 ConvertRotationBase( aAxisProp
, true );
3350 bool bLinkNumberFmtToSource
= true;
3351 if ( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3353 sal_uInt32 nScNumFmt
= GetNumFmtBuffer().GetScFormat( mnNumFmtIdx
);
3354 if( nScNumFmt
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
3356 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT
, static_cast< sal_Int32
>( nScNumFmt
) );
3357 bLinkNumberFmtToSource
= false;
3361 aAxisProp
.SetProperty( EXC_CHPROP_NUMBERFORMAT_LINKSRC
, bLinkNumberFmtToSource
);
3364 // axis scaling and increment -----------------------------------------
3366 const XclChExtTypeInfo
& rTypeInfo
= rTypeGroup
.GetTypeInfo();
3367 ScaleData aScaleData
= xAxis
->getScaleData();
3369 switch( GetAxisType() )
3372 if( rTypeInfo
.mbCategoryAxis
)
3374 aScaleData
.AxisType
= cssc2::AxisType::CATEGORY
;
3375 aScaleData
.Categories
= rTypeGroup
.CreateCategSequence();
3378 aScaleData
.AxisType
= cssc2::AxisType::REALNUMBER
;
3381 aScaleData
.AxisType
= rTypeGroup
.IsPercent() ?
3382 cssc2::AxisType::PERCENT
: cssc2::AxisType::REALNUMBER
;
3385 aScaleData
.AxisType
= cssc2::AxisType::SERIES
;
3388 // axis scaling settings, dependent on axis type
3389 switch( aScaleData
.AxisType
)
3391 case cssc2::AxisType::CATEGORY
:
3392 case cssc2::AxisType::SERIES
:
3393 // #i71684# radar charts have reversed rotation direction
3395 mxLabelRange
->Convert( aAxisProp
, aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
);
3397 SAL_WARN("sc.filter", "missing LabelRange");
3399 case cssc2::AxisType::REALNUMBER
:
3400 case cssc2::AxisType::PERCENT
:
3401 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3403 mxValueRange
->Convert( aScaleData
, rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3405 SAL_WARN("sc.filter", "missing ValueRange");
3408 OSL_FAIL( "XclImpChAxis::CreateAxis - unknown axis type" );
3411 /* Do not set a value to the Origin member anymore (will be done via
3412 new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3413 aScaleData
.Origin
.clear();
3416 xAxis
->setScaleData( aScaleData
);
3418 // grid ---------------------------------------------------------------
3421 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3422 aGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMajorGrid
) );
3424 mxMajorGrid
->Convert( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3426 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3427 if( aSubGridPropSeq
.hasElements() )
3429 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3430 aSubGridProp
.SetBoolProperty( EXC_CHPROP_SHOW
, static_cast<bool>(mxMinorGrid
) );
3432 mxMinorGrid
->Convert( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3435 // position of crossing axis ------------------------------------------
3438 pCrossingAxis
->ConvertAxisPosition( aAxisProp
, rTypeGroup
);
3443 void XclImpChAxis::ConvertWall( ScfPropertySet
& rPropSet
) const
3445 // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3447 mxWallFrame
->Convert( rPropSet
, true );
3450 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet
& rPropSet
, const XclImpChTypeGroup
& rTypeGroup
) const
3452 if( ((GetAxisType() == EXC_CHAXIS_X
) && rTypeGroup
.GetTypeInfo().mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
) )
3455 mxLabelRange
->ConvertAxisPosition( rPropSet
, rTypeGroup
.Is3dChart() );
3457 SAL_WARN("sc.filter", "missing LabelRange");
3462 mxValueRange
->ConvertAxisPosition( rPropSet
);
3464 SAL_WARN("sc.filter", "missing ValueRange");
3468 void XclImpChAxis::ReadChAxisLine( XclImpStream
& rStrm
)
3470 XclImpChLineFormatRef
* pxLineFmt
= nullptr;
3471 bool bWallFrame
= false;
3472 switch( rStrm
.ReaduInt16() )
3474 case EXC_CHAXISLINE_AXISLINE
: pxLineFmt
= &mxAxisLine
; break;
3475 case EXC_CHAXISLINE_MAJORGRID
: pxLineFmt
= &mxMajorGrid
; break;
3476 case EXC_CHAXISLINE_MINORGRID
: pxLineFmt
= &mxMinorGrid
; break;
3477 case EXC_CHAXISLINE_WALLS
: bWallFrame
= true; break;
3482 bool bLoop
= pxLineFmt
|| bWallFrame
;
3485 sal_uInt16 nRecId
= rStrm
.GetNextRecId();
3486 bLoop
= ((nRecId
== EXC_ID_CHLINEFORMAT
) ||
3487 (nRecId
== EXC_ID_CHAREAFORMAT
) ||
3488 (nRecId
== EXC_ID_CHESCHERFORMAT
))
3489 && rStrm
.StartNextRecord();
3492 if( pxLineFmt
&& (nRecId
== EXC_ID_CHLINEFORMAT
) )
3494 pxLineFmt
->reset( new XclImpChLineFormat
);
3495 (*pxLineFmt
)->ReadChLineFormat( rStrm
);
3497 else if( bWallFrame
&& mxWallFrame
)
3499 mxWallFrame
->ReadSubRecord( rStrm
);
3505 void XclImpChAxis::CreateWallFrame()
3507 switch( GetAxisType() )
3510 mxWallFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D
) );
3513 mxWallFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D
) );
3516 mxWallFrame
.reset();
3520 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3521 XclImpChRoot( rRoot
)
3523 maData
.mnAxesSetId
= nAxesSetId
;
3526 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream
& rStrm
)
3528 maData
.mnAxesSetId
= rStrm
.ReaduInt16();
3529 rStrm
>> maData
.maRect
;
3532 void XclImpChAxesSet::ReadSubRecord( XclImpStream
& rStrm
)
3534 switch( rStrm
.GetRecId() )
3536 case EXC_ID_CHFRAMEPOS
:
3537 mxFramePos
.reset( new XclImpChFramePos
);
3538 mxFramePos
->ReadChFramePos( rStrm
);
3541 ReadChAxis( rStrm
);
3544 ReadChText( rStrm
);
3546 case EXC_ID_CHPLOTFRAME
:
3547 ReadChPlotFrame( rStrm
);
3549 case EXC_ID_CHTYPEGROUP
:
3550 ReadChTypeGroup( rStrm
);
3555 void XclImpChAxesSet::Finalize()
3557 if( IsValidAxesSet() )
3559 // finalize chart type groups, erase empty groups without series
3560 XclImpChTypeGroupMap aValidGroups
;
3561 for (auto const& typeGroup
: maTypeGroups
)
3563 XclImpChTypeGroupRef xTypeGroup
= typeGroup
.second
;
3564 xTypeGroup
->Finalize();
3565 if( xTypeGroup
->IsValidGroup() )
3566 aValidGroups
.emplace(typeGroup
.first
, xTypeGroup
);
3568 maTypeGroups
.swap( aValidGroups
);
3571 // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3572 if( IsValidAxesSet() )
3574 // always create missing axis objects
3576 mxXAxis
.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X
) );
3578 mxYAxis
.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y
) );
3579 if( !mxZAxis
&& GetFirstTypeGroup()->Is3dDeepChart() )
3580 mxZAxis
.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z
) );
3583 if( mxXAxis
) mxXAxis
->Finalize();
3584 if( mxYAxis
) mxYAxis
->Finalize();
3585 if( mxZAxis
) mxZAxis
->Finalize();
3587 // finalize axis titles
3588 const XclImpChText
* pDefText
= GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE
);
3589 OUString
aAutoTitle(ScResId(STR_AXISTITLE
));
3590 lclFinalizeTitle( mxXAxisTitle
, pDefText
, aAutoTitle
);
3591 lclFinalizeTitle( mxYAxisTitle
, pDefText
, aAutoTitle
);
3592 lclFinalizeTitle( mxZAxisTitle
, pDefText
, aAutoTitle
);
3594 // #i47745# missing plot frame -> invisible border and area
3596 mxPlotFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
) );
3600 XclImpChTypeGroupRef
XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3602 XclImpChTypeGroupMap::const_iterator itr
= maTypeGroups
.find(nGroupIdx
);
3603 return itr
== maTypeGroups
.end() ? XclImpChTypeGroupRef() : itr
->second
;
3606 XclImpChTypeGroupRef
XclImpChAxesSet::GetFirstTypeGroup() const
3608 XclImpChTypeGroupRef xTypeGroup
;
3609 if( !maTypeGroups
.empty() )
3610 xTypeGroup
= maTypeGroups
.begin()->second
;
3614 XclImpChLegendRef
XclImpChAxesSet::GetLegend() const
3616 XclImpChLegendRef xLegend
;
3617 for( const auto& rEntry
: maTypeGroups
)
3619 xLegend
= rEntry
.second
->GetLegend();
3626 OUString
XclImpChAxesSet::GetSingleSeriesTitle() const
3628 return (maTypeGroups
.size() == 1) ? maTypeGroups
.begin()->second
->GetSingleSeriesTitle() : OUString();
3631 void XclImpChAxesSet::Convert( Reference
< XDiagram
> const & xDiagram
) const
3633 if( IsValidAxesSet() && xDiagram
.is() )
3635 // diagram background formatting
3636 if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY
)
3637 ConvertBackground( xDiagram
);
3639 // create the coordinate system, this inserts all chart types and series
3640 Reference
< XCoordinateSystem
> xCoordSystem
= CreateCoordSystem( xDiagram
);
3641 if( xCoordSystem
.is() )
3643 // insert coordinate system, if not already done
3646 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY_THROW
);
3647 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3648 if( !aCoordSystems
.hasElements() )
3649 xCoordSystemCont
->addCoordinateSystem( xCoordSystem
);
3653 OSL_FAIL( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3656 // create the axes with grids and axis titles and insert them into the diagram
3657 ConvertAxis( mxXAxis
, mxXAxisTitle
, xCoordSystem
, mxYAxis
.get() );
3658 ConvertAxis( mxYAxis
, mxYAxisTitle
, xCoordSystem
, mxXAxis
.get() );
3659 ConvertAxis( mxZAxis
, mxZAxisTitle
, xCoordSystem
, nullptr );
3664 void XclImpChAxesSet::ConvertTitlePositions() const
3667 mxXAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_X
) );
3669 mxYAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Y
) );
3671 mxZAxisTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE
, maData
.mnAxesSetId
, EXC_CHAXIS_Z
) );
3674 void XclImpChAxesSet::ReadChAxis( XclImpStream
& rStrm
)
3676 XclImpChAxisRef
xAxis( new XclImpChAxis( GetChRoot() ) );
3677 xAxis
->ReadRecordGroup( rStrm
);
3679 switch( xAxis
->GetAxisType() )
3681 case EXC_CHAXIS_X
: mxXAxis
= xAxis
; break;
3682 case EXC_CHAXIS_Y
: mxYAxis
= xAxis
; break;
3683 case EXC_CHAXIS_Z
: mxZAxis
= xAxis
; break;
3687 void XclImpChAxesSet::ReadChText( XclImpStream
& rStrm
)
3689 XclImpChTextRef
xText( new XclImpChText( GetChRoot() ) );
3690 xText
->ReadRecordGroup( rStrm
);
3692 switch( xText
->GetLinkTarget() )
3694 case EXC_CHOBJLINK_XAXIS
: mxXAxisTitle
= xText
; break;
3695 case EXC_CHOBJLINK_YAXIS
: mxYAxisTitle
= xText
; break;
3696 case EXC_CHOBJLINK_ZAXIS
: mxZAxisTitle
= xText
; break;
3700 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream
& rStrm
)
3702 if( (rStrm
.GetNextRecId() == EXC_ID_CHFRAME
) && rStrm
.StartNextRecord() )
3704 mxPlotFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME
) );
3705 mxPlotFrame
->ReadRecordGroup( rStrm
);
3709 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream
& rStrm
)
3711 XclImpChTypeGroupRef
xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
3712 xTypeGroup
->ReadRecordGroup( rStrm
);
3713 sal_uInt16 nGroupIdx
= xTypeGroup
->GetGroupIdx();
3714 XclImpChTypeGroupMap::iterator itr
= maTypeGroups
.lower_bound(nGroupIdx
);
3715 if (itr
!= maTypeGroups
.end() && !maTypeGroups
.key_comp()(nGroupIdx
, itr
->first
))
3716 // Overwrite the existing element.
3717 itr
->second
= xTypeGroup
;
3719 maTypeGroups
.insert(
3720 itr
, XclImpChTypeGroupMap::value_type(nGroupIdx
, xTypeGroup
));
3723 Reference
< XCoordinateSystem
> XclImpChAxesSet::CreateCoordSystem( Reference
< XDiagram
> const & xDiagram
) const
3725 Reference
< XCoordinateSystem
> xCoordSystem
;
3727 /* Try to get existing coordinate system. For now, all series from primary
3728 and secondary axes sets are inserted into one coordinate system. Later,
3729 this should be changed to use one coordinate system for each axes set. */
3730 Reference
< XCoordinateSystemContainer
> xCoordSystemCont( xDiagram
, UNO_QUERY
);
3731 if( xCoordSystemCont
.is() )
3733 Sequence
< Reference
< XCoordinateSystem
> > aCoordSystems
= xCoordSystemCont
->getCoordinateSystems();
3734 OSL_ENSURE( aCoordSystems
.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3735 if( aCoordSystems
.hasElements() )
3736 xCoordSystem
= aCoordSystems
[ 0 ];
3739 // create the coordinate system according to the first chart type
3740 if( !xCoordSystem
.is() )
3742 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3745 xCoordSystem
= xTypeGroup
->CreateCoordSystem();
3746 // convert 3d chart settings
3747 ScfPropertySet
aDiaProp( xDiagram
);
3748 xTypeGroup
->ConvertChart3d( aDiaProp
);
3752 /* Create XChartType objects for all chart type groups. Each group will
3753 add its series to the data provider attached to the chart document. */
3754 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3755 if( xChartTypeCont
.is() )
3757 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3758 for( const auto& rEntry
: maTypeGroups
)
3762 Reference
< XChartType
> xChartType
= rEntry
.second
->CreateChartType( xDiagram
, nApiAxesSetIdx
);
3763 if( xChartType
.is() )
3764 xChartTypeCont
->addChartType( xChartType
);
3768 OSL_FAIL( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3773 return xCoordSystem
;
3776 void XclImpChAxesSet::ConvertAxis(
3777 XclImpChAxisRef
const & xChAxis
, XclImpChTextRef
const & xChAxisTitle
,
3778 Reference
< XCoordinateSystem
> const & xCoordSystem
, const XclImpChAxis
* pCrossingAxis
) const
3782 // create and attach the axis object
3783 Reference
< XAxis
> xAxis
= CreateAxis( *xChAxis
, pCrossingAxis
);
3786 // create and attach the axis title
3787 if( xChAxisTitle
) try
3789 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY_THROW
);
3790 Reference
< XTitle
> xTitle( xChAxisTitle
->CreateTitle(), UNO_SET_THROW
);
3791 xTitled
->setTitleObject( xTitle
);
3795 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3798 // insert axis into coordinate system
3801 sal_Int32 nApiAxisDim
= xChAxis
->GetApiAxisDimension();
3802 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3803 xCoordSystem
->setAxisByDimension( nApiAxisDim
, xAxis
, nApiAxesSetIdx
);
3807 OSL_FAIL( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3813 Reference
< XAxis
> XclImpChAxesSet::CreateAxis( const XclImpChAxis
& rChAxis
, const XclImpChAxis
* pCrossingAxis
) const
3815 Reference
< XAxis
> xAxis
;
3816 if( const XclImpChTypeGroup
* pTypeGroup
= GetFirstTypeGroup().get() )
3817 xAxis
= rChAxis
.CreateAxis( *pTypeGroup
, pCrossingAxis
);
3821 void XclImpChAxesSet::ConvertBackground( Reference
< XDiagram
> const & xDiagram
) const
3823 XclImpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3824 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3826 // wall/floor formatting (3D charts)
3829 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3830 mxXAxis
->ConvertWall( aWallProp
);
3834 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3835 mxYAxis
->ConvertWall( aFloorProp
);
3838 else if( mxPlotFrame
)
3840 // diagram background formatting
3841 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3842 mxPlotFrame
->Convert( aWallProp
);
3846 // The chart object ===========================================================
3848 XclImpChChart::XclImpChChart( const XclImpRoot
& rRoot
) :
3849 XclImpChRoot( rRoot
, *this )
3851 mxPrimAxesSet
.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY
) );
3852 mxSecnAxesSet
.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY
) );
3855 XclImpChChart::~XclImpChChart()
3859 void XclImpChChart::ReadHeaderRecord( XclImpStream
& rStrm
)
3861 // coordinates are stored as 16.16 fixed point
3865 void XclImpChChart::ReadSubRecord( XclImpStream
& rStrm
)
3867 switch( rStrm
.GetRecId() )
3869 case EXC_ID_CHFRAME
:
3870 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
) );
3871 mxFrame
->ReadRecordGroup( rStrm
);
3873 case EXC_ID_CHSERIES
:
3874 ReadChSeries( rStrm
);
3876 case EXC_ID_CHPROPERTIES
:
3877 ReadChProperties( rStrm
);
3879 case EXC_ID_CHDEFAULTTEXT
:
3880 ReadChDefaultText( rStrm
);
3882 case EXC_ID_CHAXESSET
:
3883 ReadChAxesSet( rStrm
);
3886 ReadChText( rStrm
);
3889 Finalize(); // finalize the entire chart object
3894 void XclImpChChart::ReadChDefaultText( XclImpStream
& rStrm
)
3896 sal_uInt16 nTextId
= rStrm
.ReaduInt16();
3897 if( (rStrm
.GetNextRecId() == EXC_ID_CHTEXT
) && rStrm
.StartNextRecord() )
3899 unique_ptr
<XclImpChText
> pText(new XclImpChText(GetChRoot()));
3900 pText
->ReadRecordGroup(rStrm
);
3901 m_DefTexts
.insert(std::make_pair(nTextId
, std::move(pText
)));
3905 void XclImpChChart::ReadChDataFormat( XclImpStream
& rStrm
)
3907 XclImpChDataFormatRef
xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
3908 xDataFmt
->ReadRecordGroup( rStrm
);
3909 if( xDataFmt
->GetPointPos().mnSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3911 const XclChDataPointPos
& rPos
= xDataFmt
->GetPointPos();
3912 XclImpChDataFormatMap::iterator itr
= maDataFmts
.lower_bound(rPos
);
3913 if (itr
== maDataFmts
.end() || maDataFmts
.key_comp()(rPos
, itr
->first
))
3914 // No element exists for this data point. Insert it.
3916 itr
, XclImpChDataFormatMap::value_type(rPos
, xDataFmt
));
3918 /* Do not overwrite existing data format group, Excel always uses the
3919 first data format group occurring in any CHSERIES group. */
3923 void XclImpChChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
3926 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
) );
3927 mxFrame
->UpdateObjFrame( rLineData
, rFillData
);
3930 XclImpChTypeGroupRef
XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx
) const
3932 XclImpChTypeGroupRef xTypeGroup
= mxPrimAxesSet
->GetTypeGroup( nGroupIdx
);
3933 if( !xTypeGroup
) xTypeGroup
= mxSecnAxesSet
->GetTypeGroup( nGroupIdx
);
3934 if( !xTypeGroup
) xTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup();
3938 const XclImpChText
* XclImpChChart::GetDefaultText( XclChTextType eTextType
) const
3940 sal_uInt16 nDefTextId
= EXC_CHDEFTEXT_GLOBAL
;
3941 bool bBiff8
= GetBiff() == EXC_BIFF8
;
3944 case EXC_CHTEXTTYPE_TITLE
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3945 case EXC_CHTEXTTYPE_LEGEND
: nDefTextId
= EXC_CHDEFTEXT_GLOBAL
; break;
3946 case EXC_CHTEXTTYPE_AXISTITLE
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3947 case EXC_CHTEXTTYPE_AXISLABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3948 case EXC_CHTEXTTYPE_DATALABEL
: nDefTextId
= bBiff8
? EXC_CHDEFTEXT_AXESSET
: EXC_CHDEFTEXT_GLOBAL
; break;
3951 XclImpChTextMap::const_iterator
const itr
= m_DefTexts
.find(nDefTextId
);
3952 return itr
== m_DefTexts
.end() ? nullptr : itr
->second
.get();
3955 bool XclImpChChart::IsManualPlotArea() const
3957 // there is no real automatic mode in BIFF5 charts
3958 return (GetBiff() <= EXC_BIFF5
) || ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3961 void XclImpChChart::Convert( const Reference
<XChartDocument
>& xChartDoc
,
3962 XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
3964 // initialize conversion (locks the model to suppress any internal updates)
3965 InitConversion( xChartDoc
, rChartRect
);
3967 // chart frame formatting
3970 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3971 mxFrame
->Convert( aFrameProp
);
3977 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY_THROW
);
3978 Reference
< XTitle
> xTitle( mxTitle
->CreateTitle(), UNO_SET_THROW
);
3979 xTitled
->setTitleObject( xTitle
);
3985 /* Create the diagram object and attach it to the chart document. Currently,
3986 one diagram is used to carry all coordinate systems and data series. */
3987 Reference
< XDiagram
> xDiagram
= CreateDiagram();
3988 xChartDoc
->setFirstDiagram( xDiagram
);
3990 // coordinate systems and chart types, convert axis settings
3991 mxPrimAxesSet
->Convert( xDiagram
);
3992 mxSecnAxesSet
->Convert( xDiagram
);
3995 if( xDiagram
.is() && mxLegend
)
3996 xDiagram
->setLegend( mxLegend
->CreateLegend() );
3998 /* Following all conversions needing the old Chart1 API that involves full
3999 initialization of the chart view. */
4000 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY
);
4001 if( xChart1Doc
.is() )
4003 Reference
< cssc::XDiagram
> xDiagram1
= xChart1Doc
->getDiagram();
4005 /* Set the 'IncludeHiddenCells' property via the old API as only this
4006 ensures that the data provider and all created sequences get this
4008 ScfPropertySet
aDiaProp( xDiagram1
);
4009 bool bShowVisCells
= ::get_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
);
4010 aDiaProp
.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
, !bShowVisCells
);
4012 // plot area position and size (there is no real automatic mode in BIFF5 charts)
4013 XclImpChFramePosRef xPlotAreaPos
= mxPrimAxesSet
->GetPlotAreaFramePos();
4014 if( IsManualPlotArea() && xPlotAreaPos
) try
4016 const XclChFramePos
& rFramePos
= xPlotAreaPos
->GetFramePosData();
4017 if( (rFramePos
.mnTLMode
== EXC_CHFRAMEPOS_PARENT
) && (rFramePos
.mnBRMode
== EXC_CHFRAMEPOS_PARENT
) )
4019 Reference
< cssc::XDiagramPositioning
> xPositioning( xDiagram1
, UNO_QUERY_THROW
);
4020 css::awt::Rectangle aDiagramRect
= CalcHmmFromChartRect( rFramePos
.maRect
);
4021 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
4022 const XclImpChTypeGroup
* pFirstTypeGroup
= mxPrimAxesSet
->GetFirstTypeGroup().get();
4023 if( pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
4024 xPositioning
->setDiagramPositionExcludingAxes( aDiagramRect
);
4025 else if( pFirstTypeGroup
&& pFirstTypeGroup
->Is3dChart() )
4026 xPositioning
->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect
);
4028 xPositioning
->setDiagramPositionIncludingAxes( aDiagramRect
);
4035 // positions of all title objects
4037 mxTitle
->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE
) );
4038 mxPrimAxesSet
->ConvertTitlePositions();
4039 mxSecnAxesSet
->ConvertTitlePositions();
4043 FinishConversion( rDffConv
);
4045 // start listening to this chart
4046 ScDocument
& rDoc
= GetRoot().GetDoc();
4047 if( ScChartListenerCollection
* pChartCollection
= rDoc
.GetChartListenerCollection() )
4049 ::std::unique_ptr
< ::std::vector
< ScTokenRef
> > xRefTokens( new ::std::vector
< ScTokenRef
> );
4050 for( const auto& rxSeries
: maSeries
)
4051 rxSeries
->FillAllSourceLinks( *xRefTokens
);
4052 if( !xRefTokens
->empty() )
4054 ::std::unique_ptr
< ScChartListener
> xListener( new ScChartListener( rObjName
, &rDoc
, std::move(xRefTokens
) ) );
4055 xListener
->SetUsed( true );
4056 xListener
->StartListeningTo();
4057 pChartCollection
->insert( xListener
.release() );
4062 void XclImpChChart::ReadChSeries( XclImpStream
& rStrm
)
4064 sal_uInt16 nNewSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.size() );
4065 XclImpChSeriesRef
xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx
) );
4066 xSeries
->ReadRecordGroup( rStrm
);
4067 maSeries
.push_back( xSeries
);
4070 void XclImpChChart::ReadChProperties( XclImpStream
& rStrm
)
4072 maProps
.mnFlags
= rStrm
.ReaduInt16();
4073 maProps
.mnEmptyMode
= rStrm
.ReaduInt8();
4076 void XclImpChChart::ReadChAxesSet( XclImpStream
& rStrm
)
4078 XclImpChAxesSetRef
xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE
) );
4079 xAxesSet
->ReadRecordGroup( rStrm
);
4080 switch( xAxesSet
->GetAxesSetId() )
4082 case EXC_CHAXESSET_PRIMARY
: mxPrimAxesSet
= xAxesSet
; break;
4083 case EXC_CHAXESSET_SECONDARY
: mxSecnAxesSet
= xAxesSet
; break;
4087 void XclImpChChart::ReadChText( XclImpStream
& rStrm
)
4089 XclImpChTextRef
xText( new XclImpChText( GetChRoot() ) );
4090 xText
->ReadRecordGroup( rStrm
);
4091 switch( xText
->GetLinkTarget() )
4093 case EXC_CHOBJLINK_TITLE
:
4096 case EXC_CHOBJLINK_DATA
:
4098 sal_uInt16 nSeriesIdx
= xText
->GetPointPos().mnSeriesIdx
;
4099 if( nSeriesIdx
< maSeries
.size() )
4100 maSeries
[ nSeriesIdx
]->SetDataLabel( xText
);
4106 void XclImpChChart::Finalize()
4108 // finalize series (must be done first)
4110 // #i49218# legend may be attached to primary or secondary axes set
4111 mxLegend
= mxPrimAxesSet
->GetLegend();
4113 mxLegend
= mxSecnAxesSet
->GetLegend();
4115 mxLegend
->Finalize();
4116 // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
4117 mxPrimAxesSet
->Finalize();
4118 mxSecnAxesSet
->Finalize();
4119 // formatting of all series
4120 FinalizeDataFormats();
4121 // #i47745# missing frame -> invisible border and area
4123 mxFrame
.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND
) );
4128 void XclImpChChart::FinalizeSeries()
4130 for( const XclImpChSeriesRef
& xSeries
: maSeries
)
4132 if( xSeries
->HasParentSeries() )
4134 /* Process child series (trend lines and error bars). Data of
4135 child series will be set at the connected parent series. */
4136 if( xSeries
->GetParentIdx() < maSeries
.size() )
4137 maSeries
[ xSeries
->GetParentIdx() ]->AddChildSeries( *xSeries
);
4141 // insert the series into the related chart type group
4142 if( XclImpChTypeGroup
* pTypeGroup
= GetTypeGroup( xSeries
->GetGroupIdx() ).get() )
4143 pTypeGroup
->AddSeries( xSeries
);
4148 void XclImpChChart::FinalizeDataFormats()
4150 /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4151 Each CHDATAFORMAT group specifies the series and data point it is
4152 assigned to. This makes it possible to have a data format that is
4153 related to another series, e.g. a CHDATAFORMAT group for series 2 is
4154 part of a CHSERIES group that describes series 1. Therefore the chart
4155 itself has collected all CHDATAFORMAT groups to be able to store data
4156 format groups for series that have not been imported at that time. This
4157 loop finally assigns these groups to the related series. */
4158 for( const auto& [rPos
, rDataFmt
] : maDataFmts
)
4160 sal_uInt16 nSeriesIdx
= rPos
.mnSeriesIdx
;
4161 if( nSeriesIdx
< maSeries
.size() )
4162 maSeries
[ nSeriesIdx
]->SetDataFormat( rDataFmt
);
4165 /* #i51639# (part 2): Finalize data formats of all series. This adds for
4166 example missing CHDATAFORMAT groups for entire series that are needed
4167 for automatic colors of lines and areas. */
4168 for( auto& rxSeries
: maSeries
)
4169 rxSeries
->FinalizeDataFormats();
4172 void XclImpChChart::FinalizeTitle()
4174 // special handling for auto-generated title
4175 OUString aAutoTitle
;
4176 if( !mxTitle
|| (!mxTitle
->IsDeleted() && !mxTitle
->HasString()) )
4178 // automatic title from first series name (if there are no series on secondary axes set)
4179 if( !mxSecnAxesSet
->IsValidAxesSet() )
4180 aAutoTitle
= mxPrimAxesSet
->GetSingleSeriesTitle();
4181 if( mxTitle
|| (!aAutoTitle
.isEmpty()) )
4184 mxTitle
.reset( new XclImpChText( GetChRoot() ) );
4185 if( aAutoTitle
.isEmpty() )
4186 aAutoTitle
= ScResId(STR_CHARTTITLE
);
4190 // will reset mxTitle, if it does not contain a string and no auto title exists
4191 lclFinalizeTitle( mxTitle
, GetDefaultText( EXC_CHTEXTTYPE_TITLE
), aAutoTitle
);
4194 Reference
< XDiagram
> XclImpChChart::CreateDiagram() const
4196 // create a diagram object
4197 Reference
< XDiagram
> xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM
), UNO_QUERY
);
4199 // convert global chart settings
4200 ScfPropertySet
aDiaProp( xDiagram
);
4202 // treatment of missing values
4203 using namespace cssc::MissingValueTreatment
;
4204 sal_Int32 nMissingValues
= LEAVE_GAP
;
4205 switch( maProps
.mnEmptyMode
)
4207 case EXC_CHPROPS_EMPTY_SKIP
: nMissingValues
= LEAVE_GAP
; break;
4208 case EXC_CHPROPS_EMPTY_ZERO
: nMissingValues
= USE_ZERO
; break;
4209 case EXC_CHPROPS_EMPTY_INTERPOLATE
: nMissingValues
= CONTINUE
; break;
4211 aDiaProp
.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT
, nMissingValues
);
4216 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4217 XclImpDrawing( rRoot
, bOwnTab
), // sheet charts may contain OLE objects
4218 mnScTab( rRoot
.GetCurrScTab() ),
4223 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter
& rDffConv
,
4224 const Reference
< XModel
>& rxModel
, const tools::Rectangle
& rChartRect
)
4226 maChartRect
= rChartRect
; // needed in CalcAnchorRect() callback
4228 SdrModel
* pSdrModel
= nullptr;
4229 SdrPage
* pSdrPage
= nullptr;
4232 // chart sheet: insert all shapes into the sheet, not into the chart object
4233 pSdrModel
= GetDoc().GetDrawLayer();
4234 pSdrPage
= GetSdrPage( mnScTab
);
4238 // embedded chart object: insert all shapes into the chart
4241 Reference
< XDrawPageSupplier
> xDrawPageSupp( rxModel
, UNO_QUERY_THROW
);
4242 Reference
< XDrawPage
> xDrawPage( xDrawPageSupp
->getDrawPage(), UNO_SET_THROW
);
4243 pSdrPage
= ::GetSdrPageFromXDrawPage( xDrawPage
);
4244 pSdrModel
= pSdrPage
? &pSdrPage
->getSdrModelFromSdrPage() : nullptr;
4251 if( pSdrModel
&& pSdrPage
)
4252 ImplConvertObjects( rDffConv
, *pSdrModel
, *pSdrPage
);
4255 tools::Rectangle
XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor
& rAnchor
, bool bDffAnchor
) const
4257 /* In objects with DFF client anchor, the position of the shape is stored
4258 in the cell address components of the client anchor. In old BIFF3-BIFF5
4259 objects, the position is stored in the offset components of the anchor. */
4260 tools::Rectangle
aRect(
4261 static_cast< long >( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnCol
: rAnchor
.mnLX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4262 static_cast< long >( static_cast< double >( bDffAnchor
? rAnchor
.maFirst
.mnRow
: rAnchor
.mnTY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ),
4263 static_cast< long >( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnCol
: rAnchor
.mnRX
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetWidth() + 0.5 ),
4264 static_cast< long >( static_cast< double >( bDffAnchor
? rAnchor
.maLast
.mnRow
: rAnchor
.mnBY
) / EXC_CHART_TOTALUNITS
* maChartRect
.GetHeight() + 0.5 ) );
4266 // move shapes into chart area for sheet charts
4268 aRect
.Move( maChartRect
.Left(), maChartRect
.Top() );
4272 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase
& )
4276 XclImpChart::XclImpChart( const XclImpRoot
& rRoot
, bool bOwnTab
) :
4277 XclImpRoot( rRoot
),
4278 mbOwnTab( bOwnTab
),
4279 mbIsPivotChart( false )
4283 XclImpChart::~XclImpChart()
4287 void XclImpChart::ReadChartSubStream( XclImpStream
& rStrm
)
4289 XclImpPageSettings
& rPageSett
= GetPageSettings();
4290 XclImpTabViewSettings
& rTabViewSett
= GetTabViewSettings();
4293 while( bLoop
&& rStrm
.StartNextRecord() )
4295 // page settings - only for charts in entire sheet
4296 if( mbOwnTab
) switch( rStrm
.GetRecId() )
4298 case EXC_ID_HORPAGEBREAKS
:
4299 case EXC_ID_VERPAGEBREAKS
: rPageSett
.ReadPageBreaks( rStrm
); break;
4301 case EXC_ID_FOOTER
: rPageSett
.ReadHeaderFooter( rStrm
); break;
4302 case EXC_ID_LEFTMARGIN
:
4303 case EXC_ID_RIGHTMARGIN
:
4304 case EXC_ID_TOPMARGIN
:
4305 case EXC_ID_BOTTOMMARGIN
: rPageSett
.ReadMargin( rStrm
); break;
4306 case EXC_ID_PRINTHEADERS
: rPageSett
.ReadPrintHeaders( rStrm
); break;
4307 case EXC_ID_PRINTGRIDLINES
: rPageSett
.ReadPrintGridLines( rStrm
); break;
4308 case EXC_ID_HCENTER
:
4309 case EXC_ID_VCENTER
: rPageSett
.ReadCenter( rStrm
); break;
4310 case EXC_ID_SETUP
: rPageSett
.ReadSetup( rStrm
); break;
4311 case EXC_ID8_IMGDATA
: rPageSett
.ReadImgData( rStrm
); break;
4313 case EXC_ID_WINDOW2
: rTabViewSett
.ReadWindow2( rStrm
, true );break;
4314 case EXC_ID_SCL
: rTabViewSett
.ReadScl( rStrm
); break;
4316 case EXC_ID_SHEETEXT
: //0x0862
4318 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4319 XclImpPalette
& rPal
= GetPalette();
4320 rTabViewSett
.ReadTabBgColor( rStrm
, rPal
);
4324 case EXC_ID_CODENAME
: ReadCodeName( rStrm
, false ); break;
4328 switch( rStrm
.GetRecId() )
4330 case EXC_ID_EOF
: bLoop
= false; break;
4332 // #i31882# ignore embedded chart objects
4336 case EXC_ID5_BOF
: XclTools::SkipSubStream( rStrm
); break;
4338 case EXC_ID_CHCHART
: ReadChChart( rStrm
); break;
4340 case EXC_ID8_CHPIVOTREF
:
4341 GetTracer().TracePivotChartExists();
4342 mbIsPivotChart
= true;
4345 // BIFF specific records
4346 default: switch( GetBiff() )
4348 case EXC_BIFF5
: switch( rStrm
.GetRecId() )
4350 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4353 case EXC_BIFF8
: switch( rStrm
.GetRecId() )
4355 case EXC_ID_MSODRAWING
: GetChartDrawing().ReadMsoDrawing( rStrm
); break;
4356 // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4357 case EXC_ID_OBJ
: GetChartDrawing().ReadObj( rStrm
); break;
4366 void XclImpChart::UpdateObjFrame( const XclObjLineData
& rLineData
, const XclObjFillData
& rFillData
)
4369 mxChartData
.reset( new XclImpChChart( GetRoot() ) );
4370 mxChartData
->UpdateObjFrame( rLineData
, rFillData
);
4373 std::size_t XclImpChart::GetProgressSize() const
4376 (mxChartData
? XclImpChChart::GetProgressSize() : 0) +
4377 (mxChartDrawing
? mxChartDrawing
->GetProgressSize() : 0);
4380 void XclImpChart::Convert( Reference
< XModel
> const & xModel
, XclImpDffConverter
& rDffConv
, const OUString
& rObjName
, const tools::Rectangle
& rChartRect
) const
4382 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
4383 if( xChartDoc
.is() )
4386 mxChartData
->Convert( xChartDoc
, rDffConv
, rObjName
, rChartRect
);
4387 if( mxChartDrawing
)
4388 mxChartDrawing
->ConvertObjects( rDffConv
, xModel
, rChartRect
);
4392 XclImpChartDrawing
& XclImpChart::GetChartDrawing()
4394 if( !mxChartDrawing
)
4395 mxChartDrawing
.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab
) );
4396 return *mxChartDrawing
;
4399 void XclImpChart::ReadChChart( XclImpStream
& rStrm
)
4401 mxChartData
.reset( new XclImpChChart( GetRoot() ) );
4402 mxChartData
->ReadRecordGroup( rStrm
);
4405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */