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 <xechart.hxx>
22 #include <com/sun/star/i18n/XBreakIterator.hpp>
23 #include <com/sun/star/i18n/ScriptType.hpp>
24 #include <com/sun/star/drawing/FillStyle.hpp>
25 #include <com/sun/star/drawing/XShapes.hpp>
26 #include <com/sun/star/chart/XChartDocument.hpp>
27 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
28 #include <com/sun/star/chart/ChartAxisPosition.hpp>
29 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
30 #include <com/sun/star/chart/DataLabelPlacement.hpp>
31 #include <com/sun/star/chart/ErrorBarStyle.hpp>
32 #include <com/sun/star/chart/MissingValueTreatment.hpp>
33 #include <com/sun/star/chart/TimeInterval.hpp>
34 #include <com/sun/star/chart/TimeUnit.hpp>
35 #include <com/sun/star/chart/XAxisSupplier.hpp>
36 #include <com/sun/star/chart/XDiagramPositioning.hpp>
37 #include <com/sun/star/chart2/XChartDocument.hpp>
38 #include <com/sun/star/chart2/XDiagram.hpp>
39 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
40 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
41 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
42 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
43 #include <com/sun/star/chart2/XTitled.hpp>
44 #include <com/sun/star/chart2/XColorScheme.hpp>
45 #include <com/sun/star/chart2/data/XDataSource.hpp>
46 #include <com/sun/star/chart2/AxisType.hpp>
47 #include <com/sun/star/chart2/CurveStyle.hpp>
48 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
49 #include <com/sun/star/chart2/DataPointLabel.hpp>
50 #include <com/sun/star/chart2/LegendPosition.hpp>
51 #include <com/sun/star/chart2/RelativePosition.hpp>
52 #include <com/sun/star/chart2/RelativeSize.hpp>
53 #include <com/sun/star/chart2/StackingDirection.hpp>
54 #include <com/sun/star/chart2/TickmarkStyle.hpp>
56 #include <tools/gen.hxx>
57 #include <filter/msfilter/escherex.hxx>
59 #include <document.hxx>
60 #include <compiler.hxx>
61 #include <tokenarray.hxx>
62 #include <xeescher.hxx>
63 #include <xeformula.hxx>
64 #include <xehelper.hxx>
66 #include <xestyle.hxx>
67 #include <xltools.hxx>
71 using ::com::sun::star::uno::Any
;
72 using ::com::sun::star::uno::Reference
;
73 using ::com::sun::star::uno::Sequence
;
74 using ::com::sun::star::uno::UNO_QUERY
;
75 using ::com::sun::star::uno::UNO_QUERY_THROW
;
76 using ::com::sun::star::uno::UNO_SET_THROW
;
77 using ::com::sun::star::uno::Exception
;
78 using ::com::sun::star::beans::XPropertySet
;
79 using ::com::sun::star::i18n::XBreakIterator
;
80 using ::com::sun::star::frame::XModel
;
81 using ::com::sun::star::drawing::XShape
;
82 using ::com::sun::star::drawing::XShapes
;
84 using ::com::sun::star::chart2::IncrementData
;
85 using ::com::sun::star::chart2::RelativePosition
;
86 using ::com::sun::star::chart2::RelativeSize
;
87 using ::com::sun::star::chart2::ScaleData
;
88 using ::com::sun::star::chart2::SubIncrement
;
89 using ::com::sun::star::chart2::XAxis
;
90 using ::com::sun::star::chart2::XChartDocument
;
91 using ::com::sun::star::chart2::XChartTypeContainer
;
92 using ::com::sun::star::chart2::XColorScheme
;
93 using ::com::sun::star::chart2::XCoordinateSystem
;
94 using ::com::sun::star::chart2::XCoordinateSystemContainer
;
95 using ::com::sun::star::chart2::XChartType
;
96 using ::com::sun::star::chart2::XDataSeries
;
97 using ::com::sun::star::chart2::XDataSeriesContainer
;
98 using ::com::sun::star::chart2::XDiagram
;
99 using ::com::sun::star::chart2::XFormattedString
;
100 using ::com::sun::star::chart2::XLegend
;
101 using ::com::sun::star::chart2::XRegressionCurve
;
102 using ::com::sun::star::chart2::XRegressionCurveContainer
;
103 using ::com::sun::star::chart2::XTitle
;
104 using ::com::sun::star::chart2::XTitled
;
106 using ::com::sun::star::chart2::data::XDataSequence
;
107 using ::com::sun::star::chart2::data::XDataSource
;
108 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
110 using ::formula::FormulaToken
;
111 using ::formula::FormulaTokenArrayPlainIterator
;
113 namespace cssc
= ::com::sun::star::chart
;
114 namespace cssc2
= ::com::sun::star::chart2
;
116 // Helpers ====================================================================
120 XclExpStream
& operator<<( XclExpStream
& rStrm
, const XclChRectangle
& rRect
)
122 return rStrm
<< rRect
.mnX
<< rRect
.mnY
<< rRect
.mnWidth
<< rRect
.mnHeight
;
125 void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef
const & xRec
)
131 /** Saves the passed record (group) together with a leading value record. */
132 template< typename Type
>
133 void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef
const & xRec
, sal_uInt16 nRecId
, Type nValue
)
137 XclExpValueRecord
< Type
>( nRecId
, nValue
).Save( rStrm
);
142 template<typename ValueType
, typename KeyType
>
143 void lclSaveRecord(XclExpStream
& rStrm
, ValueType
* pRec
, sal_uInt16 nRecId
, KeyType nValue
)
147 XclExpValueRecord
<KeyType
>(nRecId
, nValue
).Save(rStrm
);
152 void lclWriteChFrBlockRecord( XclExpStream
& rStrm
, const XclChFrBlock
& rFrBlock
, bool bBegin
)
154 sal_uInt16 nRecId
= bBegin
? EXC_ID_CHFRBLOCKBEGIN
: EXC_ID_CHFRBLOCKEND
;
155 rStrm
.StartRecord( nRecId
, 12 );
156 rStrm
<< nRecId
<< EXC_FUTUREREC_EMPTYFLAGS
<< rFrBlock
.mnType
<< rFrBlock
.mnContext
<< rFrBlock
.mnValue1
<< rFrBlock
.mnValue2
;
160 template< typename Type
>
161 bool lclIsAutoAnyOrGetValue( Type
& rValue
, const Any
& rAny
)
163 return !rAny
.hasValue() || !(rAny
>>= rValue
);
166 bool lclIsAutoAnyOrGetScaledValue( double& rfValue
, const Any
& rAny
, bool bLogScale
)
168 bool bIsAuto
= lclIsAutoAnyOrGetValue( rfValue
, rAny
);
169 if( !bIsAuto
&& bLogScale
)
170 rfValue
= log( rfValue
) / log( 10.0 );
174 sal_uInt16
lclGetTimeValue( const XclExpRoot
& rRoot
, double fSerialDate
, sal_uInt16 nTimeUnit
)
176 DateTime aDateTime
= rRoot
.GetDateTimeFromDouble( fSerialDate
);
179 case EXC_CHDATERANGE_DAYS
:
180 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
181 case EXC_CHDATERANGE_MONTHS
:
182 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( 12 * (aDateTime
.GetYear() - rRoot
.GetBaseYear()) + aDateTime
.GetMonth() - 1, 0, SAL_MAX_INT16
);
183 case EXC_CHDATERANGE_YEARS
:
184 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( aDateTime
.GetYear() - rRoot
.GetBaseYear(), 0, SAL_MAX_INT16
);
186 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
188 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
191 bool lclConvertTimeValue( const XclExpRoot
& rRoot
, sal_uInt16
& rnValue
, const Any
& rAny
, sal_uInt16 nTimeUnit
)
193 double fSerialDate
= 0;
194 bool bAuto
= lclIsAutoAnyOrGetValue( fSerialDate
, rAny
);
196 rnValue
= lclGetTimeValue( rRoot
, fSerialDate
, nTimeUnit
);
200 sal_uInt16
lclGetTimeUnit( sal_Int32 nApiTimeUnit
)
202 switch( nApiTimeUnit
)
204 case cssc::TimeUnit::DAY
: return EXC_CHDATERANGE_DAYS
;
205 case cssc::TimeUnit::MONTH
: return EXC_CHDATERANGE_MONTHS
;
206 case cssc::TimeUnit::YEAR
: return EXC_CHDATERANGE_YEARS
;
207 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
209 return EXC_CHDATERANGE_DAYS
;
212 bool lclConvertTimeInterval( sal_uInt16
& rnValue
, sal_uInt16
& rnTimeUnit
, const Any
& rAny
)
214 cssc::TimeInterval aInterval
;
215 bool bAuto
= lclIsAutoAnyOrGetValue( aInterval
, rAny
);
218 rnValue
= ::limit_cast
< sal_uInt16
, sal_Int32
>( aInterval
.Number
, 1, SAL_MAX_UINT16
);
219 rnTimeUnit
= lclGetTimeUnit( aInterval
.TimeUnit
);
226 // Common =====================================================================
228 /** Stores global data needed in various classes of the Chart export filter. */
229 struct XclExpChRootData
: public XclChRootData
231 typedef ::std::vector
< XclChFrBlock
> XclChFrBlockVector
;
233 XclExpChChart
& mrChartData
; /// The chart data object.
234 XclChFrBlockVector maWrittenFrBlocks
; /// Stack of future record levels already written out.
235 XclChFrBlockVector maUnwrittenFrBlocks
; /// Stack of future record levels not yet written out.
237 explicit XclExpChRootData( XclExpChChart
& rChartData
) : mrChartData( rChartData
) {}
239 /** Registers a new future record level. */
240 void RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
);
241 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
242 void InitializeFutureRecBlock( XclExpStream
& rStrm
);
243 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
244 void FinalizeFutureRecBlock( XclExpStream
& rStrm
);
247 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
249 maUnwrittenFrBlocks
.push_back( rFrBlock
);
252 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream
& rStrm
)
254 // first call from a future record writes all missing CHFRBLOCKBEGIN records
255 if( maUnwrittenFrBlocks
.empty() )
258 // write the leading CHFRINFO record
259 if( maWrittenFrBlocks
.empty() )
261 rStrm
.StartRecord( EXC_ID_CHFRINFO
, 20 );
262 rStrm
<< EXC_ID_CHFRINFO
<< EXC_FUTUREREC_EMPTYFLAGS
<< EXC_CHFRINFO_EXCELXP2003
<< EXC_CHFRINFO_EXCELXP2003
<< sal_uInt16( 3 );
263 rStrm
<< sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
266 // write all unwritten CHFRBLOCKBEGIN records
267 for( const auto& rUnwrittenFrBlock
: maUnwrittenFrBlocks
)
269 OSL_ENSURE( rUnwrittenFrBlock
.mnType
!= EXC_CHFRBLOCK_TYPE_UNKNOWN
, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
270 lclWriteChFrBlockRecord( rStrm
, rUnwrittenFrBlock
, true );
272 // move all record infos to vector of written blocks
273 maWrittenFrBlocks
.insert( maWrittenFrBlocks
.end(), maUnwrittenFrBlocks
.begin(), maUnwrittenFrBlocks
.end() );
274 maUnwrittenFrBlocks
.clear();
277 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
279 OSL_ENSURE( !maUnwrittenFrBlocks
.empty() || !maWrittenFrBlocks
.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
280 if( !maUnwrittenFrBlocks
.empty() )
282 // no future record has been written, just forget the topmost level
283 maUnwrittenFrBlocks
.pop_back();
285 else if( !maWrittenFrBlocks
.empty() )
287 // write the CHFRBLOCKEND record for the topmost block and delete it
288 lclWriteChFrBlockRecord( rStrm
, maWrittenFrBlocks
.back(), false );
289 maWrittenFrBlocks
.pop_back();
293 XclExpChRoot::XclExpChRoot( const XclExpRoot
& rRoot
, XclExpChChart
& rChartData
) :
295 mxChData( std::make_shared
<XclExpChRootData
>( rChartData
) )
299 XclExpChRoot::~XclExpChRoot()
303 Reference
< XChartDocument
> const & XclExpChRoot::GetChartDocument() const
305 return mxChData
->mxChartDoc
;
308 XclExpChChart
& XclExpChRoot::GetChartData() const
310 return mxChData
->mrChartData
;
313 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType
) const
315 return mxChData
->mxTypeInfoProv
->GetTypeInfo( eType
);
318 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( std::u16string_view rServiceName
) const
320 return mxChData
->mxTypeInfoProv
->GetTypeInfoFromService( rServiceName
);
323 const XclChFormatInfo
& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType
) const
325 return mxChData
->mxFmtInfoProv
->GetFormatInfo( eObjType
);
328 void XclExpChRoot::InitConversion( css::uno::Reference
< css::chart2::XChartDocument
> const & xChartDoc
, const tools::Rectangle
& rChartRect
) const
330 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
333 void XclExpChRoot::FinishConversion() const
335 mxChData
->FinishConversion();
338 bool XclExpChRoot::IsSystemColor( const Color
& rColor
, sal_uInt16 nSysColorIdx
) const
340 XclExpPalette
& rPal
= GetPalette();
341 return rPal
.IsSystemColor( nSysColorIdx
) && (rColor
== rPal
.GetDefColor( nSysColorIdx
));
344 void XclExpChRoot::SetSystemColor( Color
& rColor
, sal_uInt32
& rnColorId
, sal_uInt16 nSysColorIdx
) const
346 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx
), "XclExpChRoot::SetSystemColor - invalid color index" );
347 rColor
= GetPalette().GetDefColor( nSysColorIdx
);
348 rnColorId
= XclExpPalette::GetColorIdFromIndex( nSysColorIdx
);
351 sal_Int32
XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX
) const
353 return ::limit_cast
< sal_Int32
, double >( (nPosX
- mxChData
->mnBorderGapX
) / mxChData
->mfUnitSizeX
, 0, EXC_CHART_TOTALUNITS
);
356 sal_Int32
XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY
) const
358 return ::limit_cast
< sal_Int32
, double >( (nPosY
- mxChData
->mnBorderGapY
) / mxChData
->mfUnitSizeY
, 0, EXC_CHART_TOTALUNITS
);
361 XclChRectangle
XclExpChRoot::CalcChartRectFromHmm( const css::awt::Rectangle
& rRect
) const
363 XclChRectangle aRect
;
364 aRect
.mnX
= CalcChartXFromHmm( rRect
.X
);
365 aRect
.mnY
= CalcChartYFromHmm( rRect
.Y
);
366 aRect
.mnWidth
= CalcChartXFromHmm( rRect
.Width
);
367 aRect
.mnHeight
= CalcChartYFromHmm( rRect
.Height
);
371 void XclExpChRoot::ConvertLineFormat( XclChLineFormat
& rLineFmt
,
372 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
374 GetChartPropSetHelper().ReadLineProperties(
375 rLineFmt
, *mxChData
->mxLineDashTable
, rPropSet
, ePropMode
);
378 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat
& rAreaFmt
,
379 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
381 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt
, rPropSet
, ePropMode
);
384 void XclExpChRoot::ConvertEscherFormat(
385 XclChEscherFormat
& rEscherFmt
, XclChPicFormat
& rPicFmt
,
386 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
388 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt
, rPicFmt
,
389 *mxChData
->mxGradientTable
, *mxChData
->mxHatchTable
, *mxChData
->mxBitmapTable
, rPropSet
, ePropMode
);
392 sal_uInt16
XclExpChRoot::ConvertFont( const ScfPropertySet
& rPropSet
, sal_Int16 nScript
) const
394 XclFontData aFontData
;
395 GetFontPropSetHelper().ReadFontProperties( aFontData
, rPropSet
, EXC_FONTPROPSET_CHART
, nScript
);
396 return GetFontBuffer().Insert( aFontData
, EXC_COLOR_CHARTTEXT
);
399 sal_uInt16
XclExpChRoot::ConvertPieRotation( const ScfPropertySet
& rPropSet
)
401 sal_Int32 nApiRot
= 0;
402 rPropSet
.GetProperty( nApiRot
, EXC_CHPROP_STARTINGANGLE
);
403 return static_cast< sal_uInt16
>( (450 - (nApiRot
% 360)) % 360 );
406 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
408 mxChData
->RegisterFutureRecBlock( rFrBlock
);
411 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream
& rStrm
)
413 mxChData
->InitializeFutureRecBlock( rStrm
);
416 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
418 mxChData
->FinalizeFutureRecBlock( rStrm
);
421 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot
& rRoot
,
422 sal_uInt16 nFrType
, sal_uInt16 nRecId
, std::size_t nRecSize
) :
423 XclExpRecord( nRecId
, nRecSize
),
424 XclExpChRoot( rRoot
),
429 XclExpChGroupBase::~XclExpChGroupBase()
433 void XclExpChGroupBase::Save( XclExpStream
& rStrm
)
436 XclExpRecord::Save( rStrm
);
438 if( !HasSubRecords() )
441 // register the future record context corresponding to this record group
442 RegisterFutureRecBlock( maFrBlock
);
444 XclExpEmptyRecord( EXC_ID_CHBEGIN
).Save( rStrm
);
446 WriteSubRecords( rStrm
);
447 // finalize the future records, must be done before the closing CHEND
448 FinalizeFutureRecBlock( rStrm
);
450 XclExpEmptyRecord( EXC_ID_CHEND
).Save( rStrm
);
453 bool XclExpChGroupBase::HasSubRecords() const
458 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext
, sal_uInt16 nFrValue1
, sal_uInt16 nFrValue2
)
460 maFrBlock
.mnContext
= nFrContext
;
461 maFrBlock
.mnValue1
= nFrValue1
;
462 maFrBlock
.mnValue2
= nFrValue2
;
465 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot
& rRoot
,
466 XclFutureRecType eRecType
, sal_uInt16 nRecId
, std::size_t nRecSize
) :
467 XclExpFutureRecord( eRecType
, nRecId
, nRecSize
),
468 XclExpChRoot( rRoot
)
472 void XclExpChFutureRecordBase::Save( XclExpStream
& rStrm
)
474 InitializeFutureRecBlock( rStrm
);
475 XclExpFutureRecord::Save( rStrm
);
478 // Frame formatting ===========================================================
480 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode
) :
481 XclExpRecord( EXC_ID_CHFRAMEPOS
, 20 )
483 maData
.mnTLMode
= nTLMode
;
484 maData
.mnBRMode
= EXC_CHFRAMEPOS_PARENT
;
487 void XclExpChFramePos::WriteBody( XclExpStream
& rStrm
)
489 rStrm
<< maData
.mnTLMode
<< maData
.mnBRMode
<< maData
.maRect
;
492 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot
& rRoot
) :
493 XclExpRecord( EXC_ID_CHLINEFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 10 ),
494 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
498 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType
)
500 switch( eDefFrameType
)
502 case EXC_CHFRAMETYPE_AUTO
:
505 case EXC_CHFRAMETYPE_INVISIBLE
:
507 maData
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
510 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" );
514 void XclExpChLineFormat::Convert( const XclExpChRoot
& rRoot
,
515 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
517 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
518 rRoot
.ConvertLineFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
521 // detect system color, set color identifier (TODO: detect automatic series line)
522 if( (eObjType
!= EXC_CHOBJTYPE_LINEARSERIES
) && rRoot
.IsSystemColor( maData
.maColor
, rFmtInfo
.mnAutoLineColorIdx
) )
524 // store color index from automatic format data
525 mnColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoLineColorIdx
);
526 // try to set automatic mode
527 bool bAuto
= (maData
.mnPattern
== EXC_CHLINEFORMAT_SOLID
) && (maData
.mnWeight
== rFmtInfo
.mnAutoLineWeight
);
528 ::set_flag( maData
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, bAuto
);
532 // user defined color - register in palette
533 mnColorId
= rRoot
.GetPalette().InsertColor( maData
.maColor
, EXC_COLOR_CHARTLINE
);
538 // no line - set default system color
539 rRoot
.SetSystemColor( maData
.maColor
, mnColorId
, EXC_COLOR_CHWINDOWTEXT
);
543 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType
) const
546 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasLine()) ||
547 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
550 void XclExpChLineFormat::WriteBody( XclExpStream
& rStrm
)
552 rStrm
<< maData
.maColor
<< maData
.mnPattern
<< maData
.mnWeight
<< maData
.mnFlags
;
553 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
554 rStrm
<< rStrm
.GetRoot().GetPalette().GetColorIndex( mnColorId
);
559 /** Creates a CHLINEFORMAT record from the passed property set. */
560 XclExpChLineFormatRef
lclCreateLineFormat( const XclExpChRoot
& rRoot
,
561 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
563 XclExpChLineFormatRef xLineFmt
= new XclExpChLineFormat( rRoot
);
564 xLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
565 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
566 if( rFmtInfo
.mbDeleteDefFrame
&& xLineFmt
->IsDefault( rFmtInfo
.meDefFrameType
) )
573 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot
& rRoot
) :
574 XclExpRecord( EXC_ID_CHAREAFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 16 : 12 ),
575 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
576 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
580 bool XclExpChAreaFormat::Convert( const XclExpChRoot
& rRoot
,
581 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
583 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
584 bool bComplexFill
= rRoot
.ConvertAreaFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
587 bool bSolid
= maData
.mnPattern
== EXC_PATT_SOLID
;
588 // detect system color, set color identifier (TODO: detect automatic series area)
589 if( (eObjType
!= EXC_CHOBJTYPE_FILLEDSERIES
) && rRoot
.IsSystemColor( maData
.maPattColor
, rFmtInfo
.mnAutoPattColorIdx
) )
591 // store color index from automatic format data
592 mnPattColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoPattColorIdx
);
593 // set automatic mode
594 ::set_flag( maData
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, bSolid
);
598 // user defined color - register color in palette
599 mnPattColorId
= rRoot
.GetPalette().InsertColor( maData
.maPattColor
, EXC_COLOR_CHARTAREA
);
601 // background color (default system color for solid fills)
603 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
605 mnBackColorId
= rRoot
.GetPalette().InsertColor( maData
.maBackColor
, EXC_COLOR_CHARTAREA
);
609 // no area - set default system colors
610 rRoot
.SetSystemColor( maData
.maPattColor
, mnPattColorId
, EXC_COLOR_CHWINDOWBACK
);
611 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
616 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType
)
618 switch( eDefFrameType
)
620 case EXC_CHFRAMETYPE_AUTO
:
623 case EXC_CHFRAMETYPE_INVISIBLE
:
625 maData
.mnPattern
= EXC_PATT_NONE
;
628 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" );
632 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType
) const
635 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasArea()) ||
636 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
639 void XclExpChAreaFormat::WriteBody( XclExpStream
& rStrm
)
641 rStrm
<< maData
.maPattColor
<< maData
.maBackColor
<< maData
.mnPattern
<< maData
.mnFlags
;
642 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
644 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
645 rStrm
<< rPal
.GetColorIndex( mnPattColorId
) << rPal
.GetColorIndex( mnBackColorId
);
649 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot
& rRoot
) :
650 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_UNKNOWN
, EXC_ID_CHESCHERFORMAT
),
651 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
652 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
654 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8
);
657 void XclExpChEscherFormat::Convert( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
659 const XclChFormatInfo
& rFmtInfo
= GetFormatInfo( eObjType
);
660 ConvertEscherFormat( maData
, maPicFmt
, rPropSet
, rFmtInfo
.mePropMode
);
661 // register colors in palette
662 mnColor1Id
= RegisterColor( ESCHER_Prop_fillColor
);
663 mnColor2Id
= RegisterColor( ESCHER_Prop_fillBackColor
);
666 bool XclExpChEscherFormat::IsValid() const
668 return static_cast< bool >(maData
.mxEscherSet
);
671 void XclExpChEscherFormat::Save( XclExpStream
& rStrm
)
673 if( maData
.mxEscherSet
)
675 // replace RGB colors with palette indexes in the Escher container
676 const XclExpPalette
& rPal
= GetPalette();
677 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillColor
, 0x08000000 | rPal
.GetColorIndex( mnColor1Id
) );
678 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillBackColor
, 0x08000000 | rPal
.GetColorIndex( mnColor2Id
) );
680 // save the record group
681 XclExpChGroupBase::Save( rStrm
);
685 bool XclExpChEscherFormat::HasSubRecords() const
687 // no subrecords for gradients
688 return maPicFmt
.mnBmpMode
!= EXC_CHPICFORMAT_NONE
;
691 void XclExpChEscherFormat::WriteSubRecords( XclExpStream
& rStrm
)
693 rStrm
.StartRecord( EXC_ID_CHPICFORMAT
, 14 );
694 rStrm
<< maPicFmt
.mnBmpMode
<< sal_uInt16( 0 ) << maPicFmt
.mnFlags
<< maPicFmt
.mfScale
;
698 sal_uInt32
XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId
)
700 sal_uInt32 nBGRValue
;
701 if( maData
.mxEscherSet
&& maData
.mxEscherSet
->GetOpt( nPropId
, nBGRValue
) )
704 Color
aColor( nBGRValue
& 0xff, (nBGRValue
>> 8) & 0xff, (nBGRValue
>> 16) & 0xff );
705 return GetPalette().InsertColor( aColor
, EXC_COLOR_CHARTAREA
);
707 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
);
710 void XclExpChEscherFormat::WriteBody( XclExpStream
& rStrm
)
712 OSL_ENSURE( maData
.mxEscherSet
, "XclExpChEscherFormat::WriteBody - missing property container" );
713 // write Escher property container via temporary memory stream
714 SvMemoryStream aMemStrm
;
715 maData
.mxEscherSet
->Commit( aMemStrm
);
716 aMemStrm
.FlushBuffer();
717 aMemStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
718 rStrm
.CopyFromStream( aMemStrm
);
721 XclExpChFrameBase::XclExpChFrameBase()
725 XclExpChFrameBase::~XclExpChFrameBase()
729 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot
& rRoot
,
730 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
733 mxLineFmt
= new XclExpChLineFormat( rRoot
);
734 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
735 // area format (only for frame objects)
736 if( !rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
739 mxAreaFmt
= new XclExpChAreaFormat( rRoot
);
740 bool bComplexFill
= mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
);
741 if( (rRoot
.GetBiff() == EXC_BIFF8
) && bComplexFill
)
743 mxEscherFmt
= new XclExpChEscherFormat( rRoot
);
744 mxEscherFmt
->Convert( rPropSet
, eObjType
);
745 if( mxEscherFmt
->IsValid() )
746 mxAreaFmt
->SetAuto( false );
752 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot
& rRoot
,
753 XclChFrameType eDefFrameType
, bool bIsFrame
)
756 mxLineFmt
= new XclExpChLineFormat( rRoot
);
757 mxLineFmt
->SetDefault( eDefFrameType
);
758 // area format (only for frame objects)
761 mxAreaFmt
= new XclExpChAreaFormat( rRoot
);
762 mxAreaFmt
->SetDefault( eDefFrameType
);
767 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType
) const
770 (!mxLineFmt
|| mxLineFmt
->IsDefault( eDefFrameType
)) &&
771 (!mxAreaFmt
|| mxAreaFmt
->IsDefault( eDefFrameType
));
774 void XclExpChFrameBase::WriteFrameRecords( XclExpStream
& rStrm
)
776 lclSaveRecord( rStrm
, mxLineFmt
);
777 lclSaveRecord( rStrm
, mxAreaFmt
);
778 lclSaveRecord( rStrm
, mxEscherFmt
);
781 XclExpChFrame::XclExpChFrame( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
782 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_FRAME
, EXC_ID_CHFRAME
, 4 ),
783 meObjType( eObjType
)
787 void XclExpChFrame::Convert( const ScfPropertySet
& rPropSet
)
789 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
792 void XclExpChFrame::SetAutoFlags( bool bAutoPos
, bool bAutoSize
)
794 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOPOS
, bAutoPos
);
795 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOSIZE
, bAutoSize
);
798 bool XclExpChFrame::IsDefault() const
800 return IsDefaultFrameBase( GetFormatInfo( meObjType
).meDefFrameType
);
803 bool XclExpChFrame::IsDeleteable() const
805 return IsDefault() && GetFormatInfo( meObjType
).mbDeleteDefFrame
;
808 void XclExpChFrame::Save( XclExpStream
& rStrm
)
812 // wall/floor frame without CHFRAME header record
813 case EXC_CHOBJTYPE_WALL3D
:
814 case EXC_CHOBJTYPE_FLOOR3D
:
815 WriteFrameRecords( rStrm
);
818 XclExpChGroupBase::Save( rStrm
);
822 void XclExpChFrame::WriteSubRecords( XclExpStream
& rStrm
)
824 WriteFrameRecords( rStrm
);
827 void XclExpChFrame::WriteBody( XclExpStream
& rStrm
)
829 rStrm
<< maData
.mnFormat
<< maData
.mnFlags
;
834 /** Creates a CHFRAME record from the passed property set. */
835 XclExpChFrameRef
lclCreateFrame( const XclExpChRoot
& rRoot
,
836 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
838 XclExpChFrameRef xFrame
= new XclExpChFrame( rRoot
, eObjType
);
839 xFrame
->Convert( rPropSet
);
840 if( xFrame
->IsDeleteable() )
847 // Source links ===============================================================
851 void lclAddDoubleRefData(
852 ScTokenArray
& orArray
, const FormulaToken
& rToken
,
853 SCTAB nScTab1
, SCCOL nScCol1
, SCROW nScRow1
,
854 SCTAB nScTab2
, SCCOL nScCol2
, SCROW nScRow2
)
856 ScComplexRefData aComplexRef
;
857 aComplexRef
.InitRange(ScRange(nScCol1
,nScRow1
,nScTab1
,nScCol2
,nScRow2
,nScTab2
));
858 aComplexRef
.Ref1
.SetFlag3D( true );
860 if( orArray
.GetLen() > 0 )
861 orArray
.AddOpCode( ocUnion
);
863 OSL_ENSURE( (rToken
.GetType() == ::formula::svDoubleRef
) || (rToken
.GetType() == ::formula::svExternalDoubleRef
),
864 "lclAddDoubleRefData - double reference token expected");
865 if( rToken
.GetType() == ::formula::svExternalDoubleRef
)
866 orArray
.AddExternalDoubleReference(
867 rToken
.GetIndex(), rToken
.GetString(), aComplexRef
);
869 orArray
.AddDoubleReference( aComplexRef
);
874 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot
& rRoot
, sal_uInt8 nDestType
) :
875 XclExpRecord( EXC_ID_CHSOURCELINK
),
876 XclExpChRoot( rRoot
)
878 maData
.mnDestType
= nDestType
;
879 maData
.mnLinkType
= EXC_CHSRCLINK_DIRECTLY
;
882 sal_uInt16
XclExpChSourceLink::ConvertDataSequence( Reference
< XDataSequence
> const & xDataSeq
, bool bSplitToColumns
, sal_uInt16 nDefCount
)
885 maData
.mnLinkType
= EXC_CHSRCLINK_DEFAULT
;
890 // Compile the range representation string into token array. Note that the
891 // source range text depends on the current grammar.
892 OUString aRangeRepr
= xDataSeq
->getSourceRangeRepresentation();
893 ScCompiler
aComp( GetDoc(), ScAddress(), GetDoc().GetGrammar() );
894 std::unique_ptr
<ScTokenArray
> pArray(aComp
.CompileString(aRangeRepr
));
898 ScTokenArray
aArray(GetRoot().GetDoc());
899 sal_uInt32 nValueCount
= 0;
900 FormulaTokenArrayPlainIterator
aIter(*pArray
);
901 for( const FormulaToken
* pToken
= aIter
.First(); pToken
; pToken
= aIter
.Next() )
903 switch( pToken
->GetType() )
905 case ::formula::svSingleRef
:
906 case ::formula::svExternalSingleRef
:
907 // for a single ref token, just add it to the new token array as is
908 if( aArray
.GetLen() > 0 )
909 aArray
.AddOpCode( ocUnion
);
910 aArray
.AddToken( *pToken
);
914 case ::formula::svDoubleRef
:
915 case ::formula::svExternalDoubleRef
:
917 // split 3-dimensional ranges into single sheets
918 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
919 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(GetRoot().GetDoc(), ScAddress());
920 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(GetRoot().GetDoc(), ScAddress());
921 for (SCTAB nScTab
= aAbs1
.Tab(); nScTab
<= aAbs2
.Tab(); ++nScTab
)
923 // split 2-dimensional ranges into single columns
924 if (bSplitToColumns
&& (aAbs1
.Col() < aAbs2
.Col()) && (aAbs1
.Row() < aAbs2
.Row()))
925 for (SCCOL nScCol
= aAbs1
.Col(); nScCol
<= aAbs2
.Col(); ++nScCol
)
926 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, nScCol
, aAbs1
.Row(), nScTab
, nScCol
, aAbs2
.Row());
928 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, aAbs1
.Col(), aAbs1
.Row(), nScTab
, aAbs2
.Col(), aAbs2
.Row());
930 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
931 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
932 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
933 nValueCount
+= nCols
* nRows
* nTabs
;
941 const ScAddress aBaseCell
;
942 mxLinkFmla
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aArray
, &aBaseCell
);
943 maData
.mnLinkType
= EXC_CHSRCLINK_WORKSHEET
;
944 return ulimit_cast
< sal_uInt16
>( nValueCount
, EXC_CHDATAFORMAT_MAXPOINTCOUNT
);
947 void XclExpChSourceLink::ConvertString( const OUString
& aString
)
949 mxString
= XclExpStringHelper::CreateString( GetRoot(), aString
, XclStrFlags::ForceUnicode
| XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
952 sal_uInt16
XclExpChSourceLink::ConvertStringSequence( const Sequence
< Reference
< XFormattedString
> >& rStringSeq
)
955 sal_uInt16 nFontIdx
= EXC_FONT_APP
;
956 if( rStringSeq
.hasElements() )
958 mxString
= XclExpStringHelper::CreateString( GetRoot(), OUString(), XclStrFlags::ForceUnicode
| XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
959 Reference
< XBreakIterator
> xBreakIt
= GetDoc().GetBreakIterator();
960 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
962 // convert all formatted string entries from the sequence
963 for( const Reference
< XFormattedString
>& rString
: rStringSeq
)
967 sal_uInt16 nWstrnFontIdx
= EXC_FONT_NOTFOUND
;
968 sal_uInt16 nAsianFontIdx
= EXC_FONT_NOTFOUND
;
969 sal_uInt16 nCmplxFontIdx
= EXC_FONT_NOTFOUND
;
970 OUString aText
= rString
->getString();
971 ScfPropertySet
aStrProp( rString
);
973 // #i63255# get script type for leading weak characters
974 sal_Int16 nLastScript
= XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText
);
976 // process all script portions
977 sal_Int32 nPortionPos
= 0;
978 sal_Int32 nTextLen
= aText
.getLength();
979 while( nPortionPos
< nTextLen
)
981 // get script type and end position of next script portion
982 sal_Int16 nScript
= xBreakIt
->getScriptType( aText
, nPortionPos
);
983 sal_Int32 nPortionEnd
= xBreakIt
->endOfScript( aText
, nPortionPos
, nScript
);
985 // reuse previous script for following weak portions
986 if( nScript
== ApiScriptType::WEAK
)
987 nScript
= nLastScript
;
989 // Excel start position of this portion
990 sal_uInt16 nXclPortionStart
= mxString
->Len();
991 // add portion text to Excel string
992 XclExpStringHelper::AppendString( *mxString
, GetRoot(), aText
.subView( nPortionPos
, nPortionEnd
- nPortionPos
) );
993 if( nXclPortionStart
< mxString
->Len() )
995 // find font index variable dependent on script type
996 sal_uInt16
& rnFontIdx
= (nScript
== ApiScriptType::COMPLEX
) ? nCmplxFontIdx
:
997 ((nScript
== ApiScriptType::ASIAN
) ? nAsianFontIdx
: nWstrnFontIdx
);
999 // insert font into buffer (if not yet done)
1000 if( rnFontIdx
== EXC_FONT_NOTFOUND
)
1001 rnFontIdx
= ConvertFont( aStrProp
, nScript
);
1003 // insert font index into format run vector
1004 mxString
->AppendFormat( nXclPortionStart
, rnFontIdx
);
1007 // go to next script portion
1008 nLastScript
= nScript
;
1009 nPortionPos
= nPortionEnd
;
1013 if( !mxString
->IsEmpty() )
1015 // get leading font index
1016 const XclFormatRunVec
& rFormats
= mxString
->GetFormats();
1017 OSL_ENSURE( !rFormats
.empty() && (rFormats
.front().mnChar
== 0),
1018 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1019 // remove leading format run, if entire string is equally formatted
1020 if( rFormats
.size() == 1 )
1021 nFontIdx
= mxString
->RemoveLeadingFont();
1022 else if( !rFormats
.empty() )
1023 nFontIdx
= rFormats
.front().mnFontIdx
;
1024 // add trailing format run, if string is rich-formatted
1025 if( mxString
->IsRich() )
1026 mxString
->AppendTrailingFormat( EXC_FONT_APP
);
1032 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet
& rPropSet
, bool bPercent
)
1034 sal_Int32 nApiNumFmt
= 0;
1035 if( bPercent
? rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_PERCENTAGENUMFMT
) : rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
1037 ::set_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
1038 maData
.mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
1042 void XclExpChSourceLink::AppendString( std::u16string_view rStr
)
1046 XclExpStringHelper::AppendString( *mxString
, GetRoot(), rStr
);
1049 void XclExpChSourceLink::Save( XclExpStream
& rStrm
)
1051 // CHFORMATRUNS record
1052 if( mxString
&& mxString
->IsRich() )
1054 std::size_t nRecSize
= (1 + mxString
->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8
) ? 2 : 1);
1055 rStrm
.StartRecord( EXC_ID_CHFORMATRUNS
, nRecSize
);
1056 mxString
->WriteFormats( rStrm
, true );
1059 // CHSOURCELINK record
1060 XclExpRecord::Save( rStrm
);
1062 if( mxString
&& !mxString
->IsEmpty() )
1064 rStrm
.StartRecord( EXC_ID_CHSTRING
, 2 + mxString
->GetSize() );
1065 rStrm
<< sal_uInt16( 0 ) << *mxString
;
1070 void XclExpChSourceLink::WriteBody( XclExpStream
& rStrm
)
1072 rStrm
<< maData
.mnDestType
1073 << maData
.mnLinkType
1075 << maData
.mnNumFmtIdx
1079 // Text =======================================================================
1081 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx
) :
1082 XclExpUInt16Record( EXC_ID_CHFONT
, nFontIdx
)
1086 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget
, const XclChDataPointPos
& rPointPos
) :
1087 XclExpRecord( EXC_ID_CHOBJECTLINK
, 6 )
1089 maData
.mnTarget
= nLinkTarget
;
1090 maData
.maPointPos
= rPointPos
;
1093 void XclExpChObjectLink::WriteBody( XclExpStream
& rStrm
)
1095 rStrm
<< maData
.mnTarget
<< maData
.maPointPos
.mnSeriesIdx
<< maData
.maPointPos
.mnPointIdx
;
1098 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot
& rRoot
) :
1099 XclExpChFutureRecordBase( rRoot
, EXC_FUTUREREC_UNUSEDREF
, EXC_ID_CHFRLABELPROPS
, 4 )
1103 void XclExpChFrLabelProps::Convert( const ScfPropertySet
& rPropSet
,
1104 bool bShowCateg
, bool bShowValue
, bool bShowPercent
, bool bShowBubble
)
1106 // label value flags
1107 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWSERIES
, false );
1108 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWCATEG
, bShowCateg
);
1109 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWVALUE
, bShowValue
);
1110 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWPERCENT
, bShowPercent
);
1111 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWBUBBLE
, bShowBubble
);
1113 // label value separator
1114 maData
.maSeparator
= rPropSet
.GetStringProperty( EXC_CHPROP_LABELSEPARATOR
);
1115 if( maData
.maSeparator
.isEmpty() )
1116 maData
.maSeparator
= " ";
1119 void XclExpChFrLabelProps::WriteBody( XclExpStream
& rStrm
)
1121 XclExpString
aXclSep( maData
.maSeparator
, XclStrFlags::ForceUnicode
| XclStrFlags::SmartFlags
);
1122 rStrm
<< maData
.mnFlags
<< aXclSep
;
1125 XclExpChFontBase::~XclExpChFontBase()
1129 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, sal_uInt16 nFontIdx
)
1131 if( const XclExpFont
* pFont
= rRoot
.GetFontBuffer().GetFont( nFontIdx
) )
1133 XclExpChFontRef xFont
= new XclExpChFont(nFontIdx
);
1134 SetFont(xFont
, pFont
->GetFontData().maComplexColor
, pFont
->GetFontColorId());
1138 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, const ScfPropertySet
& rPropSet
)
1140 ConvertFontBase( rRoot
, rRoot
.ConvertFont( rPropSet
, rRoot
.GetDefApiScript() ) );
1143 void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet
& rPropSet
, bool bSupportsStacked
)
1145 sal_uInt16 nRotation
= XclChPropSetHelper::ReadRotationProperties( rPropSet
, bSupportsStacked
);
1146 SetRotation( nRotation
);
1149 XclExpChText::XclExpChText( const XclExpChRoot
& rRoot
) :
1150 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TEXT
, EXC_ID_CHTEXT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 32 : 26 ),
1151 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
1155 void XclExpChText::SetFont(const XclExpChFontRef
& xFont
, model::ComplexColor
const& rComplexColor
, sal_uInt32 nColorId
)
1158 maData
.maTextComplexColor
= rComplexColor
;
1159 ::set_flag(maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, rComplexColor
.getFinalColor() == COL_AUTO
);
1160 mnTextColorId
= nColorId
;
1163 void XclExpChText::SetRotation( sal_uInt16 nRotation
)
1165 maData
.mnRotation
= nRotation
;
1166 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 8, 3 );
1169 void XclExpChText::ConvertTitle( Reference
< XTitle
> const & xTitle
, sal_uInt16 nTarget
, const OUString
* pSubTitle
)
1173 case EXC_CHOBJLINK_TITLE
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE
); break;
1174 case EXC_CHOBJLINK_YAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 1 ); break;
1175 case EXC_CHOBJLINK_XAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
); break;
1176 case EXC_CHOBJLINK_ZAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 2 ); break;
1180 mxObjLink
= new XclExpChObjectLink( nTarget
, XclChDataPointPos( 0, 0 ) );
1184 // title frame formatting
1185 ScfPropertySet
aTitleProp( xTitle
);
1186 mxFrame
= lclCreateFrame( GetChRoot(), aTitleProp
, EXC_CHOBJTYPE_TEXT
);
1189 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1190 sal_uInt16 nFontIdx
= mxSrcLink
->ConvertStringSequence( xTitle
->getText() );
1193 // append subtitle as the 2nd line of the title.
1194 OUString aSubTitle
= "\n" + *pSubTitle
;
1195 mxSrcLink
->AppendString(aSubTitle
);
1198 ConvertFontBase( GetChRoot(), nFontIdx
);
1201 ConvertRotationBase( aTitleProp
, true );
1203 // manual text position - only for main title
1204 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
);
1205 if( nTarget
== EXC_CHOBJLINK_TITLE
)
1208 if( aTitleProp
.GetAnyProperty( aRelPos
, EXC_CHPROP_RELATIVEPOSITION
) && aRelPos
.has
< RelativePosition
>() ) try
1210 // calculate absolute position for CHTEXT record
1211 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
1212 Reference
< XShape
> xTitleShape( xChart1Doc
->getTitle(), UNO_SET_THROW
);
1213 css::awt::Point aPos
= xTitleShape
->getPosition();
1214 css::awt::Size aSize
= xTitleShape
->getSize();
1215 css::awt::Rectangle
aRect( aPos
.X
, aPos
.Y
, aSize
.Width
, aSize
.Height
);
1216 maData
.maRect
= CalcChartRectFromHmm( aRect
);
1217 ::insert_value( maData
.mnFlags2
, EXC_CHTEXT_POS_MOVED
, 0, 4 );
1218 // manual title position implies manual plot area
1219 GetChartData().SetManualPlotArea();
1220 // calculate the default title position in chart units
1221 sal_Int32 nDefPosX
= ::std::max
< sal_Int32
>( (EXC_CHART_TOTALUNITS
- maData
.maRect
.mnWidth
) / 2, 0 );
1222 sal_Int32 nDefPosY
= 85;
1223 // set the position relative to the standard position
1224 XclChRectangle
& rFrameRect
= mxFramePos
->GetFramePosData().maRect
;
1225 rFrameRect
.mnX
= maData
.maRect
.mnX
- nDefPosX
;
1226 rFrameRect
.mnY
= maData
.maRect
.mnY
- nDefPosY
;
1235 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
);
1239 void XclExpChText::ConvertLegend( const ScfPropertySet
& rPropSet
)
1241 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1242 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOGEN
);
1243 ConvertFontBase( GetChRoot(), rPropSet
);
1246 bool XclExpChText::ConvertDataLabel( const ScfPropertySet
& rPropSet
,
1247 const XclChTypeInfo
& rTypeInfo
, const XclChDataPointPos
& rPointPos
)
1249 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL
, rPointPos
.mnPointIdx
, rPointPos
.mnSeriesIdx
);
1251 cssc2::DataPointLabel aPointLabel
;
1252 if( !rPropSet
.GetProperty( aPointLabel
, EXC_CHPROP_LABEL
) )
1255 // percentage only allowed in pie and donut charts
1256 bool bIsPie
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
;
1257 // bubble sizes only allowed in bubble charts
1258 bool bIsBubble
= rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
;
1259 OSL_ENSURE( (GetBiff() == EXC_BIFF8
) || !bIsBubble
, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1262 bool bShowValue
= !bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1263 bool bShowPercent
= bIsPie
&& aPointLabel
.ShowNumberInPercent
; // percentage only in pie/donut charts
1264 bool bShowCateg
= aPointLabel
.ShowCategoryName
;
1265 bool bShowBubble
= bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1266 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
|| bShowBubble
;
1268 // create the CHFRLABELPROPS record for extended settings in BIFF8
1269 if( bShowAny
&& (GetBiff() == EXC_BIFF8
) )
1271 mxLabelProps
= new XclExpChFrLabelProps( GetChRoot() );
1272 mxLabelProps
->Convert( rPropSet
, bShowCateg
, bShowValue
, bShowPercent
, bShowBubble
);
1275 // restrict to combinations allowed in CHTEXT
1276 if( bShowPercent
) bShowValue
= false; // percent wins over value
1277 if( bShowValue
) bShowCateg
= false; // value wins over category
1278 if( bShowValue
|| bShowCateg
) bShowBubble
= false; // value or category wins over bubble size
1281 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1282 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bShowValue
);
1283 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bShowPercent
);
1284 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bShowCateg
);
1285 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bShowPercent
&& bShowCateg
);
1286 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWBUBBLE
, bShowBubble
);
1287 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
, bShowAny
&& aPointLabel
.ShowLegendSymbol
);
1288 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bShowAny
);
1293 ConvertFontBase( GetChRoot(), rPropSet
);
1294 ConvertRotationBase( rPropSet
, false );
1296 sal_Int32 nPlacement
= 0;
1297 sal_uInt16 nLabelPos
= EXC_CHTEXT_POS_AUTO
;
1298 if( rPropSet
.GetProperty( nPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1300 using namespace cssc::DataLabelPlacement
;
1301 if( nPlacement
== rTypeInfo
.mnDefaultLabelPos
)
1303 nLabelPos
= EXC_CHTEXT_POS_DEFAULT
;
1305 else switch( nPlacement
)
1307 case AVOID_OVERLAP
: nLabelPos
= EXC_CHTEXT_POS_AUTO
; break;
1308 case CENTER
: nLabelPos
= EXC_CHTEXT_POS_CENTER
; break;
1309 case TOP
: nLabelPos
= EXC_CHTEXT_POS_ABOVE
; break;
1310 case TOP_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1311 case LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1312 case BOTTOM_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1313 case BOTTOM
: nLabelPos
= EXC_CHTEXT_POS_BELOW
; break;
1314 case BOTTOM_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1315 case RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1316 case TOP_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1317 case INSIDE
: nLabelPos
= EXC_CHTEXT_POS_INSIDE
; break;
1318 case OUTSIDE
: nLabelPos
= EXC_CHTEXT_POS_OUTSIDE
; break;
1319 case NEAR_ORIGIN
: nLabelPos
= EXC_CHTEXT_POS_AXIS
; break;
1320 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1323 ::insert_value( maData
.mnFlags2
, nLabelPos
, 0, 4 );
1324 // source link (contains number format)
1325 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1326 if( bShowValue
|| bShowPercent
)
1327 // percentage format wins over value format
1328 mxSrcLink
->ConvertNumFmt( rPropSet
, bShowPercent
);
1330 mxObjLink
= new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
);
1333 /* Return true to indicate valid label settings:
1334 - for existing labels at entire series
1335 - for any settings at single data point (to be able to delete a point label) */
1336 return bShowAny
|| (rPointPos
.mnPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
);
1339 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet
& rPropSet
, const XclChDataPointPos
& rPointPos
)
1342 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1343 if( GetBiff() == EXC_BIFF8
)
1344 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
); // must set this to make equation visible in Excel
1346 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_TEXT
);
1348 maData
.mnHAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1349 maData
.mnVAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1350 ConvertFontBase( GetChRoot(), rPropSet
);
1351 // source link (contains number format)
1352 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1353 mxSrcLink
->ConvertNumFmt( rPropSet
, false );
1355 mxObjLink
= new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
);
1358 sal_uInt16
XclExpChText::GetAttLabelFlags() const
1360 sal_uInt16 nFlags
= 0;
1361 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWVALUE
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
) );
1362 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWPERCENT
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
) );
1363 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEGPERC
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
) );
1364 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEG
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
) );
1368 void XclExpChText::WriteSubRecords( XclExpStream
& rStrm
)
1370 // CHFRAMEPOS record
1371 lclSaveRecord( rStrm
, mxFramePos
);
1373 lclSaveRecord( rStrm
, mxFont
);
1374 // CHSOURCELINK group
1375 lclSaveRecord( rStrm
, mxSrcLink
);
1377 lclSaveRecord( rStrm
, mxFrame
);
1378 // CHOBJECTLINK record
1379 lclSaveRecord( rStrm
, mxObjLink
);
1380 // CHFRLABELPROPS record
1381 lclSaveRecord( rStrm
, mxLabelProps
);
1384 void XclExpChText::WriteBody( XclExpStream
& rStrm
)
1386 rStrm
<< maData
.mnHAlign
1388 << maData
.mnBackMode
1389 << maData
.maTextComplexColor
.getFinalColor()
1393 if( GetBiff() == EXC_BIFF8
)
1395 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
)
1397 << maData
.mnRotation
;
1403 /** Creates and returns an Excel text object from the passed title. */
1404 XclExpChTextRef
lclCreateTitle( const XclExpChRoot
& rRoot
, Reference
< XTitled
> const & xTitled
, sal_uInt16 nTarget
,
1405 const OUString
* pSubTitle
= nullptr )
1407 Reference
< XTitle
> xTitle
;
1409 xTitle
= xTitled
->getTitleObject();
1411 XclExpChTextRef xText
= new XclExpChText( rRoot
);
1412 xText
->ConvertTitle( xTitle
, nTarget
, pSubTitle
);
1413 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1414 will be interpreted as auto-generated title showing the series title in
1415 charts that contain exactly one data series. */
1416 if( (nTarget
!= EXC_CHOBJLINK_TITLE
) && !xText
->HasString() )
1424 // Data series ================================================================
1426 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot
& rRoot
) :
1427 XclExpRecord( EXC_ID_CHMARKERFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 20 : 12 ),
1428 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) ),
1429 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
1433 void XclExpChMarkerFormat::Convert( const XclExpChRoot
& rRoot
,
1434 const ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
)
1436 XclChPropSetHelper::ReadMarkerProperties( maData
, rPropSet
, nFormatIdx
);
1437 /* Set marker line/fill color to series line color.
1438 TODO: remove this if OOChart supports own colors in markers. */
1440 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1441 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1442 // register colors in palette
1443 RegisterColors( rRoot
);
1446 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot
& rRoot
,
1447 const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1449 // clear the automatic flag
1450 ::set_flag( maData
.mnFlags
, EXC_CHMARKERFORMAT_AUTO
, false );
1451 // symbol type and color
1454 // set symbol type for the 'close' data series
1455 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_DOWJ
;
1456 maData
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
;
1457 // set symbol line/fill color to series line color
1459 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1461 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1462 RegisterColors( rRoot
);
1467 // set invisible symbol
1468 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_NOSYMBOL
;
1472 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot
& rRoot
)
1476 if( HasLineColor() )
1477 mnLineColorId
= rRoot
.GetPalette().InsertColor( maData
.maLineColor
, EXC_COLOR_CHARTLINE
);
1478 if( HasFillColor() )
1479 mnFillColorId
= rRoot
.GetPalette().InsertColor( maData
.maFillColor
, EXC_COLOR_CHARTAREA
);
1483 void XclExpChMarkerFormat::WriteBody( XclExpStream
& rStrm
)
1485 rStrm
<< maData
.maLineColor
<< maData
.maFillColor
<< maData
.mnMarkerType
<< maData
.mnFlags
;
1486 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
1488 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
1489 rStrm
<< rPal
.GetColorIndex( mnLineColorId
) << rPal
.GetColorIndex( mnFillColorId
) << maData
.mnMarkerSize
;
1493 XclExpChPieFormat::XclExpChPieFormat() :
1494 XclExpUInt16Record( EXC_ID_CHPIEFORMAT
, 0 )
1498 void XclExpChPieFormat::Convert( const ScfPropertySet
& rPropSet
)
1500 double fApiDist(0.0);
1501 if( rPropSet
.GetProperty( fApiDist
, EXC_CHPROP_OFFSET
) )
1502 SetValue( limit_cast
< sal_uInt16
>( fApiDist
* 100.0, 0, 100 ) );
1505 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1506 XclExpRecord( EXC_ID_CH3DDATAFORMAT
, 2 )
1510 void XclExpCh3dDataFormat::Convert( const ScfPropertySet
& rPropSet
)
1512 sal_Int32
nApiType(0);
1513 if( !rPropSet
.GetProperty( nApiType
, EXC_CHPROP_GEOMETRY3D
) )
1516 using namespace cssc2::DataPointGeometry3D
;
1520 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1521 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1524 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1525 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1528 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1529 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1532 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1533 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1536 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1540 void XclExpCh3dDataFormat::WriteBody( XclExpStream
& rStrm
)
1542 rStrm
<< maData
.mnBase
<< maData
.mnTop
;
1545 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags
) :
1546 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL
, nFlags
)
1550 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot
& rRoot
,
1551 const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
) :
1552 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DATAFORMAT
, EXC_ID_CHDATAFORMAT
, 8 )
1554 maData
.maPointPos
= rPointPos
;
1555 maData
.mnFormatIdx
= nFormatIdx
;
1558 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
)
1560 // line and area formatting
1561 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType() );
1563 // data point symbols
1564 bool bIsFrame
= rTypeInfo
.IsSeriesFrameFormat();
1567 mxMarkerFmt
= new XclExpChMarkerFormat( GetChRoot() );
1568 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1572 if( rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)
1574 mxPieFmt
= new XclExpChPieFormat();
1575 mxPieFmt
->Convert( rPropSet
);
1578 // 3D bars (only allowed for entire series in BIFF8)
1579 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8
) && rTypeInfo
.mb3dChart
&& (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
) )
1581 mx3dDataFmt
= new XclExpCh3dDataFormat();
1582 mx3dDataFmt
->Convert( rPropSet
);
1586 if( IsSeriesFormat() && rTypeInfo
.mbSpline
&& !bIsFrame
)
1587 mxSeriesFmt
= new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT
, EXC_CHSERIESFORMAT_SMOOTHED
);
1589 // data point labels
1590 XclExpChTextRef xLabel
= new XclExpChText( GetChRoot() );
1591 if( xLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, maData
.maPointPos
) )
1593 // CHTEXT groups for data labels are stored in global CHCHART group
1594 GetChartData().SetDataLabel( xLabel
);
1595 mxAttLabel
= new XclExpChAttachedLabel( xLabel
->GetAttLabelFlags() );
1599 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1601 // set line format to invisible
1602 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, false );
1603 // set symbols to invisible or to 'close' series symbol
1604 mxMarkerFmt
= new XclExpChMarkerFormat( GetChRoot() );
1605 mxMarkerFmt
->ConvertStockSymbol( GetChRoot(), rPropSet
, bCloseSymbol
);
1608 void XclExpChDataFormat::ConvertLine( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
1610 ConvertFrameBase( GetChRoot(), rPropSet
, eObjType
);
1613 void XclExpChDataFormat::WriteSubRecords( XclExpStream
& rStrm
)
1615 lclSaveRecord( rStrm
, mx3dDataFmt
);
1616 WriteFrameRecords( rStrm
);
1617 lclSaveRecord( rStrm
, mxPieFmt
);
1618 lclSaveRecord( rStrm
, mxMarkerFmt
);
1619 lclSaveRecord( rStrm
, mxSeriesFmt
);
1620 lclSaveRecord( rStrm
, mxAttLabel
);
1623 void XclExpChDataFormat::WriteBody( XclExpStream
& rStrm
)
1625 rStrm
<< maData
.maPointPos
.mnPointIdx
1626 << maData
.maPointPos
.mnSeriesIdx
1627 << maData
.mnFormatIdx
1631 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot
& rRoot
) :
1632 XclExpRecord( EXC_ID_CHSERTRENDLINE
, 28 ),
1633 XclExpChRoot( rRoot
)
1637 bool XclExpChSerTrendLine::Convert( Reference
< XRegressionCurve
> const & xRegCurve
, sal_uInt16 nSeriesIdx
)
1639 if( !xRegCurve
.is() )
1643 ScfPropertySet
aCurveProp( xRegCurve
);
1645 OUString aService
= aCurveProp
.GetServiceName();
1646 if( aService
== "com.sun.star.chart2.LinearRegressionCurve" )
1648 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1651 else if( aService
== "com.sun.star.chart2.ExponentialRegressionCurve" )
1653 maData
.mnLineType
= EXC_CHSERTREND_EXPONENTIAL
;
1655 else if( aService
== "com.sun.star.chart2.LogarithmicRegressionCurve" )
1657 maData
.mnLineType
= EXC_CHSERTREND_LOGARITHMIC
;
1659 else if( aService
== "com.sun.star.chart2.PotentialRegressionCurve" )
1661 maData
.mnLineType
= EXC_CHSERTREND_POWER
;
1663 else if( aService
== "com.sun.star.chart2.PolynomialRegressionCurve" )
1665 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1667 aCurveProp
.GetProperty(aDegree
, EXC_CHPROP_POLYNOMIAL_DEGREE
);
1668 maData
.mnOrder
= static_cast<sal_uInt8
> (aDegree
);
1670 else if( aService
== "com.sun.star.chart2.MovingAverageRegressionCurve" )
1672 maData
.mnLineType
= EXC_CHSERTREND_MOVING_AVG
;
1674 aCurveProp
.GetProperty(aPeriod
, EXC_CHPROP_MOVING_AVERAGE_PERIOD
);
1675 maData
.mnOrder
= static_cast<sal_uInt8
> (aPeriod
);
1682 aCurveProp
.GetProperty(maData
.mfForecastFor
, EXC_CHPROP_EXTRAPOLATE_FORWARD
);
1683 aCurveProp
.GetProperty(maData
.mfForecastBack
, EXC_CHPROP_EXTRAPOLATE_BACKWARD
);
1684 bool bIsForceIntercept
= false;
1685 aCurveProp
.GetProperty(bIsForceIntercept
, EXC_CHPROP_FORCE_INTERCEPT
);
1686 if (bIsForceIntercept
)
1687 aCurveProp
.GetProperty(maData
.mfIntercept
, EXC_CHPROP_INTERCEPT_VALUE
);
1690 XclChDataPointPos
aPointPos( nSeriesIdx
);
1691 mxDataFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, 0 );
1692 mxDataFmt
->ConvertLine( aCurveProp
, EXC_CHOBJTYPE_TRENDLINE
);
1694 // #i83100# show equation and correlation coefficient
1695 ScfPropertySet
aEquationProp( xRegCurve
->getEquationProperties() );
1696 maData
.mnShowEquation
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWEQUATION
) ? 1 : 0;
1697 maData
.mnShowRSquared
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION
) ? 1 : 0;
1699 // #i83100# formatting of the equation text box
1700 if( (maData
.mnShowEquation
!= 0) || (maData
.mnShowRSquared
!= 0) )
1702 mxLabel
= new XclExpChText( GetChRoot() );
1703 mxLabel
->ConvertTrendLineEquation( aEquationProp
, aPointPos
);
1707 // #i5085# manual trend line size
1708 // #i34093# manual crossing point
1712 void XclExpChSerTrendLine::WriteBody( XclExpStream
& rStrm
)
1714 rStrm
<< maData
.mnLineType
1716 << maData
.mfIntercept
1717 << maData
.mnShowEquation
1718 << maData
.mnShowRSquared
1719 << maData
.mfForecastFor
1720 << maData
.mfForecastBack
;
1723 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot
& rRoot
, sal_uInt8 nBarType
) :
1724 XclExpRecord( EXC_ID_CHSERERRORBAR
, 14 ),
1725 XclExpChRoot( rRoot
)
1727 maData
.mnBarType
= nBarType
;
1730 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink
& rValueLink
, sal_uInt16
& rnValueCount
, const ScfPropertySet
& rPropSet
)
1732 sal_Int32 nBarStyle
= 0;
1733 bool bOk
= rPropSet
.GetProperty( nBarStyle
, EXC_CHPROP_ERRORBARSTYLE
);
1738 case cssc::ErrorBarStyle::ABSOLUTE
:
1739 maData
.mnSourceType
= EXC_CHSERERR_FIXED
;
1740 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1742 case cssc::ErrorBarStyle::RELATIVE
:
1743 maData
.mnSourceType
= EXC_CHSERERR_PERCENT
;
1744 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1746 case cssc::ErrorBarStyle::STANDARD_DEVIATION
:
1747 maData
.mnSourceType
= EXC_CHSERERR_STDDEV
;
1748 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_WEIGHT
);
1750 case cssc::ErrorBarStyle::STANDARD_ERROR
:
1751 maData
.mnSourceType
= EXC_CHSERERR_STDERR
;
1753 case cssc::ErrorBarStyle::FROM_DATA
:
1756 maData
.mnSourceType
= EXC_CHSERERR_CUSTOM
;
1757 Reference
< XDataSource
> xDataSource( rPropSet
.GetApiPropertySet(), UNO_QUERY
);
1758 if( xDataSource
.is() )
1760 // find first sequence with current role
1761 OUString aRole
= XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
);
1762 Reference
< XDataSequence
> xValueSeq
;
1764 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1765 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1767 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1768 ScfPropertySet
aValueProp( xTmpValueSeq
);
1770 if( aValueProp
.GetProperty( aCurrRole
, EXC_CHPROP_ROLE
) && (aCurrRole
== aRole
) )
1772 xValueSeq
= std::move(xTmpValueSeq
);
1776 if( xValueSeq
.is() )
1778 // #i86465# pass value count back to series
1779 rnValueCount
= maData
.mnValueCount
= rValueLink
.ConvertDataSequence( xValueSeq
, true );
1780 bOk
= maData
.mnValueCount
> 0;
1792 void XclExpChSerErrorBar::WriteBody( XclExpStream
& rStrm
)
1794 rStrm
<< maData
.mnBarType
1795 << maData
.mnSourceType
1797 << sal_uInt8( 1 ) // must be 1 to make line visible
1799 << maData
.mnValueCount
;
1804 /** Returns the property set of the specified data point. */
1805 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> const & xDataSeries
, sal_Int32 nPointIdx
)
1807 ScfPropertySet aPropSet
;
1810 aPropSet
.Set( xDataSeries
->getDataPointByIndex( nPointIdx
) );
1814 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1821 XclExpChSeries::XclExpChSeries( const XclExpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1822 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_SERIES
, EXC_ID_CHSERIES
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 8 ),
1823 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1824 mnSeriesIdx( nSeriesIdx
),
1825 mnParentIdx( EXC_CHSERIES_INVALID
)
1827 // CHSOURCELINK records are always required, even if unused
1828 mxTitleLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1829 mxValueLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES
);
1830 mxCategLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY
);
1831 if( GetBiff() == EXC_BIFF8
)
1832 mxBubbleLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES
);
1835 bool XclExpChSeries::ConvertDataSeries(
1836 Reference
< XDiagram
> const & xDiagram
, Reference
< XDataSeries
> const & xDataSeries
,
1837 const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
)
1840 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1841 if( xDataSource
.is() )
1843 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
, xXValueSeq
, xBubbleSeq
;
1845 // find first sequence with role 'values-y'
1846 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1847 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1849 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1850 ScfPropertySet
aValueProp( xTmpValueSeq
);
1852 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) )
1854 if( !xYValueSeq
.is() && (aRole
== EXC_CHPROP_ROLE_YVALUES
) )
1856 xYValueSeq
= std::move(xTmpValueSeq
);
1857 if( !xTitleSeq
.is() )
1858 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1860 else if( !xXValueSeq
.is() && !rTypeInfo
.mbCategoryAxis
&& (aRole
== EXC_CHPROP_ROLE_XVALUES
) )
1862 xXValueSeq
= std::move(xTmpValueSeq
);
1864 else if( !xBubbleSeq
.is() && (rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
) && (aRole
== EXC_CHPROP_ROLE_SIZEVALUES
) )
1866 xBubbleSeq
= std::move(xTmpValueSeq
);
1867 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1872 bOk
= xYValueSeq
.is();
1875 // chart type group index
1876 mnGroupIdx
= nGroupIdx
;
1878 // convert source links
1879 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1880 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1882 // X values of XY charts
1883 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xXValueSeq
, false, maData
.mnValueCount
);
1885 // size values of bubble charts
1887 mxBubbleLink
->ConvertDataSequence( xBubbleSeq
, false, maData
.mnValueCount
);
1889 // series formatting
1890 XclChDataPointPos
aPointPos( mnSeriesIdx
);
1891 ScfPropertySet
aSeriesProp( xDataSeries
);
1892 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
);
1893 mxSeriesFmt
->ConvertDataSeries( aSeriesProp
, rTypeInfo
);
1896 CreateTrendLines( xDataSeries
);
1899 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARX
, EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
1900 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARY
, EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
1902 if( maData
.mnValueCount
> 0 )
1904 const sal_Int32 nMaxPointCount
= maData
.mnValueCount
;
1906 /* #i91063# Create missing fill properties in pie/doughnut charts.
1907 If freshly created (never saved to ODF), these charts show
1908 varying point colors but do not return these points via API. */
1909 if( xDiagram
.is() && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
1911 Reference
< XColorScheme
> xColorScheme
= xDiagram
->getDefaultColorScheme();
1912 if( xColorScheme
.is() )
1914 static constexpr OUStringLiteral aFillStyleName
= u
"FillStyle";
1915 static constexpr OUString aColorName
= u
"Color"_ustr
;
1916 namespace cssd
= ::com::sun::star::drawing
;
1917 for( sal_Int32 nPointIdx
= 0; nPointIdx
< nMaxPointCount
; ++nPointIdx
)
1919 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( nPointIdx
);
1920 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
1921 // test that the point fill style is solid, but no color is set
1922 cssd::FillStyle eFillStyle
= cssd::FillStyle_NONE
;
1923 if( aPointProp
.GetProperty( eFillStyle
, aFillStyleName
) &&
1924 (eFillStyle
== cssd::FillStyle_SOLID
) &&
1925 !aPointProp
.HasProperty( aColorName
) )
1927 aPointProp
.SetProperty( aColorName
, xColorScheme
->getColorByIndex( nPointIdx
) );
1933 // data point formatting
1934 Sequence
< sal_Int32
> aPointIndexes
;
1935 if( aSeriesProp
.GetProperty( aPointIndexes
, EXC_CHPROP_ATTRIBDATAPOINTS
) && aPointIndexes
.hasElements() )
1937 for (const sal_Int32 nPointIndex
: aPointIndexes
)
1939 if (nPointIndex
>= nMaxPointCount
)
1941 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( nPointIndex
);
1942 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIndex
);
1943 XclExpChDataFormatRef xPointFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
);
1944 xPointFmt
->ConvertDataSeries( aPointProp
, rTypeInfo
);
1945 maPointFmts
.AppendRecord( xPointFmt
);
1954 bool XclExpChSeries::ConvertStockSeries( css::uno::Reference
< css::chart2::XDataSeries
> const & xDataSeries
,
1955 std::u16string_view rValueRole
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
, bool bCloseSymbol
)
1958 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1959 if( xDataSource
.is() )
1961 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
;
1963 // find first sequence with passed role
1964 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1965 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1967 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1968 ScfPropertySet
aValueProp( xTmpValueSeq
);
1970 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) && (aRole
== rValueRole
) )
1972 xYValueSeq
= std::move(xTmpValueSeq
);
1973 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1978 bOk
= xYValueSeq
.is();
1981 // chart type group index
1982 mnGroupIdx
= nGroupIdx
;
1983 // convert source links
1984 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1985 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1986 // series formatting
1987 ScfPropertySet
aSeriesProp( xDataSeries
);
1988 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), nFormatIdx
);
1989 mxSeriesFmt
->ConvertStockSeries( aSeriesProp
, bCloseSymbol
);
1995 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries
& rParent
, Reference
< XRegressionCurve
> const & xRegCurve
)
1997 InitFromParent( rParent
);
1999 mxTrendLine
= new XclExpChSerTrendLine( GetChRoot() );
2000 bool bOk
= mxTrendLine
->Convert( xRegCurve
, mnSeriesIdx
);
2004 ScfPropertySet
aProperties( xRegCurve
);
2005 aProperties
.GetProperty(aName
, EXC_CHPROP_CURVENAME
);
2006 mxTitleLink
->ConvertString(aName
);
2008 mxSeriesFmt
= mxTrendLine
->GetDataFormat();
2009 GetChartData().SetDataLabel( mxTrendLine
->GetDataLabel() );
2014 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries
& rParent
, const ScfPropertySet
& rPropSet
, sal_uInt8 nBarId
)
2016 InitFromParent( rParent
);
2017 // error bar settings
2018 mxErrorBar
= new XclExpChSerErrorBar( GetChRoot(), nBarId
);
2019 bool bOk
= mxErrorBar
->Convert( *mxValueLink
, maData
.mnValueCount
, rPropSet
);
2022 // error bar formatting
2023 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), 0 );
2024 mxSeriesFmt
->ConvertLine( rPropSet
, EXC_CHOBJTYPE_ERRORBAR
);
2029 void XclExpChSeries::ConvertCategSequence( Reference
< XLabeledDataSequence
> const & xCategSeq
)
2031 if( xCategSeq
.is() )
2032 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xCategSeq
->getValues(), false );
2035 void XclExpChSeries::WriteSubRecords( XclExpStream
& rStrm
)
2037 lclSaveRecord( rStrm
, mxTitleLink
);
2038 lclSaveRecord( rStrm
, mxValueLink
);
2039 lclSaveRecord( rStrm
, mxCategLink
);
2040 lclSaveRecord( rStrm
, mxBubbleLink
);
2041 lclSaveRecord( rStrm
, mxSeriesFmt
);
2042 maPointFmts
.Save( rStrm
);
2043 if( mnGroupIdx
!= EXC_CHSERGROUP_NONE
)
2044 XclExpUInt16Record( EXC_ID_CHSERGROUP
, mnGroupIdx
).Save( rStrm
);
2045 if( mnParentIdx
!= EXC_CHSERIES_INVALID
)
2046 XclExpUInt16Record( EXC_ID_CHSERPARENT
, mnParentIdx
).Save( rStrm
);
2047 lclSaveRecord( rStrm
, mxTrendLine
);
2048 lclSaveRecord( rStrm
, mxErrorBar
);
2051 void XclExpChSeries::InitFromParent( const XclExpChSeries
& rParent
)
2053 // index to parent series is stored 1-based
2054 mnParentIdx
= rParent
.mnSeriesIdx
+ 1;
2055 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2056 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2057 maData
.mnCategCount
= rParent
.maData
.mnCategCount
;
2058 maData
.mnValueCount
= rParent
.maData
.mnValueCount
;
2061 void XclExpChSeries::CreateTrendLines( css::uno::Reference
< css::chart2::XDataSeries
> const & xDataSeries
)
2063 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2064 if( xRegCurveCont
.is() )
2066 const Sequence
< Reference
< XRegressionCurve
> > aRegCurveSeq
= xRegCurveCont
->getRegressionCurves();
2067 for( const Reference
< XRegressionCurve
>& rRegCurve
: aRegCurveSeq
)
2069 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2070 if( xSeries
&& !xSeries
->ConvertTrendLine( *this, rRegCurve
) )
2071 GetChartData().RemoveLastSeries();
2076 void XclExpChSeries::CreateErrorBars( const ScfPropertySet
& rPropSet
,
2077 const OUString
& rBarPropName
, sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
)
2079 Reference
< XPropertySet
> xErrorBar
;
2080 if( rPropSet
.GetProperty( xErrorBar
, rBarPropName
) && xErrorBar
.is() )
2082 ScfPropertySet
aErrorProp( xErrorBar
);
2083 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWPOSITIVEERROR
, nPosBarId
);
2084 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWNEGATIVEERROR
, nNegBarId
);
2088 void XclExpChSeries::CreateErrorBar( const ScfPropertySet
& rPropSet
,
2089 const OUString
& rShowPropName
, sal_uInt8 nBarId
)
2091 if( rPropSet
.GetBoolProperty( rShowPropName
) )
2093 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2094 if( xSeries
&& !xSeries
->ConvertErrorBar( *this, rPropSet
, nBarId
) )
2095 GetChartData().RemoveLastSeries();
2099 void XclExpChSeries::WriteBody( XclExpStream
& rStrm
)
2101 rStrm
<< maData
.mnCategType
<< maData
.mnValueType
<< maData
.mnCategCount
<< maData
.mnValueCount
;
2102 if( GetBiff() == EXC_BIFF8
)
2103 rStrm
<< maData
.mnBubbleType
<< maData
.mnBubbleCount
;
2106 // Chart type groups ==========================================================
2108 XclExpChType::XclExpChType( const XclExpChRoot
& rRoot
) :
2109 XclExpRecord( EXC_ID_CHUNKNOWN
),
2110 XclExpChRoot( rRoot
),
2111 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2115 void XclExpChType::Convert( Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2116 sal_Int32 nApiAxesSetIdx
, bool bSwappedAxesSet
, bool bHasXLabels
)
2118 if( !xChartType
.is() )
2121 maTypeInfo
= GetChartTypeInfo( xChartType
->getChartType() );
2122 // special handling for some chart types
2123 switch( maTypeInfo
.meTypeCateg
)
2125 case EXC_CHTYPECATEG_BAR
:
2127 maTypeInfo
= GetChartTypeInfo( bSwappedAxesSet
? EXC_CHTYPEID_HORBAR
: EXC_CHTYPEID_BAR
);
2128 ::set_flag( maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
, bSwappedAxesSet
);
2129 ScfPropertySet
aTypeProp( xChartType
);
2130 Sequence
< sal_Int32
> aInt32Seq
;
2131 maData
.mnOverlap
= 0;
2132 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_OVERLAPSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2133 maData
.mnOverlap
= limit_cast
< sal_Int16
>( -aInt32Seq
[ nApiAxesSetIdx
], -100, 100 );
2135 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_GAPWIDTHSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2136 maData
.mnGap
= limit_cast
< sal_uInt16
>( aInt32Seq
[ nApiAxesSetIdx
], 0, 500 );
2139 case EXC_CHTYPECATEG_RADAR
:
2140 ::set_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
, bHasXLabels
);
2142 case EXC_CHTYPECATEG_PIE
:
2144 ScfPropertySet
aTypeProp( xChartType
);
2145 bool bDonut
= aTypeProp
.GetBoolProperty( EXC_CHPROP_USERINGS
);
2146 maTypeInfo
= GetChartTypeInfo( bDonut
? EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2147 maData
.mnPieHole
= bDonut
? 50 : 0;
2148 // #i85166# starting angle of first pie slice
2149 ScfPropertySet
aDiaProp( xDiagram
);
2150 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( aDiaProp
);
2153 case EXC_CHTYPECATEG_SCATTER
:
2154 if( GetBiff() == EXC_BIFF8
)
2155 ::set_flag( maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
);
2159 SetRecId( maTypeInfo
.mnRecId
);
2162 void XclExpChType::SetStacked( bool bPercent
)
2164 switch( maTypeInfo
.meTypeCateg
)
2166 case EXC_CHTYPECATEG_LINE
:
2167 ::set_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
);
2168 ::set_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
, bPercent
);
2170 case EXC_CHTYPECATEG_BAR
:
2171 ::set_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
);
2172 ::set_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
, bPercent
);
2173 maData
.mnOverlap
= -100;
2179 void XclExpChType::WriteBody( XclExpStream
& rStrm
)
2181 switch( GetRecId() )
2184 rStrm
<< maData
.mnOverlap
<< maData
.mnGap
<< maData
.mnFlags
;
2189 case EXC_ID_CHRADARLINE
:
2190 case EXC_ID_CHRADARAREA
:
2191 rStrm
<< maData
.mnFlags
;
2195 rStrm
<< maData
.mnRotation
<< maData
.mnPieHole
;
2196 if( GetBiff() == EXC_BIFF8
)
2197 rStrm
<< maData
.mnFlags
;
2200 case EXC_ID_CHSCATTER
:
2201 if( GetBiff() == EXC_BIFF8
)
2202 rStrm
<< maData
.mnBubbleSize
<< maData
.mnBubbleType
<< maData
.mnFlags
;
2206 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" );
2210 XclExpChChart3d::XclExpChChart3d() :
2211 XclExpRecord( EXC_ID_CHCHART3D
, 14 )
2215 void XclExpChChart3d::Convert( const ScfPropertySet
& rPropSet
, bool b3dWallChart
)
2217 sal_Int32 nRotationY
= 0;
2218 rPropSet
.GetProperty( nRotationY
, EXC_CHPROP_ROTATIONVERTICAL
);
2219 sal_Int32 nRotationX
= 0;
2220 rPropSet
.GetProperty( nRotationX
, EXC_CHPROP_ROTATIONHORIZONTAL
);
2221 sal_Int32 nPerspective
= 15;
2222 rPropSet
.GetProperty( nPerspective
, EXC_CHPROP_PERSPECTIVE
);
2226 // Y rotation (Excel [0..359], Chart2 [-179,180])
2227 if( nRotationY
< 0 ) nRotationY
+= 360;
2228 maData
.mnRotation
= static_cast< sal_uInt16
>( nRotationY
);
2229 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2230 maData
.mnElevation
= limit_cast
< sal_Int16
>( nRotationX
, -90, 90 );
2231 // perspective (Excel and Chart2 [0,100])
2232 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2235 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
, !rPropSet
.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
) );
2236 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_AUTOHEIGHT
);
2237 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_HASWALLS
);
2241 // Y rotation not used in pie charts, but 'first pie slice angle'
2242 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( rPropSet
);
2243 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2244 maData
.mnElevation
= limit_cast
< sal_Int16
>( (nRotationX
+ 270) % 180, 10, 80 );
2245 // perspective (Excel and Chart2 [0,100])
2246 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2252 void XclExpChChart3d::WriteBody( XclExpStream
& rStrm
)
2254 rStrm
<< maData
.mnRotation
2255 << maData
.mnElevation
2257 << maData
.mnRelHeight
2258 << maData
.mnRelDepth
2259 << maData
.mnDepthGap
2263 XclExpChLegend::XclExpChLegend( const XclExpChRoot
& rRoot
) :
2264 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_LEGEND
, EXC_ID_CHLEGEND
, 20 )
2268 void XclExpChLegend::Convert( const ScfPropertySet
& rPropSet
)
2271 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_LEGEND
);
2273 mxText
= new XclExpChText( GetChRoot() );
2274 mxText
->ConvertLegend( rPropSet
);
2276 // legend position and size
2277 Any aRelPosAny
, aRelSizeAny
;
2278 rPropSet
.GetAnyProperty( aRelPosAny
, EXC_CHPROP_RELATIVEPOSITION
);
2279 rPropSet
.GetAnyProperty( aRelSizeAny
, EXC_CHPROP_RELATIVESIZE
);
2280 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2281 rPropSet
.GetProperty( eApiExpand
, EXC_CHPROP_EXPANSION
);
2282 if( aRelPosAny
.has
< RelativePosition
>() || ((eApiExpand
== cssc::ChartLegendExpansion_CUSTOM
) && aRelSizeAny
.has
< RelativeSize
>()) )
2286 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2287 indicator of manually changed legend position/size, but due to
2288 the different anchor modes used by this property (in the
2289 RelativePosition.Anchor member) it cannot be used to calculate
2290 the position easily. For this, the Chart1 API will be used
2292 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
2293 Reference
< XShape
> xChart1Legend( xChart1Doc
->getLegend(), UNO_SET_THROW
);
2294 // coordinates in CHLEGEND record written but not used by Excel
2295 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE
);
2296 XclChFramePos
& rFramePos
= mxFramePos
->GetFramePosData();
2297 rFramePos
.mnTLMode
= EXC_CHFRAMEPOS_CHARTSIZE
;
2298 css::awt::Point aLegendPos
= xChart1Legend
->getPosition();
2299 rFramePos
.maRect
.mnX
= maData
.maRect
.mnX
= CalcChartXFromHmm( aLegendPos
.X
);
2300 rFramePos
.maRect
.mnY
= maData
.maRect
.mnY
= CalcChartYFromHmm( aLegendPos
.Y
);
2301 // legend size, Excel expects points in CHFRAMEPOS record
2302 rFramePos
.mnBRMode
= EXC_CHFRAMEPOS_ABSSIZE_POINTS
;
2303 css::awt::Size aLegendSize
= xChart1Legend
->getSize();
2304 rFramePos
.maRect
.mnWidth
= o3tl::convert(aLegendSize
.Width
, o3tl::Length::mm100
, o3tl::Length::pt
);
2305 rFramePos
.maRect
.mnHeight
= o3tl::convert(aLegendSize
.Height
, o3tl::Length::mm100
, o3tl::Length::pt
);
2306 maData
.maRect
.mnWidth
= CalcChartXFromHmm( aLegendSize
.Width
);
2307 maData
.maRect
.mnHeight
= CalcChartYFromHmm( aLegendSize
.Height
);
2308 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2309 // manual legend position implies manual plot area
2310 GetChartData().SetManualPlotArea();
2311 maData
.mnDockMode
= EXC_CHLEGEND_NOTDOCKED
;
2312 // a CHFRAME record with cleared auto flags is needed
2314 mxFrame
= new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2315 mxFrame
->SetAutoFlags( false, false );
2319 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
2320 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2321 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2326 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_LINE_END
;
2327 rPropSet
.GetProperty( eApiPos
, EXC_CHPROP_ANCHORPOSITION
);
2330 case cssc2::LegendPosition_LINE_START
: maData
.mnDockMode
= EXC_CHLEGEND_LEFT
; break;
2331 case cssc2::LegendPosition_LINE_END
: maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
; break;
2332 case cssc2::LegendPosition_PAGE_START
: maData
.mnDockMode
= EXC_CHLEGEND_TOP
; break;
2333 case cssc2::LegendPosition_PAGE_END
: maData
.mnDockMode
= EXC_CHLEGEND_BOTTOM
; break;
2335 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
2336 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2337 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2340 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_STACKED
, eApiExpand
== cssc::ChartLegendExpansion_HIGH
);
2343 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_AUTOSERIES
);
2344 const sal_uInt16 nAutoFlags
= EXC_CHLEGEND_DOCKED
| EXC_CHLEGEND_AUTOPOSX
| EXC_CHLEGEND_AUTOPOSY
;
2345 ::set_flag( maData
.mnFlags
, nAutoFlags
, maData
.mnDockMode
!= EXC_CHLEGEND_NOTDOCKED
);
2348 void XclExpChLegend::WriteSubRecords( XclExpStream
& rStrm
)
2350 lclSaveRecord( rStrm
, mxFramePos
);
2351 lclSaveRecord( rStrm
, mxText
);
2352 lclSaveRecord( rStrm
, mxFrame
);
2355 void XclExpChLegend::WriteBody( XclExpStream
& rStrm
)
2357 rStrm
<< maData
.maRect
<< maData
.mnDockMode
<< maData
.mnSpacing
<< maData
.mnFlags
;
2360 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
2361 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DROPBAR
, EXC_ID_CHDROPBAR
, 2 ),
2362 meObjType( eObjType
)
2366 void XclExpChDropBar::Convert( const ScfPropertySet
& rPropSet
)
2369 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
2371 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, true );
2374 void XclExpChDropBar::WriteSubRecords( XclExpStream
& rStrm
)
2376 WriteFrameRecords( rStrm
);
2379 void XclExpChDropBar::WriteBody( XclExpStream
& rStrm
)
2381 rStrm
<< sal_uInt16(100); // Distance between bars (CHDROPBAR record).
2384 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot
& rRoot
, sal_uInt16 nGroupIdx
) :
2385 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TYPEGROUP
, EXC_ID_CHTYPEGROUP
, 20 ),
2387 maTypeInfo( maType
.GetTypeInfo() )
2389 maData
.mnGroupIdx
= nGroupIdx
;
2392 void XclExpChTypeGroup::ConvertType(
2393 Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2394 sal_Int32 nApiAxesSetIdx
, bool b3dChart
, bool bSwappedAxesSet
, bool bHasXLabels
)
2396 // chart type settings
2397 maType
.Convert( xDiagram
, xChartType
, nApiAxesSetIdx
, bSwappedAxesSet
, bHasXLabels
);
2399 // spline - TODO: get from single series (#i66858#)
2400 ScfPropertySet
aTypeProp( xChartType
);
2401 cssc2::CurveStyle eCurveStyle
;
2402 bool bSpline
= aTypeProp
.GetProperty( eCurveStyle
, EXC_CHPROP_CURVESTYLE
) &&
2403 (eCurveStyle
!= cssc2::CurveStyle_LINES
);
2405 // extended type info
2406 maTypeInfo
.Set( maType
.GetTypeInfo(), b3dChart
, bSpline
);
2408 // 3d chart settings
2409 if( maTypeInfo
.mb3dChart
) // only true, if Excel chart supports 3d mode
2411 mxChart3d
= new XclExpChChart3d();
2412 ScfPropertySet
aDiaProp( xDiagram
);
2413 mxChart3d
->Convert( aDiaProp
, Is3dWallChart() );
2417 void XclExpChTypeGroup::ConvertSeries(
2418 Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2419 sal_Int32 nGroupAxesSetIdx
, bool bPercent
, bool bConnectBars
)
2421 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2422 if( !xSeriesCont
.is() )
2425 std::vector
< Reference
< XDataSeries
> > aSeriesVec
;
2427 // copy data series attached to the current axes set to the vector
2428 const Sequence
< Reference
< XDataSeries
> > aSeriesSeq
= xSeriesCont
->getDataSeries();
2429 for( const Reference
< XDataSeries
>& rSeries
: aSeriesSeq
)
2431 ScfPropertySet
aSeriesProp( rSeries
);
2432 sal_Int32
nSeriesAxesSetIdx(0);
2433 if( aSeriesProp
.GetProperty( nSeriesAxesSetIdx
, EXC_CHPROP_ATTAXISINDEX
) && (nSeriesAxesSetIdx
== nGroupAxesSetIdx
) )
2434 aSeriesVec
.push_back( rSeries
);
2437 // Are there any series in the current axes set?
2438 if( aSeriesVec
.empty() )
2441 // stacking direction (stacked/percent/deep 3d) from first series
2442 ScfPropertySet
aSeriesProp( aSeriesVec
.front() );
2443 cssc2::StackingDirection eStacking
;
2444 if( !aSeriesProp
.GetProperty( eStacking
, EXC_CHPROP_STACKINGDIR
) )
2445 eStacking
= cssc2::StackingDirection_NO_STACKING
;
2447 // stacked or percent chart
2448 if( maTypeInfo
.mbSupportsStacking
&& (eStacking
== cssc2::StackingDirection_Y_STACKING
) )
2450 // percent overrides simple stacking
2451 maType
.SetStacked( bPercent
);
2453 // connected data points (only in stacked bar charts)
2454 if (bConnectBars
&& (maTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
))
2456 sal_uInt16 nKey
= EXC_CHCHARTLINE_CONNECT
;
2457 m_ChartLines
.insert(std::make_pair(nKey
, std::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2462 // reverse series order for some unstacked 2D chart types
2463 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() )
2464 ::std::reverse( aSeriesVec
.begin(), aSeriesVec
.end() );
2467 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2468 if( (eStacking
== cssc2::StackingDirection_NO_STACKING
) && Is3dWallChart() )
2469 mxChart3d
->SetClustered();
2471 // varied point colors
2472 ::set_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
, aSeriesProp
.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY
) );
2474 // process all series
2475 for( const auto& rxSeries
: aSeriesVec
)
2477 // create Excel series object, stock charts need special processing
2478 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2479 CreateAllStockSeries( xChartType
, rxSeries
);
2481 CreateDataSeries( xDiagram
, rxSeries
);
2485 void XclExpChTypeGroup::ConvertCategSequence( Reference
< XLabeledDataSequence
> const & xCategSeq
)
2487 for( size_t nIdx
= 0, nSize
= maSeries
.GetSize(); nIdx
< nSize
; ++nIdx
)
2488 maSeries
.GetRecord( nIdx
)->ConvertCategSequence( xCategSeq
);
2491 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet
& rPropSet
)
2493 if( rPropSet
.GetBoolProperty( EXC_CHPROP_SHOW
) )
2495 mxLegend
= new XclExpChLegend( GetChRoot() );
2496 mxLegend
->Convert( rPropSet
);
2500 void XclExpChTypeGroup::WriteSubRecords( XclExpStream
& rStrm
)
2502 maType
.Save( rStrm
);
2503 lclSaveRecord( rStrm
, mxChart3d
);
2504 lclSaveRecord( rStrm
, mxLegend
);
2505 lclSaveRecord( rStrm
, mxUpBar
);
2506 lclSaveRecord( rStrm
, mxDownBar
);
2507 for (auto const& it
: m_ChartLines
)
2509 lclSaveRecord( rStrm
, it
.second
.get(), EXC_ID_CHCHARTLINE
, it
.first
);
2513 sal_uInt16
XclExpChTypeGroup::GetFreeFormatIdx() const
2515 return static_cast< sal_uInt16
>( maSeries
.GetSize() );
2518 void XclExpChTypeGroup::CreateDataSeries(
2519 Reference
< XDiagram
> const & xDiagram
, Reference
< XDataSeries
> const & xDataSeries
)
2521 // let chart create series object with correct series index
2522 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2525 if( xSeries
->ConvertDataSeries( xDiagram
, xDataSeries
, maTypeInfo
, GetGroupIdx(), GetFreeFormatIdx() ) )
2526 maSeries
.AppendRecord( xSeries
);
2528 GetChartData().RemoveLastSeries();
2532 void XclExpChTypeGroup::CreateAllStockSeries(
2533 Reference
< XChartType
> const & xChartType
, Reference
< XDataSeries
> const & xDataSeries
)
2535 // create existing series objects
2536 bool bHasOpen
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_OPENVALUES
, false );
2537 bool bHasHigh
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_HIGHVALUES
, false );
2538 bool bHasLow
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_LOWVALUES
, false );
2539 bool bHasClose
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_CLOSEVALUES
, !bHasOpen
);
2541 // formatting of special stock chart elements
2542 ScfPropertySet
aTypeProp( xChartType
);
2544 if( bHasHigh
&& bHasLow
&& aTypeProp
.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
) )
2546 ScfPropertySet
aSeriesProp( xDataSeries
);
2547 XclExpChLineFormatRef xLineFmt
= new XclExpChLineFormat( GetChRoot() );
2548 xLineFmt
->Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2549 sal_uInt16 nKey
= EXC_CHCHARTLINE_HILO
;
2550 m_ChartLines
.insert(std::make_pair(nKey
, std::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2553 if( !(bHasOpen
&& bHasClose
) )
2556 // dropbar type is dependent on position in the file - always create both
2557 Reference
< XPropertySet
> xWhitePropSet
, xBlackPropSet
;
2558 // white dropbar format
2559 aTypeProp
.GetProperty( xWhitePropSet
, EXC_CHPROP_WHITEDAY
);
2560 ScfPropertySet
aWhiteProp( xWhitePropSet
);
2561 mxUpBar
= new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR
);
2562 mxUpBar
->Convert( aWhiteProp
);
2563 // black dropbar format
2564 aTypeProp
.GetProperty( xBlackPropSet
, EXC_CHPROP_BLACKDAY
);
2565 ScfPropertySet
aBlackProp( xBlackPropSet
);
2566 mxDownBar
= new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR
);
2567 mxDownBar
->Convert( aBlackProp
);
2570 bool XclExpChTypeGroup::CreateStockSeries( Reference
< XDataSeries
> const & xDataSeries
,
2571 std::u16string_view rValueRole
, bool bCloseSymbol
)
2574 // let chart create series object with correct series index
2575 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2578 bOk
= xSeries
->ConvertStockSeries( xDataSeries
,
2579 rValueRole
, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol
);
2581 maSeries
.AppendRecord( xSeries
);
2583 GetChartData().RemoveLastSeries();
2588 void XclExpChTypeGroup::WriteBody( XclExpStream
& rStrm
)
2590 rStrm
.WriteZeroBytes( 16 );
2591 rStrm
<< maData
.mnFlags
<< maData
.mnGroupIdx
;
2594 // Axes =======================================================================
2596 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot
& rRoot
) :
2597 XclExpRecord( EXC_ID_CHLABELRANGE
, 8 ),
2598 XclExpChRoot( rRoot
)
2602 void XclExpChLabelRange::Convert( const ScaleData
& rScaleData
, const ScfPropertySet
& rChart1Axis
, bool bMirrorOrient
)
2604 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2605 chart API allows to detect axis type (date axis, if property exists),
2606 and to receive the base time unit currently used in case the base time
2607 unit is set to 'automatic'. */
2608 cssc::TimeIncrement aTimeIncrement
;
2609 if( rChart1Axis
.GetProperty( aTimeIncrement
, EXC_CHPROP_EXPTIMEINCREMENT
) )
2611 // property exists -> this is a date axis currently
2612 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2614 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2615 bool bAutoBase
= !rScaleData
.TimeIncrement
.TimeResolution
.has
< cssc::TimeIncrement
>();
2616 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
, bAutoBase
);
2618 // ...but get the current base time unit from the property of the old chart API
2619 sal_Int32 nApiTimeUnit
= 0;
2620 bool bValidBaseUnit
= aTimeIncrement
.TimeResolution
>>= nApiTimeUnit
;
2621 OSL_ENSURE( bValidBaseUnit
, "XclExpChLabelRange::Convert - cannot get base time unit" );
2622 maDateData
.mnBaseUnit
= bValidBaseUnit
? lclGetTimeUnit( nApiTimeUnit
) : EXC_CHDATERANGE_DAYS
;
2624 /* Min/max values depend on base time unit, they specify the number of
2625 days, months, or years starting from null date. */
2626 bool bAutoMin
= lclConvertTimeValue( GetRoot(), maDateData
.mnMinDate
, rScaleData
.Minimum
, maDateData
.mnBaseUnit
);
2627 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
, bAutoMin
);
2628 bool bAutoMax
= lclConvertTimeValue( GetRoot(), maDateData
.mnMaxDate
, rScaleData
.Maximum
, maDateData
.mnBaseUnit
);
2629 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
, bAutoMax
);
2632 // automatic axis type detection
2633 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
, rScaleData
.AutoDateAxis
);
2636 bool bAutoMajor
= lclConvertTimeInterval( maDateData
.mnMajorStep
, maDateData
.mnMajorUnit
, rScaleData
.TimeIncrement
.MajorTimeInterval
);
2637 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
, bAutoMajor
);
2638 bool bAutoMinor
= lclConvertTimeInterval( maDateData
.mnMinorStep
, maDateData
.mnMinorUnit
, rScaleData
.TimeIncrement
.MinorTimeInterval
);
2639 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
, bAutoMinor
);
2642 double fOrigin
= 0.0;
2643 if( !lclIsAutoAnyOrGetValue( fOrigin
, rScaleData
.Origin
) )
2644 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fOrigin
, 1, 31999 );
2647 if( (rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
) != bMirrorOrient
)
2648 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
);
2651 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2653 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2654 rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
);
2655 double fCrossingPos
= 1.0;
2656 rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
);
2658 bool bDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2661 case cssc::ChartAxisPosition_ZERO
:
2662 case cssc::ChartAxisPosition_START
:
2663 maLabelData
.mnCross
= 1;
2664 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2666 case cssc::ChartAxisPosition_END
:
2667 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_MAXCROSS
);
2669 case cssc::ChartAxisPosition_VALUE
:
2670 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fCrossingPos
, 1, 31999 );
2671 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
, false );
2673 maDateData
.mnCross
= lclGetTimeValue( GetRoot(), fCrossingPos
, maDateData
.mnBaseUnit
);
2676 maLabelData
.mnCross
= 1;
2677 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2681 void XclExpChLabelRange::Save( XclExpStream
& rStrm
)
2683 // the CHLABELRANGE record
2684 XclExpRecord::Save( rStrm
);
2686 // the CHDATERANGE record with date axis settings (BIFF8 only)
2687 if( GetBiff() != EXC_BIFF8
)
2690 rStrm
.StartRecord( EXC_ID_CHDATERANGE
, 18 );
2691 rStrm
<< maDateData
.mnMinDate
2692 << maDateData
.mnMaxDate
2693 << maDateData
.mnMajorStep
2694 << maDateData
.mnMajorUnit
2695 << maDateData
.mnMinorStep
2696 << maDateData
.mnMinorUnit
2697 << maDateData
.mnBaseUnit
2698 << maDateData
.mnCross
2699 << maDateData
.mnFlags
;
2703 void XclExpChLabelRange::WriteBody( XclExpStream
& rStrm
)
2705 rStrm
<< maLabelData
.mnCross
<< maLabelData
.mnLabelFreq
<< maLabelData
.mnTickFreq
<< maLabelData
.mnFlags
;
2708 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot
& rRoot
) :
2709 XclExpRecord( EXC_ID_CHVALUERANGE
, 42 ),
2710 XclExpChRoot( rRoot
)
2714 void XclExpChValueRange::Convert( const ScaleData
& rScaleData
)
2716 // scaling algorithm
2717 bool bLogScale
= ScfApiHelper::GetServiceName( rScaleData
.Scaling
) == "com.sun.star.chart2.LogarithmicScaling";
2718 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, bLogScale
);
2721 bool bAutoMin
= lclIsAutoAnyOrGetScaledValue( maData
.mfMin
, rScaleData
.Minimum
, bLogScale
);
2722 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
, bAutoMin
);
2723 bool bAutoMax
= lclIsAutoAnyOrGetScaledValue( maData
.mfMax
, rScaleData
.Maximum
, bLogScale
);
2724 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
, bAutoMax
);
2727 bool bAutoCross
= lclIsAutoAnyOrGetScaledValue( maData
.mfCross
, rScaleData
.Origin
, bLogScale
);
2728 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, bAutoCross
);
2731 const IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
2732 const bool bAutoMajor
= lclIsAutoAnyOrGetValue( maData
.mfMajorStep
, rIncrementData
.Distance
) || (maData
.mfMajorStep
<= 0.0);
2733 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
, bAutoMajor
);
2735 const Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
2736 sal_Int32 nCount
= 0;
2738 // tdf#114168 If IntervalCount is 5, then enable automatic minor calculation.
2739 // During import, if minorUnit is set and majorUnit not, then it is impossible
2740 // to calculate IntervalCount.
2741 const bool bAutoMinor
= bLogScale
|| bAutoMajor
|| !rSubIncrementSeq
.hasElements() ||
2742 lclIsAutoAnyOrGetValue( nCount
, rSubIncrementSeq
[ 0 ].IntervalCount
) || (nCount
< 1) || (nCount
== 5);
2744 if( maData
.mfMajorStep
&& !bAutoMinor
)
2745 maData
.mfMinorStep
= maData
.mfMajorStep
/ nCount
;
2746 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
, bAutoMinor
);
2749 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
, rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
);
2752 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2754 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2755 double fCrossingPos
= 0.0;
2756 if( !(rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
) && rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
)) )
2761 case cssc::ChartAxisPosition_ZERO
:
2762 case cssc::ChartAxisPosition_START
:
2763 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2765 case cssc::ChartAxisPosition_END
:
2766 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
2768 case cssc::ChartAxisPosition_VALUE
:
2769 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, false );
2770 maData
.mfCross
= ::get_flagvalue
< double >( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, log( fCrossingPos
) / log( 10.0 ), fCrossingPos
);
2773 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2777 void XclExpChValueRange::WriteBody( XclExpStream
& rStrm
)
2779 rStrm
<< maData
.mfMin
2781 << maData
.mfMajorStep
2782 << maData
.mfMinorStep
2789 sal_uInt8
lclGetXclTickPos( sal_Int32 nApiTickmarks
)
2791 using namespace cssc2::TickmarkStyle
;
2792 sal_uInt8 nXclTickPos
= 0;
2793 ::set_flag( nXclTickPos
, EXC_CHTICK_INSIDE
, ::get_flag( nApiTickmarks
, INNER
) );
2794 ::set_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
, ::get_flag( nApiTickmarks
, OUTER
) );
2800 XclExpChTick::XclExpChTick( const XclExpChRoot
& rRoot
) :
2801 XclExpRecord( EXC_ID_CHTICK
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 30 : 26 ),
2802 XclExpChRoot( rRoot
),
2803 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
2807 void XclExpChTick::Convert( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nAxisType
)
2810 sal_Int32 nApiTickmarks
= 0;
2811 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MAJORTICKS
) )
2812 maData
.mnMajor
= lclGetXclTickPos( nApiTickmarks
);
2813 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MINORTICKS
) )
2814 maData
.mnMinor
= lclGetXclTickPos( nApiTickmarks
);
2817 if( (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) && (nAxisType
== EXC_CHAXIS_X
) )
2819 /* Radar charts disable their category labels via chart type, not via
2820 axis, and axis labels are always 'near axis'. */
2821 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2823 else if( !rPropSet
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
) )
2826 maData
.mnLabelPos
= EXC_CHTICK_NOLABEL
;
2828 else if( rTypeInfo
.mb3dChart
&& (nAxisType
== EXC_CHAXIS_Y
) )
2830 // Excel expects 'near axis' at Y axes in 3D charts
2831 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2835 cssc::ChartAxisLabelPosition eApiLabelPos
= cssc::ChartAxisLabelPosition_NEAR_AXIS
;
2836 rPropSet
.GetProperty( eApiLabelPos
, EXC_CHPROP_LABELPOSITION
);
2837 switch( eApiLabelPos
)
2839 case cssc::ChartAxisLabelPosition_NEAR_AXIS
:
2840 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
: maData
.mnLabelPos
= EXC_CHTICK_NEXT
; break;
2841 case cssc::ChartAxisLabelPosition_OUTSIDE_START
: maData
.mnLabelPos
= EXC_CHTICK_LOW
; break;
2842 case cssc::ChartAxisLabelPosition_OUTSIDE_END
: maData
.mnLabelPos
= EXC_CHTICK_HIGH
; break;
2843 default: maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2848 void XclExpChTick::SetFontColor(model::ComplexColor
const& rComplexColor
, sal_uInt32 nColorId
)
2850 maData
.maTextComplexColor
= rComplexColor
;
2851 ::set_flag(maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
, rComplexColor
.getFinalColor() == COL_AUTO
);
2852 mnTextColorId
= nColorId
;
2855 void XclExpChTick::SetRotation( sal_uInt16 nRotation
)
2857 maData
.mnRotation
= nRotation
;
2858 ::set_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
, false );
2859 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 2, 3 );
2862 void XclExpChTick::WriteBody( XclExpStream
& rStrm
)
2864 rStrm
<< maData
.mnMajor
2866 << maData
.mnLabelPos
2867 << maData
.mnBackMode
;
2868 rStrm
.WriteZeroBytes( 16 );
2869 rStrm
<< maData
.maTextComplexColor
.getFinalColor()
2871 if( GetBiff() == EXC_BIFF8
)
2872 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
) << maData
.mnRotation
;
2877 /** Returns an API axis object from the passed coordinate system. */
2878 Reference
< XAxis
> lclGetApiAxis( Reference
< XCoordinateSystem
> const & xCoordSystem
,
2879 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2881 Reference
< XAxis
> xAxis
;
2882 if( (nApiAxisDim
>= 0) && xCoordSystem
.is() ) try
2884 xAxis
= xCoordSystem
->getAxisByDimension( nApiAxisDim
, nApiAxesSetIdx
);
2892 Reference
< cssc::XAxis
> lclGetApiChart1Axis( Reference
< XChartDocument
> const & xChartDoc
,
2893 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2895 Reference
< cssc::XAxis
> xChart1Axis
;
2898 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY_THROW
);
2899 Reference
< cssc::XAxisSupplier
> xChart1AxisSupp( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
2900 switch( nApiAxesSetIdx
)
2902 case EXC_CHART_AXESSET_PRIMARY
:
2903 xChart1Axis
= xChart1AxisSupp
->getAxis( nApiAxisDim
);
2905 case EXC_CHART_AXESSET_SECONDARY
:
2906 xChart1Axis
= xChart1AxisSupp
->getSecondaryAxis( nApiAxisDim
);
2918 XclExpChAxis::XclExpChAxis( const XclExpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
2919 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXIS
, EXC_ID_CHAXIS
, 18 ),
2920 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
2922 maData
.mnType
= nAxisType
;
2925 void XclExpChAxis::SetFont(const XclExpChFontRef
& xFont
, model::ComplexColor
const& rComplexColor
, sal_uInt32 nColorId
)
2929 mxTick
->SetFontColor(rComplexColor
, nColorId
);
2932 void XclExpChAxis::SetRotation( sal_uInt16 nRotation
)
2935 mxTick
->SetRotation( nRotation
);
2938 void XclExpChAxis::Convert( Reference
< XAxis
> const & xAxis
, Reference
< XAxis
> const & xCrossingAxis
,
2939 Reference
< cssc::XAxis
> const & xChart1Axis
, const XclChExtTypeInfo
& rTypeInfo
)
2941 ScfPropertySet
aAxisProp( xAxis
);
2942 bool bCategoryAxis
= ((GetAxisType() == EXC_CHAXIS_X
) && rTypeInfo
.mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
);
2944 // axis line format -------------------------------------------------------
2946 mxAxisLine
= new XclExpChLineFormat( GetChRoot() );
2947 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
2948 // #i58688# axis enabled
2949 mxAxisLine
->SetShowAxis( aAxisProp
.GetBoolProperty( EXC_CHPROP_SHOW
) );
2951 // axis scaling and increment ---------------------------------------------
2953 ScfPropertySet
aCrossingProp( xCrossingAxis
);
2956 mxLabelRange
= new XclExpChLabelRange( GetChRoot() );
2957 mxLabelRange
->SetTicksBetweenCateg( rTypeInfo
.mbTicksBetweenCateg
);
2960 ScfPropertySet
aChart1AxisProp( xChart1Axis
);
2961 // #i71684# radar charts have reversed rotation direction
2962 mxLabelRange
->Convert( xAxis
->getScaleData(), aChart1AxisProp
, (GetAxisType() == EXC_CHAXIS_X
) && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) );
2964 // get position of crossing axis on this axis from passed axis object
2965 if( aCrossingProp
.Is() )
2966 mxLabelRange
->ConvertAxisPosition( aCrossingProp
);
2970 mxValueRange
= new XclExpChValueRange( GetChRoot() );
2972 mxValueRange
->Convert( xAxis
->getScaleData() );
2973 // get position of crossing axis on this axis from passed axis object
2974 if( aCrossingProp
.Is() )
2975 mxValueRange
->ConvertAxisPosition( aCrossingProp
);
2978 // axis caption text ------------------------------------------------------
2980 // axis ticks properties
2981 mxTick
= new XclExpChTick( GetChRoot() );
2982 mxTick
->Convert( aAxisProp
, rTypeInfo
, GetAxisType() );
2984 // axis label formatting and rotation
2985 ConvertFontBase( GetChRoot(), aAxisProp
);
2986 ConvertRotationBase( aAxisProp
, true );
2988 // axis number format
2989 sal_Int32 nApiNumFmt
= 0;
2990 if( !bCategoryAxis
&& aAxisProp
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
2992 bool bLinkNumberFmtToSource
= false;
2993 if ( !aAxisProp
.GetProperty( bLinkNumberFmtToSource
, EXC_CHPROP_NUMBERFORMAT_LINKSRC
) || !bLinkNumberFmtToSource
)
2994 mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
2997 // grid -------------------------------------------------------------------
3003 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3004 if( aGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3005 mxMajorGrid
= lclCreateLineFormat( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3007 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3008 if( aSubGridPropSeq
.hasElements() )
3010 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3011 if( aSubGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3012 mxMinorGrid
= lclCreateLineFormat( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3016 void XclExpChAxis::ConvertWall( css::uno::Reference
< css::chart2::XDiagram
> const & xDiagram
)
3018 if( !xDiagram
.is() )
3021 switch( GetAxisType() )
3025 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3026 mxWallFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_WALL3D
);
3031 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3032 mxWallFrame
= lclCreateFrame( GetChRoot(), aFloorProp
, EXC_CHOBJTYPE_FLOOR3D
);
3036 mxWallFrame
.clear();
3040 void XclExpChAxis::WriteSubRecords( XclExpStream
& rStrm
)
3042 lclSaveRecord( rStrm
, mxLabelRange
);
3043 lclSaveRecord( rStrm
, mxValueRange
);
3044 if( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3045 XclExpUInt16Record( EXC_ID_CHFORMAT
, mnNumFmtIdx
).Save( rStrm
);
3046 lclSaveRecord( rStrm
, mxTick
);
3047 lclSaveRecord( rStrm
, mxFont
);
3048 lclSaveRecord( rStrm
, mxAxisLine
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_AXISLINE
);
3049 lclSaveRecord( rStrm
, mxMajorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MAJORGRID
);
3050 lclSaveRecord( rStrm
, mxMinorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MINORGRID
);
3051 lclSaveRecord( rStrm
, mxWallFrame
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_WALLS
);
3054 void XclExpChAxis::WriteBody( XclExpStream
& rStrm
)
3056 rStrm
<< maData
.mnType
;
3057 rStrm
.WriteZeroBytes( 16 );
3060 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3061 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXESSET
, EXC_ID_CHAXESSET
, 18 )
3063 maData
.mnAxesSetId
= nAxesSetId
;
3064 SetFutureRecordContext( 0, nAxesSetId
);
3066 /* Need to set a reasonable size for the plot area, otherwise Excel will
3067 move away embedded shapes while auto-sizing the plot area. This is just
3068 a wild guess, but will be fixed with implementing manual positioning of
3070 maData
.maRect
.mnX
= 262;
3071 maData
.maRect
.mnY
= 626;
3072 maData
.maRect
.mnWidth
= 3187;
3073 maData
.maRect
.mnHeight
= 2633;
3076 sal_uInt16
XclExpChAxesSet::Convert( Reference
< XDiagram
> const & xDiagram
, sal_uInt16 nFirstGroupIdx
)
3078 /* First unused chart type group index is passed to be able to continue
3079 counting of chart type groups for secondary axes set. */
3080 sal_uInt16 nGroupIdx
= nFirstGroupIdx
;
3081 Reference
< XCoordinateSystemContainer
> xCoordSysCont( xDiagram
, UNO_QUERY
);
3082 if( xCoordSysCont
.is() )
3084 Sequence
< Reference
< XCoordinateSystem
> > aCoordSysSeq
= xCoordSysCont
->getCoordinateSystems();
3085 if( aCoordSysSeq
.hasElements() )
3087 /* Process first coordinate system only. Import filter puts all
3088 chart types into one coordinate system. */
3089 const Reference
< XCoordinateSystem
>& xCoordSystem
= aCoordSysSeq
[ 0 ];
3090 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3093 bool b3dChart
= xCoordSystem
.is() && (xCoordSystem
->getDimension() == 3);
3096 namespace ApiAxisType
= cssc2::AxisType
;
3097 Reference
< XAxis
> xApiYAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_Y
, nApiAxesSetIdx
);
3098 bool bPercent
= xApiYAxis
.is() && (xApiYAxis
->getScaleData().AxisType
== ApiAxisType::PERCENT
);
3100 // connector lines in bar charts
3101 ScfPropertySet
aDiaProp( xDiagram
);
3102 bool bConnectBars
= aDiaProp
.GetBoolProperty( EXC_CHPROP_CONNECTBARS
);
3104 // swapped axes sets
3105 ScfPropertySet
aCoordSysProp( xCoordSystem
);
3106 bool bSwappedAxesSet
= aCoordSysProp
.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
);
3108 // X axis for later use
3109 Reference
< XAxis
> xApiXAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_X
, nApiAxesSetIdx
);
3111 ScfPropertySet
aXAxisProp( xApiXAxis
);
3112 bool bHasXLabels
= aXAxisProp
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
);
3114 // process chart types
3115 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3116 if( xChartTypeCont
.is() )
3118 const Sequence
< Reference
< XChartType
> > aChartTypeSeq
= xChartTypeCont
->getChartTypes();
3119 for( const Reference
< XChartType
>& rChartType
: aChartTypeSeq
)
3121 XclExpChTypeGroupRef xTypeGroup
= new XclExpChTypeGroup( GetChRoot(), nGroupIdx
);
3122 xTypeGroup
->ConvertType( xDiagram
, rChartType
, nApiAxesSetIdx
, b3dChart
, bSwappedAxesSet
, bHasXLabels
);
3123 /* If new chart type group cannot be inserted into a combination
3124 chart with existing type groups, insert all series into last
3125 contained chart type group instead of creating a new group. */
3126 XclExpChTypeGroupRef xLastGroup
= GetLastTypeGroup();
3127 if( xLastGroup
&& !(xTypeGroup
->IsCombinable2d() && xLastGroup
->IsCombinable2d()) )
3129 xLastGroup
->ConvertSeries( xDiagram
, rChartType
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3133 xTypeGroup
->ConvertSeries( xDiagram
, rChartType
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3134 if( xTypeGroup
->IsValidGroup() )
3136 maTypeGroups
.AppendRecord( xTypeGroup
);
3143 if( XclExpChTypeGroup
* pGroup
= GetFirstTypeGroup().get() )
3145 const XclChExtTypeInfo
& rTypeInfo
= pGroup
->GetTypeInfo();
3147 // create axes according to chart type (no axes for pie and donut charts)
3148 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
3150 ConvertAxis( mxXAxis
, EXC_CHAXIS_X
, mxXAxisTitle
, EXC_CHOBJLINK_XAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_Y
);
3151 ConvertAxis( mxYAxis
, EXC_CHAXIS_Y
, mxYAxisTitle
, EXC_CHOBJLINK_YAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_X
);
3152 if( pGroup
->Is3dDeepChart() )
3153 ConvertAxis( mxZAxis
, EXC_CHAXIS_Z
, mxZAxisTitle
, EXC_CHOBJLINK_ZAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_NONE
);
3156 // X axis category ranges
3157 if( rTypeInfo
.mbCategoryAxis
&& xApiXAxis
.is() )
3159 const ScaleData aScaleData
= xApiXAxis
->getScaleData();
3160 for( size_t nIdx
= 0, nSize
= maTypeGroups
.GetSize(); nIdx
< nSize
; ++nIdx
)
3161 maTypeGroups
.GetRecord( nIdx
)->ConvertCategSequence( aScaleData
.Categories
);
3165 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3167 Reference
< XLegend
> xLegend
= xDiagram
->getLegend();
3170 ScfPropertySet
aLegendProp( xLegend
);
3171 pGroup
->ConvertLegend( aLegendProp
);
3178 // wall/floor/diagram frame formatting
3179 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3181 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3182 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3184 // wall/floor formatting (3D charts)
3186 mxXAxis
->ConvertWall( xDiagram
);
3188 mxYAxis
->ConvertWall( xDiagram
);
3192 // diagram background formatting
3193 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3194 mxPlotFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_PLOTFRAME
);
3198 // inner and outer plot area position and size
3201 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
3202 Reference
< cssc::XDiagramPositioning
> xPositioning( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
3203 // set manual flag in chart data
3204 if( !xPositioning
->isAutomaticDiagramPositioning() )
3205 GetChartData().SetManualPlotArea();
3206 // the CHAXESSET record contains the inner plot area
3207 maData
.maRect
= CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionExcludingAxes() );
3208 // the embedded CHFRAMEPOS record contains the outer plot area
3209 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
);
3210 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3211 const XclExpChTypeGroup
* pFirstTypeGroup
= GetFirstTypeGroup().get();
3212 bool bPieChart
= pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3213 mxFramePos
->GetFramePosData().maRect
= bPieChart
? maData
.maRect
:
3214 CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionIncludingAxes() );
3220 // return first unused chart type group index for next axes set
3224 bool XclExpChAxesSet::Is3dChart() const
3226 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3227 return xTypeGroup
&& xTypeGroup
->Is3dChart();
3230 void XclExpChAxesSet::WriteSubRecords( XclExpStream
& rStrm
)
3232 lclSaveRecord( rStrm
, mxFramePos
);
3233 lclSaveRecord( rStrm
, mxXAxis
);
3234 lclSaveRecord( rStrm
, mxYAxis
);
3235 lclSaveRecord( rStrm
, mxZAxis
);
3236 lclSaveRecord( rStrm
, mxXAxisTitle
);
3237 lclSaveRecord( rStrm
, mxYAxisTitle
);
3238 lclSaveRecord( rStrm
, mxZAxisTitle
);
3241 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME
).Save( rStrm
);
3242 mxPlotFrame
->Save( rStrm
);
3244 maTypeGroups
.Save( rStrm
);
3247 XclExpChTypeGroupRef
XclExpChAxesSet::GetFirstTypeGroup() const
3249 return maTypeGroups
.GetFirstRecord();
3252 XclExpChTypeGroupRef
XclExpChAxesSet::GetLastTypeGroup() const
3254 return maTypeGroups
.GetLastRecord();
3257 void XclExpChAxesSet::ConvertAxis(
3258 XclExpChAxisRef
& rxChAxis
, sal_uInt16 nAxisType
,
3259 XclExpChTextRef
& rxChAxisTitle
, sal_uInt16 nTitleTarget
,
3260 Reference
< XCoordinateSystem
> const & xCoordSystem
, const XclChExtTypeInfo
& rTypeInfo
,
3261 sal_Int32 nCrossingAxisDim
)
3263 // create and convert axis object
3264 rxChAxis
= new XclExpChAxis( GetChRoot(), nAxisType
);
3265 sal_Int32 nApiAxisDim
= rxChAxis
->GetApiAxisDimension();
3266 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3267 Reference
< XAxis
> xAxis
= lclGetApiAxis( xCoordSystem
, nApiAxisDim
, nApiAxesSetIdx
);
3268 Reference
< XAxis
> xCrossingAxis
= lclGetApiAxis( xCoordSystem
, nCrossingAxisDim
, nApiAxesSetIdx
);
3269 Reference
< cssc::XAxis
> xChart1Axis
= lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim
, nApiAxesSetIdx
);
3270 rxChAxis
->Convert( xAxis
, xCrossingAxis
, xChart1Axis
, rTypeInfo
);
3272 // create and convert axis title
3273 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY
);
3274 rxChAxisTitle
= lclCreateTitle( GetChRoot(), xTitled
, nTitleTarget
);
3277 void XclExpChAxesSet::WriteBody( XclExpStream
& rStrm
)
3279 rStrm
<< maData
.mnAxesSetId
<< maData
.maRect
;
3282 // The chart object ===========================================================
3284 static void lcl_getChartSubTitle(const Reference
<XChartDocument
>& xChartDoc
,
3285 OUString
& rSubTitle
)
3287 Reference
< css::chart::XChartDocument
> xChartDoc1(xChartDoc
, UNO_QUERY
);
3288 if (!xChartDoc1
.is())
3291 Reference
< XPropertySet
> xProp(xChartDoc1
->getSubTitle(), UNO_QUERY
);
3296 Any any
= xProp
->getPropertyValue(u
"String"_ustr
);
3301 XclExpChChart::XclExpChChart( const XclExpRoot
& rRoot
,
3302 Reference
< XChartDocument
> const & xChartDoc
, const tools::Rectangle
& rChartRect
) :
3303 XclExpChGroupBase( XclExpChRoot( rRoot
, *this ), EXC_CHFRBLOCK_TYPE_CHART
, EXC_ID_CHCHART
, 16 )
3305 Size aPtSize
= o3tl::convert( rChartRect
.GetSize(), o3tl::Length::mm100
, o3tl::Length::pt
);
3306 // rectangle is stored in 16.16 fixed-point format
3307 maRect
.mnX
= maRect
.mnY
= 0;
3308 maRect
.mnWidth
= static_cast< sal_Int32
>( aPtSize
.Width() << 16 );
3309 maRect
.mnHeight
= static_cast< sal_Int32
>( aPtSize
.Height() << 16 );
3311 // global chart properties (default values)
3312 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, false );
3313 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_MANPLOTAREA
);
3314 maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
;
3316 // always create both axes set objects
3317 mxPrimAxesSet
= std::make_shared
<XclExpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_PRIMARY
);
3318 mxSecnAxesSet
= std::make_shared
<XclExpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_SECONDARY
);
3320 if( !xChartDoc
.is() )
3323 Reference
< XDiagram
> xDiagram
= xChartDoc
->getFirstDiagram();
3325 // global chart properties (only 'include hidden cells' attribute for now)
3326 ScfPropertySet
aDiagramProp( xDiagram
);
3327 bool bIncludeHidden
= aDiagramProp
.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
);
3328 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, !bIncludeHidden
);
3330 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3331 InitConversion( xChartDoc
, rChartRect
);
3334 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3335 mxFrame
= lclCreateFrame( GetChRoot(), aFrameProp
, EXC_CHOBJTYPE_BACKGROUND
);
3338 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY
);
3340 lcl_getChartSubTitle(xChartDoc
, aSubTitle
);
3341 mxTitle
= lclCreateTitle( GetChRoot(), xTitled
, EXC_CHOBJLINK_TITLE
,
3342 !aSubTitle
.isEmpty() ? &aSubTitle
: nullptr );
3344 // diagrams (axes sets)
3345 sal_uInt16 nFreeGroupIdx
= mxPrimAxesSet
->Convert( xDiagram
, 0 );
3346 if( !mxPrimAxesSet
->Is3dChart() )
3347 mxSecnAxesSet
->Convert( xDiagram
, nFreeGroupIdx
);
3349 // treatment of missing values
3350 ScfPropertySet
aDiaProp( xDiagram
);
3351 sal_Int32 nMissingValues
= 0;
3352 if( aDiaProp
.GetProperty( nMissingValues
, EXC_CHPROP_MISSINGVALUETREATMENT
) )
3354 using namespace cssc::MissingValueTreatment
;
3355 switch( nMissingValues
)
3357 case LEAVE_GAP
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
; break;
3358 case USE_ZERO
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_ZERO
; break;
3359 case CONTINUE
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_INTERPOLATE
; break;
3363 // finish API conversion
3367 XclExpChSeriesRef
XclExpChChart::CreateSeries()
3369 XclExpChSeriesRef xSeries
;
3370 sal_uInt16 nSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.GetSize() );
3371 if( nSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3373 xSeries
= new XclExpChSeries( GetChRoot(), nSeriesIdx
);
3374 maSeries
.AppendRecord( xSeries
);
3379 void XclExpChChart::RemoveLastSeries()
3381 if( !maSeries
.IsEmpty() )
3382 maSeries
.RemoveRecord( maSeries
.GetSize() - 1 );
3385 void XclExpChChart::SetDataLabel( XclExpChTextRef
const & xText
)
3388 maLabels
.AppendRecord( xText
);
3391 void XclExpChChart::SetManualPlotArea()
3393 // this flag does not exist in BIFF5
3394 if( GetBiff() == EXC_BIFF8
)
3395 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3398 void XclExpChChart::WriteSubRecords( XclExpStream
& rStrm
)
3400 // background format
3401 lclSaveRecord( rStrm
, mxFrame
);
3404 maSeries
.Save( rStrm
);
3406 // CHPROPERTIES record
3407 rStrm
.StartRecord( EXC_ID_CHPROPERTIES
, 4 );
3408 rStrm
<< maProps
.mnFlags
<< maProps
.mnEmptyMode
<< sal_uInt8( 0 );
3411 // axes sets (always save primary axes set)
3412 sal_uInt16 nUsedAxesSets
= mxSecnAxesSet
->IsValidAxesSet() ? 2 : 1;
3413 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS
, nUsedAxesSets
).Save( rStrm
);
3414 mxPrimAxesSet
->Save( rStrm
);
3415 if( mxSecnAxesSet
->IsValidAxesSet() )
3416 mxSecnAxesSet
->Save( rStrm
);
3418 // chart title and data labels
3419 lclSaveRecord( rStrm
, mxTitle
);
3420 maLabels
.Save( rStrm
);
3423 void XclExpChChart::WriteBody( XclExpStream
& rStrm
)
3428 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot
& rRoot
,
3429 const Reference
< XModel
>& rxModel
, const Size
& rChartSize
) :
3432 if( rChartSize
.IsEmpty() )
3435 ScfPropertySet
aPropSet( rxModel
);
3436 Reference
< XShapes
> xShapes
;
3437 if( !(aPropSet
.GetProperty( xShapes
, EXC_CHPROP_ADDITIONALSHAPES
) && xShapes
.is() && (xShapes
->getCount() > 0)) )
3440 /* Create a new independent object manager with own DFF stream for the
3441 DGCONTAINER, pass global manager as parent for shared usage of
3442 global DFF data (picture container etc.). */
3443 mxObjMgr
= std::make_shared
<XclExpEmbeddedObjectManager
>( GetObjectManager(), rChartSize
, EXC_CHART_TOTALUNITS
, EXC_CHART_TOTALUNITS
);
3444 // initialize the drawing object list
3445 mxObjMgr
->StartSheet();
3446 // process the draw page (convert all shapes)
3447 mxObjRecs
= mxObjMgr
->ProcessDrawing( xShapes
);
3448 // finalize the DFF stream
3449 mxObjMgr
->EndDocument();
3452 XclExpChartDrawing::~XclExpChartDrawing()
3456 void XclExpChartDrawing::Save( XclExpStream
& rStrm
)
3459 mxObjRecs
->Save( rStrm
);
3462 XclExpChart::XclExpChart( const XclExpRoot
& rRoot
, Reference
< XModel
> const & xModel
, const tools::Rectangle
& rChartRect
) :
3463 XclExpSubStream( EXC_BOF_CHART
),
3466 AppendNewRecord( new XclExpChartPageSettings( rRoot
) );
3467 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT
, false ) );
3468 AppendNewRecord( new XclExpChartDrawing( rRoot
, xModel
, rChartRect
.GetSize() ) );
3469 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS
, EXC_CHUNITS_TWIPS
) );
3471 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
3472 AppendNewRecord( new XclExpChChart( rRoot
, xChartDoc
, rChartRect
) );
3475 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */