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 <vcl/outdev.hxx>
58 #include <filter/msfilter/escherex.hxx>
60 #include <document.hxx>
61 #include <compiler.hxx>
62 #include <tokenarray.hxx>
63 #include <xeescher.hxx>
64 #include <xeformula.hxx>
65 #include <xehelper.hxx>
67 #include <xestyle.hxx>
68 #include <xltools.hxx>
72 using ::com::sun::star::uno::Any
;
73 using ::com::sun::star::uno::Reference
;
74 using ::com::sun::star::uno::Sequence
;
75 using ::com::sun::star::uno::UNO_QUERY
;
76 using ::com::sun::star::uno::UNO_QUERY_THROW
;
77 using ::com::sun::star::uno::UNO_SET_THROW
;
78 using ::com::sun::star::uno::Exception
;
79 using ::com::sun::star::beans::XPropertySet
;
80 using ::com::sun::star::i18n::XBreakIterator
;
81 using ::com::sun::star::frame::XModel
;
82 using ::com::sun::star::drawing::XShape
;
83 using ::com::sun::star::drawing::XShapes
;
85 using ::com::sun::star::chart2::IncrementData
;
86 using ::com::sun::star::chart2::RelativePosition
;
87 using ::com::sun::star::chart2::RelativeSize
;
88 using ::com::sun::star::chart2::ScaleData
;
89 using ::com::sun::star::chart2::SubIncrement
;
90 using ::com::sun::star::chart2::XAxis
;
91 using ::com::sun::star::chart2::XChartDocument
;
92 using ::com::sun::star::chart2::XChartTypeContainer
;
93 using ::com::sun::star::chart2::XColorScheme
;
94 using ::com::sun::star::chart2::XCoordinateSystem
;
95 using ::com::sun::star::chart2::XCoordinateSystemContainer
;
96 using ::com::sun::star::chart2::XChartType
;
97 using ::com::sun::star::chart2::XDataSeries
;
98 using ::com::sun::star::chart2::XDataSeriesContainer
;
99 using ::com::sun::star::chart2::XDiagram
;
100 using ::com::sun::star::chart2::XFormattedString
;
101 using ::com::sun::star::chart2::XLegend
;
102 using ::com::sun::star::chart2::XRegressionCurve
;
103 using ::com::sun::star::chart2::XRegressionCurveContainer
;
104 using ::com::sun::star::chart2::XTitle
;
105 using ::com::sun::star::chart2::XTitled
;
107 using ::com::sun::star::chart2::data::XDataSequence
;
108 using ::com::sun::star::chart2::data::XDataSource
;
109 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
111 using ::formula::FormulaToken
;
112 using ::formula::FormulaTokenArrayPlainIterator
;
114 namespace cssc
= ::com::sun::star::chart
;
115 namespace cssc2
= ::com::sun::star::chart2
;
117 // Helpers ====================================================================
121 XclExpStream
& operator<<( XclExpStream
& rStrm
, const XclChRectangle
& rRect
)
123 return rStrm
<< rRect
.mnX
<< rRect
.mnY
<< rRect
.mnWidth
<< rRect
.mnHeight
;
126 void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef
const & xRec
)
132 /** Saves the passed record (group) together with a leading value record. */
133 template< typename Type
>
134 void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef
const & xRec
, sal_uInt16 nRecId
, Type nValue
)
138 XclExpValueRecord
< Type
>( nRecId
, nValue
).Save( rStrm
);
143 template<typename ValueType
, typename KeyType
>
144 void lclSaveRecord(XclExpStream
& rStrm
, ValueType
* pRec
, sal_uInt16 nRecId
, KeyType nValue
)
148 XclExpValueRecord
<KeyType
>(nRecId
, nValue
).Save(rStrm
);
153 void lclWriteChFrBlockRecord( XclExpStream
& rStrm
, const XclChFrBlock
& rFrBlock
, bool bBegin
)
155 sal_uInt16 nRecId
= bBegin
? EXC_ID_CHFRBLOCKBEGIN
: EXC_ID_CHFRBLOCKEND
;
156 rStrm
.StartRecord( nRecId
, 12 );
157 rStrm
<< nRecId
<< EXC_FUTUREREC_EMPTYFLAGS
<< rFrBlock
.mnType
<< rFrBlock
.mnContext
<< rFrBlock
.mnValue1
<< rFrBlock
.mnValue2
;
161 template< typename Type
>
162 bool lclIsAutoAnyOrGetValue( Type
& rValue
, const Any
& rAny
)
164 return !rAny
.hasValue() || !(rAny
>>= rValue
);
167 bool lclIsAutoAnyOrGetScaledValue( double& rfValue
, const Any
& rAny
, bool bLogScale
)
169 bool bIsAuto
= lclIsAutoAnyOrGetValue( rfValue
, rAny
);
170 if( !bIsAuto
&& bLogScale
)
171 rfValue
= log( rfValue
) / log( 10.0 );
175 sal_uInt16
lclGetTimeValue( const XclExpRoot
& rRoot
, double fSerialDate
, sal_uInt16 nTimeUnit
)
177 DateTime aDateTime
= rRoot
.GetDateTimeFromDouble( fSerialDate
);
180 case EXC_CHDATERANGE_DAYS
:
181 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
182 case EXC_CHDATERANGE_MONTHS
:
183 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( 12 * (aDateTime
.GetYear() - rRoot
.GetBaseYear()) + aDateTime
.GetMonth() - 1, 0, SAL_MAX_INT16
);
184 case EXC_CHDATERANGE_YEARS
:
185 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( aDateTime
.GetYear() - rRoot
.GetBaseYear(), 0, SAL_MAX_INT16
);
187 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
189 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
192 bool lclConvertTimeValue( const XclExpRoot
& rRoot
, sal_uInt16
& rnValue
, const Any
& rAny
, sal_uInt16 nTimeUnit
)
194 double fSerialDate
= 0;
195 bool bAuto
= lclIsAutoAnyOrGetValue( fSerialDate
, rAny
);
197 rnValue
= lclGetTimeValue( rRoot
, fSerialDate
, nTimeUnit
);
201 sal_uInt16
lclGetTimeUnit( sal_Int32 nApiTimeUnit
)
203 switch( nApiTimeUnit
)
205 case cssc::TimeUnit::DAY
: return EXC_CHDATERANGE_DAYS
;
206 case cssc::TimeUnit::MONTH
: return EXC_CHDATERANGE_MONTHS
;
207 case cssc::TimeUnit::YEAR
: return EXC_CHDATERANGE_YEARS
;
208 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
210 return EXC_CHDATERANGE_DAYS
;
213 bool lclConvertTimeInterval( sal_uInt16
& rnValue
, sal_uInt16
& rnTimeUnit
, const Any
& rAny
)
215 cssc::TimeInterval aInterval
;
216 bool bAuto
= lclIsAutoAnyOrGetValue( aInterval
, rAny
);
219 rnValue
= ::limit_cast
< sal_uInt16
, sal_Int32
>( aInterval
.Number
, 1, SAL_MAX_UINT16
);
220 rnTimeUnit
= lclGetTimeUnit( aInterval
.TimeUnit
);
227 // Common =====================================================================
229 /** Stores global data needed in various classes of the Chart export filter. */
230 struct XclExpChRootData
: public XclChRootData
232 typedef ::std::vector
< XclChFrBlock
> XclChFrBlockVector
;
234 XclExpChChart
& mrChartData
; /// The chart data object.
235 XclChFrBlockVector maWrittenFrBlocks
; /// Stack of future record levels already written out.
236 XclChFrBlockVector maUnwrittenFrBlocks
; /// Stack of future record levels not yet written out.
238 explicit XclExpChRootData( XclExpChChart
& rChartData
) : mrChartData( rChartData
) {}
240 /** Registers a new future record level. */
241 void RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
);
242 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
243 void InitializeFutureRecBlock( XclExpStream
& rStrm
);
244 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
245 void FinalizeFutureRecBlock( XclExpStream
& rStrm
);
248 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
250 maUnwrittenFrBlocks
.push_back( rFrBlock
);
253 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream
& rStrm
)
255 // first call from a future record writes all missing CHFRBLOCKBEGIN records
256 if( maUnwrittenFrBlocks
.empty() )
259 // write the leading CHFRINFO record
260 if( maWrittenFrBlocks
.empty() )
262 rStrm
.StartRecord( EXC_ID_CHFRINFO
, 20 );
263 rStrm
<< EXC_ID_CHFRINFO
<< EXC_FUTUREREC_EMPTYFLAGS
<< EXC_CHFRINFO_EXCELXP2003
<< EXC_CHFRINFO_EXCELXP2003
<< sal_uInt16( 3 );
264 rStrm
<< sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
267 // write all unwritten CHFRBLOCKBEGIN records
268 for( const auto& rUnwrittenFrBlock
: maUnwrittenFrBlocks
)
270 OSL_ENSURE( rUnwrittenFrBlock
.mnType
!= EXC_CHFRBLOCK_TYPE_UNKNOWN
, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
271 lclWriteChFrBlockRecord( rStrm
, rUnwrittenFrBlock
, true );
273 // move all record infos to vector of written blocks
274 maWrittenFrBlocks
.insert( maWrittenFrBlocks
.end(), maUnwrittenFrBlocks
.begin(), maUnwrittenFrBlocks
.end() );
275 maUnwrittenFrBlocks
.clear();
278 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
280 OSL_ENSURE( !maUnwrittenFrBlocks
.empty() || !maWrittenFrBlocks
.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
281 if( !maUnwrittenFrBlocks
.empty() )
283 // no future record has been written, just forget the topmost level
284 maUnwrittenFrBlocks
.pop_back();
286 else if( !maWrittenFrBlocks
.empty() )
288 // write the CHFRBLOCKEND record for the topmost block and delete it
289 lclWriteChFrBlockRecord( rStrm
, maWrittenFrBlocks
.back(), false );
290 maWrittenFrBlocks
.pop_back();
294 XclExpChRoot::XclExpChRoot( const XclExpRoot
& rRoot
, XclExpChChart
& rChartData
) :
296 mxChData( std::make_shared
<XclExpChRootData
>( rChartData
) )
300 XclExpChRoot::~XclExpChRoot()
304 Reference
< XChartDocument
> const & XclExpChRoot::GetChartDocument() const
306 return mxChData
->mxChartDoc
;
309 XclExpChChart
& XclExpChRoot::GetChartData() const
311 return mxChData
->mrChartData
;
314 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType
) const
316 return mxChData
->mxTypeInfoProv
->GetTypeInfo( eType
);
319 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( const OUString
& rServiceName
) const
321 return mxChData
->mxTypeInfoProv
->GetTypeInfoFromService( rServiceName
);
324 const XclChFormatInfo
& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType
) const
326 return mxChData
->mxFmtInfoProv
->GetFormatInfo( eObjType
);
329 void XclExpChRoot::InitConversion( css::uno::Reference
< css::chart2::XChartDocument
> const & xChartDoc
, const tools::Rectangle
& rChartRect
) const
331 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
334 void XclExpChRoot::FinishConversion() const
336 mxChData
->FinishConversion();
339 bool XclExpChRoot::IsSystemColor( const Color
& rColor
, sal_uInt16 nSysColorIdx
) const
341 XclExpPalette
& rPal
= GetPalette();
342 return rPal
.IsSystemColor( nSysColorIdx
) && (rColor
== rPal
.GetDefColor( nSysColorIdx
));
345 void XclExpChRoot::SetSystemColor( Color
& rColor
, sal_uInt32
& rnColorId
, sal_uInt16 nSysColorIdx
) const
347 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx
), "XclExpChRoot::SetSystemColor - invalid color index" );
348 rColor
= GetPalette().GetDefColor( nSysColorIdx
);
349 rnColorId
= XclExpPalette::GetColorIdFromIndex( nSysColorIdx
);
352 sal_Int32
XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX
) const
354 return ::limit_cast
< sal_Int32
, double >( (nPosX
- mxChData
->mnBorderGapX
) / mxChData
->mfUnitSizeX
, 0, EXC_CHART_TOTALUNITS
);
357 sal_Int32
XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY
) const
359 return ::limit_cast
< sal_Int32
, double >( (nPosY
- mxChData
->mnBorderGapY
) / mxChData
->mfUnitSizeY
, 0, EXC_CHART_TOTALUNITS
);
362 XclChRectangle
XclExpChRoot::CalcChartRectFromHmm( const css::awt::Rectangle
& rRect
) const
364 XclChRectangle aRect
;
365 aRect
.mnX
= CalcChartXFromHmm( rRect
.X
);
366 aRect
.mnY
= CalcChartYFromHmm( rRect
.Y
);
367 aRect
.mnWidth
= CalcChartXFromHmm( rRect
.Width
);
368 aRect
.mnHeight
= CalcChartYFromHmm( rRect
.Height
);
372 void XclExpChRoot::ConvertLineFormat( XclChLineFormat
& rLineFmt
,
373 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
375 GetChartPropSetHelper().ReadLineProperties(
376 rLineFmt
, *mxChData
->mxLineDashTable
, rPropSet
, ePropMode
);
379 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat
& rAreaFmt
,
380 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
382 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt
, rPropSet
, ePropMode
);
385 void XclExpChRoot::ConvertEscherFormat(
386 XclChEscherFormat
& rEscherFmt
, XclChPicFormat
& rPicFmt
,
387 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
389 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt
, rPicFmt
,
390 *mxChData
->mxGradientTable
, *mxChData
->mxHatchTable
, *mxChData
->mxBitmapTable
, rPropSet
, ePropMode
);
393 sal_uInt16
XclExpChRoot::ConvertFont( const ScfPropertySet
& rPropSet
, sal_Int16 nScript
) const
395 XclFontData aFontData
;
396 GetFontPropSetHelper().ReadFontProperties( aFontData
, rPropSet
, EXC_FONTPROPSET_CHART
, nScript
);
397 return GetFontBuffer().Insert( aFontData
, EXC_COLOR_CHARTTEXT
);
400 sal_uInt16
XclExpChRoot::ConvertPieRotation( const ScfPropertySet
& rPropSet
)
402 sal_Int32 nApiRot
= 0;
403 rPropSet
.GetProperty( nApiRot
, EXC_CHPROP_STARTINGANGLE
);
404 return static_cast< sal_uInt16
>( (450 - (nApiRot
% 360)) % 360 );
407 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
409 mxChData
->RegisterFutureRecBlock( rFrBlock
);
412 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream
& rStrm
)
414 mxChData
->InitializeFutureRecBlock( rStrm
);
417 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
419 mxChData
->FinalizeFutureRecBlock( rStrm
);
422 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot
& rRoot
,
423 sal_uInt16 nFrType
, sal_uInt16 nRecId
, std::size_t nRecSize
) :
424 XclExpRecord( nRecId
, nRecSize
),
425 XclExpChRoot( rRoot
),
430 XclExpChGroupBase::~XclExpChGroupBase()
434 void XclExpChGroupBase::Save( XclExpStream
& rStrm
)
437 XclExpRecord::Save( rStrm
);
439 if( !HasSubRecords() )
442 // register the future record context corresponding to this record group
443 RegisterFutureRecBlock( maFrBlock
);
445 XclExpEmptyRecord( EXC_ID_CHBEGIN
).Save( rStrm
);
447 WriteSubRecords( rStrm
);
448 // finalize the future records, must be done before the closing CHEND
449 FinalizeFutureRecBlock( rStrm
);
451 XclExpEmptyRecord( EXC_ID_CHEND
).Save( rStrm
);
454 bool XclExpChGroupBase::HasSubRecords() const
459 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext
, sal_uInt16 nFrValue1
, sal_uInt16 nFrValue2
)
461 maFrBlock
.mnContext
= nFrContext
;
462 maFrBlock
.mnValue1
= nFrValue1
;
463 maFrBlock
.mnValue2
= nFrValue2
;
466 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot
& rRoot
,
467 XclFutureRecType eRecType
, sal_uInt16 nRecId
, std::size_t nRecSize
) :
468 XclExpFutureRecord( eRecType
, nRecId
, nRecSize
),
469 XclExpChRoot( rRoot
)
473 void XclExpChFutureRecordBase::Save( XclExpStream
& rStrm
)
475 InitializeFutureRecBlock( rStrm
);
476 XclExpFutureRecord::Save( rStrm
);
479 // Frame formatting ===========================================================
481 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode
) :
482 XclExpRecord( EXC_ID_CHFRAMEPOS
, 20 )
484 maData
.mnTLMode
= nTLMode
;
485 maData
.mnBRMode
= EXC_CHFRAMEPOS_PARENT
;
488 void XclExpChFramePos::WriteBody( XclExpStream
& rStrm
)
490 rStrm
<< maData
.mnTLMode
<< maData
.mnBRMode
<< maData
.maRect
;
493 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot
& rRoot
) :
494 XclExpRecord( EXC_ID_CHLINEFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 10 ),
495 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
499 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType
)
501 switch( eDefFrameType
)
503 case EXC_CHFRAMETYPE_AUTO
:
506 case EXC_CHFRAMETYPE_INVISIBLE
:
508 maData
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
511 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" );
515 void XclExpChLineFormat::Convert( const XclExpChRoot
& rRoot
,
516 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
518 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
519 rRoot
.ConvertLineFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
522 // detect system color, set color identifier (TODO: detect automatic series line)
523 if( (eObjType
!= EXC_CHOBJTYPE_LINEARSERIES
) && rRoot
.IsSystemColor( maData
.maColor
, rFmtInfo
.mnAutoLineColorIdx
) )
525 // store color index from automatic format data
526 mnColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoLineColorIdx
);
527 // try to set automatic mode
528 bool bAuto
= (maData
.mnPattern
== EXC_CHLINEFORMAT_SOLID
) && (maData
.mnWeight
== rFmtInfo
.mnAutoLineWeight
);
529 ::set_flag( maData
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, bAuto
);
533 // user defined color - register in palette
534 mnColorId
= rRoot
.GetPalette().InsertColor( maData
.maColor
, EXC_COLOR_CHARTLINE
);
539 // no line - set default system color
540 rRoot
.SetSystemColor( maData
.maColor
, mnColorId
, EXC_COLOR_CHWINDOWTEXT
);
544 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType
) const
547 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasLine()) ||
548 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
551 void XclExpChLineFormat::WriteBody( XclExpStream
& rStrm
)
553 rStrm
<< maData
.maColor
<< maData
.mnPattern
<< maData
.mnWeight
<< maData
.mnFlags
;
554 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
555 rStrm
<< rStrm
.GetRoot().GetPalette().GetColorIndex( mnColorId
);
560 /** Creates a CHLINEFORMAT record from the passed property set. */
561 XclExpChLineFormatRef
lclCreateLineFormat( const XclExpChRoot
& rRoot
,
562 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
564 XclExpChLineFormatRef xLineFmt
= new XclExpChLineFormat( rRoot
);
565 xLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
566 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
567 if( rFmtInfo
.mbDeleteDefFrame
&& xLineFmt
->IsDefault( rFmtInfo
.meDefFrameType
) )
574 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot
& rRoot
) :
575 XclExpRecord( EXC_ID_CHAREAFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 16 : 12 ),
576 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
577 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
581 bool XclExpChAreaFormat::Convert( const XclExpChRoot
& rRoot
,
582 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
584 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
585 bool bComplexFill
= rRoot
.ConvertAreaFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
588 bool bSolid
= maData
.mnPattern
== EXC_PATT_SOLID
;
589 // detect system color, set color identifier (TODO: detect automatic series area)
590 if( (eObjType
!= EXC_CHOBJTYPE_FILLEDSERIES
) && rRoot
.IsSystemColor( maData
.maPattColor
, rFmtInfo
.mnAutoPattColorIdx
) )
592 // store color index from automatic format data
593 mnPattColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoPattColorIdx
);
594 // set automatic mode
595 ::set_flag( maData
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, bSolid
);
599 // user defined color - register color in palette
600 mnPattColorId
= rRoot
.GetPalette().InsertColor( maData
.maPattColor
, EXC_COLOR_CHARTAREA
);
602 // background color (default system color for solid fills)
604 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
606 mnBackColorId
= rRoot
.GetPalette().InsertColor( maData
.maBackColor
, EXC_COLOR_CHARTAREA
);
610 // no area - set default system colors
611 rRoot
.SetSystemColor( maData
.maPattColor
, mnPattColorId
, EXC_COLOR_CHWINDOWBACK
);
612 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
617 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType
)
619 switch( eDefFrameType
)
621 case EXC_CHFRAMETYPE_AUTO
:
624 case EXC_CHFRAMETYPE_INVISIBLE
:
626 maData
.mnPattern
= EXC_PATT_NONE
;
629 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" );
633 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType
) const
636 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasArea()) ||
637 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
640 void XclExpChAreaFormat::WriteBody( XclExpStream
& rStrm
)
642 rStrm
<< maData
.maPattColor
<< maData
.maBackColor
<< maData
.mnPattern
<< maData
.mnFlags
;
643 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
645 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
646 rStrm
<< rPal
.GetColorIndex( mnPattColorId
) << rPal
.GetColorIndex( mnBackColorId
);
650 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot
& rRoot
) :
651 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_UNKNOWN
, EXC_ID_CHESCHERFORMAT
),
652 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
653 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
655 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8
);
658 void XclExpChEscherFormat::Convert( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
660 const XclChFormatInfo
& rFmtInfo
= GetFormatInfo( eObjType
);
661 ConvertEscherFormat( maData
, maPicFmt
, rPropSet
, rFmtInfo
.mePropMode
);
662 // register colors in palette
663 mnColor1Id
= RegisterColor( ESCHER_Prop_fillColor
);
664 mnColor2Id
= RegisterColor( ESCHER_Prop_fillBackColor
);
667 bool XclExpChEscherFormat::IsValid() const
669 return static_cast< bool >(maData
.mxEscherSet
);
672 void XclExpChEscherFormat::Save( XclExpStream
& rStrm
)
674 if( maData
.mxEscherSet
)
676 // replace RGB colors with palette indexes in the Escher container
677 const XclExpPalette
& rPal
= GetPalette();
678 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillColor
, 0x08000000 | rPal
.GetColorIndex( mnColor1Id
) );
679 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillBackColor
, 0x08000000 | rPal
.GetColorIndex( mnColor2Id
) );
681 // save the record group
682 XclExpChGroupBase::Save( rStrm
);
686 bool XclExpChEscherFormat::HasSubRecords() const
688 // no subrecords for gradients
689 return maPicFmt
.mnBmpMode
!= EXC_CHPICFORMAT_NONE
;
692 void XclExpChEscherFormat::WriteSubRecords( XclExpStream
& rStrm
)
694 rStrm
.StartRecord( EXC_ID_CHPICFORMAT
, 14 );
695 rStrm
<< maPicFmt
.mnBmpMode
<< sal_uInt16( 0 ) << maPicFmt
.mnFlags
<< maPicFmt
.mfScale
;
699 sal_uInt32
XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId
)
701 sal_uInt32 nBGRValue
;
702 if( maData
.mxEscherSet
&& maData
.mxEscherSet
->GetOpt( nPropId
, nBGRValue
) )
705 Color
aColor( nBGRValue
& 0xff, (nBGRValue
>> 8) & 0xff, (nBGRValue
>> 16) & 0xff );
706 return GetPalette().InsertColor( aColor
, EXC_COLOR_CHARTAREA
);
708 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
);
711 void XclExpChEscherFormat::WriteBody( XclExpStream
& rStrm
)
713 OSL_ENSURE( maData
.mxEscherSet
, "XclExpChEscherFormat::WriteBody - missing property container" );
714 // write Escher property container via temporary memory stream
715 SvMemoryStream aMemStrm
;
716 maData
.mxEscherSet
->Commit( aMemStrm
);
718 aMemStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
719 rStrm
.CopyFromStream( aMemStrm
);
722 XclExpChFrameBase::XclExpChFrameBase()
726 XclExpChFrameBase::~XclExpChFrameBase()
730 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot
& rRoot
,
731 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
734 mxLineFmt
= new XclExpChLineFormat( rRoot
);
735 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
736 // area format (only for frame objects)
737 if( !rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
740 mxAreaFmt
= new XclExpChAreaFormat( rRoot
);
741 bool bComplexFill
= mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
);
742 if( (rRoot
.GetBiff() == EXC_BIFF8
) && bComplexFill
)
744 mxEscherFmt
= new XclExpChEscherFormat( rRoot
);
745 mxEscherFmt
->Convert( rPropSet
, eObjType
);
746 if( mxEscherFmt
->IsValid() )
747 mxAreaFmt
->SetAuto( false );
753 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot
& rRoot
,
754 XclChFrameType eDefFrameType
, bool bIsFrame
)
757 mxLineFmt
= new XclExpChLineFormat( rRoot
);
758 mxLineFmt
->SetDefault( eDefFrameType
);
759 // area format (only for frame objects)
762 mxAreaFmt
= new XclExpChAreaFormat( rRoot
);
763 mxAreaFmt
->SetDefault( eDefFrameType
);
768 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType
) const
771 (!mxLineFmt
|| mxLineFmt
->IsDefault( eDefFrameType
)) &&
772 (!mxAreaFmt
|| mxAreaFmt
->IsDefault( eDefFrameType
));
775 void XclExpChFrameBase::WriteFrameRecords( XclExpStream
& rStrm
)
777 lclSaveRecord( rStrm
, mxLineFmt
);
778 lclSaveRecord( rStrm
, mxAreaFmt
);
779 lclSaveRecord( rStrm
, mxEscherFmt
);
782 XclExpChFrame::XclExpChFrame( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
783 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_FRAME
, EXC_ID_CHFRAME
, 4 ),
784 meObjType( eObjType
)
788 void XclExpChFrame::Convert( const ScfPropertySet
& rPropSet
)
790 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
793 void XclExpChFrame::SetAutoFlags( bool bAutoPos
, bool bAutoSize
)
795 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOPOS
, bAutoPos
);
796 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOSIZE
, bAutoSize
);
799 bool XclExpChFrame::IsDefault() const
801 return IsDefaultFrameBase( GetFormatInfo( meObjType
).meDefFrameType
);
804 bool XclExpChFrame::IsDeleteable() const
806 return IsDefault() && GetFormatInfo( meObjType
).mbDeleteDefFrame
;
809 void XclExpChFrame::Save( XclExpStream
& rStrm
)
813 // wall/floor frame without CHFRAME header record
814 case EXC_CHOBJTYPE_WALL3D
:
815 case EXC_CHOBJTYPE_FLOOR3D
:
816 WriteFrameRecords( rStrm
);
819 XclExpChGroupBase::Save( rStrm
);
823 void XclExpChFrame::WriteSubRecords( XclExpStream
& rStrm
)
825 WriteFrameRecords( rStrm
);
828 void XclExpChFrame::WriteBody( XclExpStream
& rStrm
)
830 rStrm
<< maData
.mnFormat
<< maData
.mnFlags
;
835 /** Creates a CHFRAME record from the passed property set. */
836 XclExpChFrameRef
lclCreateFrame( const XclExpChRoot
& rRoot
,
837 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
839 XclExpChFrameRef xFrame
= new XclExpChFrame( rRoot
, eObjType
);
840 xFrame
->Convert( rPropSet
);
841 if( xFrame
->IsDeleteable() )
848 // Source links ===============================================================
852 void lclAddDoubleRefData(
853 ScTokenArray
& orArray
, const FormulaToken
& rToken
,
854 SCTAB nScTab1
, SCCOL nScCol1
, SCROW nScRow1
,
855 SCTAB nScTab2
, SCCOL nScCol2
, SCROW nScRow2
)
857 ScComplexRefData aComplexRef
;
858 aComplexRef
.InitRange(ScRange(nScCol1
,nScRow1
,nScTab1
,nScCol2
,nScRow2
,nScTab2
));
859 aComplexRef
.Ref1
.SetFlag3D( true );
861 if( orArray
.GetLen() > 0 )
862 orArray
.AddOpCode( ocUnion
);
864 OSL_ENSURE( (rToken
.GetType() == ::formula::svDoubleRef
) || (rToken
.GetType() == ::formula::svExternalDoubleRef
),
865 "lclAddDoubleRefData - double reference token expected");
866 if( rToken
.GetType() == ::formula::svExternalDoubleRef
)
867 orArray
.AddExternalDoubleReference(
868 rToken
.GetIndex(), rToken
.GetString(), aComplexRef
);
870 orArray
.AddDoubleReference( aComplexRef
);
875 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot
& rRoot
, sal_uInt8 nDestType
) :
876 XclExpRecord( EXC_ID_CHSOURCELINK
),
877 XclExpChRoot( rRoot
)
879 maData
.mnDestType
= nDestType
;
880 maData
.mnLinkType
= EXC_CHSRCLINK_DIRECTLY
;
883 sal_uInt16
XclExpChSourceLink::ConvertDataSequence( Reference
< XDataSequence
> const & xDataSeq
, bool bSplitToColumns
, sal_uInt16 nDefCount
)
886 maData
.mnLinkType
= EXC_CHSRCLINK_DEFAULT
;
891 // Compile the range representation string into token array. Note that the
892 // source range text depends on the current grammar.
893 OUString aRangeRepr
= xDataSeq
->getSourceRangeRepresentation();
894 ScCompiler
aComp( GetDoc(), ScAddress(), GetDoc().GetGrammar() );
895 std::unique_ptr
<ScTokenArray
> pArray(aComp
.CompileString(aRangeRepr
));
899 ScTokenArray
aArray(GetRoot().GetDoc());
900 sal_uInt32 nValueCount
= 0;
901 FormulaTokenArrayPlainIterator
aIter(*pArray
);
902 for( const FormulaToken
* pToken
= aIter
.First(); pToken
; pToken
= aIter
.Next() )
904 switch( pToken
->GetType() )
906 case ::formula::svSingleRef
:
907 case ::formula::svExternalSingleRef
:
908 // for a single ref token, just add it to the new token array as is
909 if( aArray
.GetLen() > 0 )
910 aArray
.AddOpCode( ocUnion
);
911 aArray
.AddToken( *pToken
);
915 case ::formula::svDoubleRef
:
916 case ::formula::svExternalDoubleRef
:
918 // split 3-dimensional ranges into single sheets
919 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
920 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(GetRoot().GetDoc(), ScAddress());
921 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(GetRoot().GetDoc(), ScAddress());
922 for (SCTAB nScTab
= aAbs1
.Tab(); nScTab
<= aAbs2
.Tab(); ++nScTab
)
924 // split 2-dimensional ranges into single columns
925 if (bSplitToColumns
&& (aAbs1
.Col() < aAbs2
.Col()) && (aAbs1
.Row() < aAbs2
.Row()))
926 for (SCCOL nScCol
= aAbs1
.Col(); nScCol
<= aAbs2
.Col(); ++nScCol
)
927 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, nScCol
, aAbs1
.Row(), nScTab
, nScCol
, aAbs2
.Row());
929 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, aAbs1
.Col(), aAbs1
.Row(), nScTab
, aAbs2
.Col(), aAbs2
.Row());
931 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
932 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
933 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
934 nValueCount
+= nCols
* nRows
* nTabs
;
942 const ScAddress aBaseCell
;
943 mxLinkFmla
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aArray
, &aBaseCell
);
944 maData
.mnLinkType
= EXC_CHSRCLINK_WORKSHEET
;
945 return ulimit_cast
< sal_uInt16
>( nValueCount
, EXC_CHDATAFORMAT_MAXPOINTCOUNT
);
948 void XclExpChSourceLink::ConvertString( const OUString
& aString
)
950 mxString
= XclExpStringHelper::CreateString( GetRoot(), aString
, XclStrFlags::ForceUnicode
| XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
953 sal_uInt16
XclExpChSourceLink::ConvertStringSequence( const Sequence
< Reference
< XFormattedString
> >& rStringSeq
)
956 sal_uInt16 nFontIdx
= EXC_FONT_APP
;
957 if( rStringSeq
.hasElements() )
959 mxString
= XclExpStringHelper::CreateString( GetRoot(), OUString(), XclStrFlags::ForceUnicode
| XclStrFlags::EightBitLength
| XclStrFlags::SeparateFormats
);
960 Reference
< XBreakIterator
> xBreakIt
= GetDoc().GetBreakIterator();
961 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
963 // convert all formatted string entries from the sequence
964 for( const Reference
< XFormattedString
>& rString
: rStringSeq
)
968 sal_uInt16 nWstrnFontIdx
= EXC_FONT_NOTFOUND
;
969 sal_uInt16 nAsianFontIdx
= EXC_FONT_NOTFOUND
;
970 sal_uInt16 nCmplxFontIdx
= EXC_FONT_NOTFOUND
;
971 OUString aText
= rString
->getString();
972 ScfPropertySet
aStrProp( rString
);
974 // #i63255# get script type for leading weak characters
975 sal_Int16 nLastScript
= XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText
);
977 // process all script portions
978 sal_Int32 nPortionPos
= 0;
979 sal_Int32 nTextLen
= aText
.getLength();
980 while( nPortionPos
< nTextLen
)
982 // get script type and end position of next script portion
983 sal_Int16 nScript
= xBreakIt
->getScriptType( aText
, nPortionPos
);
984 sal_Int32 nPortionEnd
= xBreakIt
->endOfScript( aText
, nPortionPos
, nScript
);
986 // reuse previous script for following weak portions
987 if( nScript
== ApiScriptType::WEAK
)
988 nScript
= nLastScript
;
990 // Excel start position of this portion
991 sal_uInt16 nXclPortionStart
= mxString
->Len();
992 // add portion text to Excel string
993 XclExpStringHelper::AppendString( *mxString
, GetRoot(), aText
.copy( nPortionPos
, nPortionEnd
- nPortionPos
) );
994 if( nXclPortionStart
< mxString
->Len() )
996 // find font index variable dependent on script type
997 sal_uInt16
& rnFontIdx
= (nScript
== ApiScriptType::COMPLEX
) ? nCmplxFontIdx
:
998 ((nScript
== ApiScriptType::ASIAN
) ? nAsianFontIdx
: nWstrnFontIdx
);
1000 // insert font into buffer (if not yet done)
1001 if( rnFontIdx
== EXC_FONT_NOTFOUND
)
1002 rnFontIdx
= ConvertFont( aStrProp
, nScript
);
1004 // insert font index into format run vector
1005 mxString
->AppendFormat( nXclPortionStart
, rnFontIdx
);
1008 // go to next script portion
1009 nLastScript
= nScript
;
1010 nPortionPos
= nPortionEnd
;
1014 if( !mxString
->IsEmpty() )
1016 // get leading font index
1017 const XclFormatRunVec
& rFormats
= mxString
->GetFormats();
1018 OSL_ENSURE( !rFormats
.empty() && (rFormats
.front().mnChar
== 0),
1019 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1020 // remove leading format run, if entire string is equally formatted
1021 if( rFormats
.size() == 1 )
1022 nFontIdx
= mxString
->RemoveLeadingFont();
1023 else if( !rFormats
.empty() )
1024 nFontIdx
= rFormats
.front().mnFontIdx
;
1025 // add trailing format run, if string is rich-formatted
1026 if( mxString
->IsRich() )
1027 mxString
->AppendTrailingFormat( EXC_FONT_APP
);
1033 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet
& rPropSet
, bool bPercent
)
1035 sal_Int32 nApiNumFmt
= 0;
1036 if( bPercent
? rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_PERCENTAGENUMFMT
) : rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
1038 ::set_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
1039 maData
.mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
1043 void XclExpChSourceLink::AppendString( const OUString
& rStr
)
1047 XclExpStringHelper::AppendString( *mxString
, GetRoot(), rStr
);
1050 void XclExpChSourceLink::Save( XclExpStream
& rStrm
)
1052 // CHFORMATRUNS record
1053 if( mxString
&& mxString
->IsRich() )
1055 std::size_t nRecSize
= (1 + mxString
->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8
) ? 2 : 1);
1056 rStrm
.StartRecord( EXC_ID_CHFORMATRUNS
, nRecSize
);
1057 mxString
->WriteFormats( rStrm
, true );
1060 // CHSOURCELINK record
1061 XclExpRecord::Save( rStrm
);
1063 if( mxString
&& !mxString
->IsEmpty() )
1065 rStrm
.StartRecord( EXC_ID_CHSTRING
, 2 + mxString
->GetSize() );
1066 rStrm
<< sal_uInt16( 0 ) << *mxString
;
1071 void XclExpChSourceLink::WriteBody( XclExpStream
& rStrm
)
1073 rStrm
<< maData
.mnDestType
1074 << maData
.mnLinkType
1076 << maData
.mnNumFmtIdx
1080 // Text =======================================================================
1082 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx
) :
1083 XclExpUInt16Record( EXC_ID_CHFONT
, nFontIdx
)
1087 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget
, const XclChDataPointPos
& rPointPos
) :
1088 XclExpRecord( EXC_ID_CHOBJECTLINK
, 6 )
1090 maData
.mnTarget
= nLinkTarget
;
1091 maData
.maPointPos
= rPointPos
;
1094 void XclExpChObjectLink::WriteBody( XclExpStream
& rStrm
)
1096 rStrm
<< maData
.mnTarget
<< maData
.maPointPos
.mnSeriesIdx
<< maData
.maPointPos
.mnPointIdx
;
1099 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot
& rRoot
) :
1100 XclExpChFutureRecordBase( rRoot
, EXC_FUTUREREC_UNUSEDREF
, EXC_ID_CHFRLABELPROPS
, 4 )
1104 void XclExpChFrLabelProps::Convert( const ScfPropertySet
& rPropSet
,
1105 bool bShowCateg
, bool bShowValue
, bool bShowPercent
, bool bShowBubble
)
1107 // label value flags
1108 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWSERIES
, false );
1109 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWCATEG
, bShowCateg
);
1110 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWVALUE
, bShowValue
);
1111 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWPERCENT
, bShowPercent
);
1112 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWBUBBLE
, bShowBubble
);
1114 // label value separator
1115 maData
.maSeparator
= rPropSet
.GetStringProperty( EXC_CHPROP_LABELSEPARATOR
);
1116 if( maData
.maSeparator
.isEmpty() )
1117 maData
.maSeparator
= " ";
1120 void XclExpChFrLabelProps::WriteBody( XclExpStream
& rStrm
)
1122 XclExpString
aXclSep( maData
.maSeparator
, XclStrFlags::ForceUnicode
| XclStrFlags::SmartFlags
);
1123 rStrm
<< maData
.mnFlags
<< aXclSep
;
1126 XclExpChFontBase::~XclExpChFontBase()
1130 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, sal_uInt16 nFontIdx
)
1132 if( const XclExpFont
* pFont
= rRoot
.GetFontBuffer().GetFont( nFontIdx
) )
1134 XclExpChFontRef xFont
= new XclExpChFont( nFontIdx
);
1135 SetFont( xFont
, pFont
->GetFontData().maColor
, pFont
->GetFontColorId() );
1139 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, const ScfPropertySet
& rPropSet
)
1141 ConvertFontBase( rRoot
, rRoot
.ConvertFont( rPropSet
, rRoot
.GetDefApiScript() ) );
1144 void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet
& rPropSet
, bool bSupportsStacked
)
1146 sal_uInt16 nRotation
= XclChPropSetHelper::ReadRotationProperties( rPropSet
, bSupportsStacked
);
1147 SetRotation( nRotation
);
1150 XclExpChText::XclExpChText( const XclExpChRoot
& rRoot
) :
1151 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TEXT
, EXC_ID_CHTEXT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 32 : 26 ),
1152 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
1156 void XclExpChText::SetFont( XclExpChFontRef xFont
, const Color
& rColor
, sal_uInt32 nColorId
)
1159 maData
.maTextColor
= rColor
;
1160 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, rColor
== COL_AUTO
);
1161 mnTextColorId
= nColorId
;
1164 void XclExpChText::SetRotation( sal_uInt16 nRotation
)
1166 maData
.mnRotation
= nRotation
;
1167 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 8, 3 );
1170 void XclExpChText::ConvertTitle( Reference
< XTitle
> const & xTitle
, sal_uInt16 nTarget
, const OUString
* pSubTitle
)
1174 case EXC_CHOBJLINK_TITLE
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE
); break;
1175 case EXC_CHOBJLINK_YAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 1 ); break;
1176 case EXC_CHOBJLINK_XAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
); break;
1177 case EXC_CHOBJLINK_ZAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 2 ); break;
1181 mxObjLink
= new XclExpChObjectLink( nTarget
, XclChDataPointPos( 0, 0 ) );
1185 // title frame formatting
1186 ScfPropertySet
aTitleProp( xTitle
);
1187 mxFrame
= lclCreateFrame( GetChRoot(), aTitleProp
, EXC_CHOBJTYPE_TEXT
);
1190 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1191 sal_uInt16 nFontIdx
= mxSrcLink
->ConvertStringSequence( xTitle
->getText() );
1194 // append subtitle as the 2nd line of the title.
1195 OUString aSubTitle
= "\n" + *pSubTitle
;
1196 mxSrcLink
->AppendString(aSubTitle
);
1199 ConvertFontBase( GetChRoot(), nFontIdx
);
1202 ConvertRotationBase( aTitleProp
, true );
1204 // manual text position - only for main title
1205 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
);
1206 if( nTarget
== EXC_CHOBJLINK_TITLE
)
1209 if( aTitleProp
.GetAnyProperty( aRelPos
, EXC_CHPROP_RELATIVEPOSITION
) && aRelPos
.has
< RelativePosition
>() ) try
1211 // calculate absolute position for CHTEXT record
1212 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
1213 Reference
< XShape
> xTitleShape( xChart1Doc
->getTitle(), UNO_SET_THROW
);
1214 css::awt::Point aPos
= xTitleShape
->getPosition();
1215 css::awt::Size aSize
= xTitleShape
->getSize();
1216 css::awt::Rectangle
aRect( aPos
.X
, aPos
.Y
, aSize
.Width
, aSize
.Height
);
1217 maData
.maRect
= CalcChartRectFromHmm( aRect
);
1218 ::insert_value( maData
.mnFlags2
, EXC_CHTEXT_POS_MOVED
, 0, 4 );
1219 // manual title position implies manual plot area
1220 GetChartData().SetManualPlotArea();
1221 // calculate the default title position in chart units
1222 sal_Int32 nDefPosX
= ::std::max
< sal_Int32
>( (EXC_CHART_TOTALUNITS
- maData
.maRect
.mnWidth
) / 2, 0 );
1223 sal_Int32 nDefPosY
= 85;
1224 // set the position relative to the standard position
1225 XclChRectangle
& rFrameRect
= mxFramePos
->GetFramePosData().maRect
;
1226 rFrameRect
.mnX
= maData
.maRect
.mnX
- nDefPosX
;
1227 rFrameRect
.mnY
= maData
.maRect
.mnY
- nDefPosY
;
1236 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
);
1240 void XclExpChText::ConvertLegend( const ScfPropertySet
& rPropSet
)
1242 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1243 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOGEN
);
1244 ConvertFontBase( GetChRoot(), rPropSet
);
1247 bool XclExpChText::ConvertDataLabel( const ScfPropertySet
& rPropSet
,
1248 const XclChTypeInfo
& rTypeInfo
, const XclChDataPointPos
& rPointPos
)
1250 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL
, rPointPos
.mnPointIdx
, rPointPos
.mnSeriesIdx
);
1252 cssc2::DataPointLabel aPointLabel
;
1253 if( !rPropSet
.GetProperty( aPointLabel
, EXC_CHPROP_LABEL
) )
1256 // percentage only allowed in pie and donut charts
1257 bool bIsPie
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
;
1258 // bubble sizes only allowed in bubble charts
1259 bool bIsBubble
= rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
;
1260 OSL_ENSURE( (GetBiff() == EXC_BIFF8
) || !bIsBubble
, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1263 bool bShowValue
= !bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1264 bool bShowPercent
= bIsPie
&& aPointLabel
.ShowNumberInPercent
; // percentage only in pie/donut charts
1265 bool bShowCateg
= aPointLabel
.ShowCategoryName
;
1266 bool bShowBubble
= bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1267 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
|| bShowBubble
;
1269 // create the CHFRLABELPROPS record for extended settings in BIFF8
1270 if( bShowAny
&& (GetBiff() == EXC_BIFF8
) )
1272 mxLabelProps
= new XclExpChFrLabelProps( GetChRoot() );
1273 mxLabelProps
->Convert( rPropSet
, bShowCateg
, bShowValue
, bShowPercent
, bShowBubble
);
1276 // restrict to combinations allowed in CHTEXT
1277 if( bShowPercent
) bShowValue
= false; // percent wins over value
1278 if( bShowValue
) bShowCateg
= false; // value wins over category
1279 if( bShowValue
|| bShowCateg
) bShowBubble
= false; // value or category wins over bubble size
1282 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1283 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bShowValue
);
1284 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bShowPercent
);
1285 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bShowCateg
);
1286 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bShowPercent
&& bShowCateg
);
1287 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWBUBBLE
, bShowBubble
);
1288 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
, bShowAny
&& aPointLabel
.ShowLegendSymbol
);
1289 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bShowAny
);
1294 ConvertFontBase( GetChRoot(), rPropSet
);
1295 ConvertRotationBase( rPropSet
, false );
1297 sal_Int32 nPlacement
= 0;
1298 sal_uInt16 nLabelPos
= EXC_CHTEXT_POS_AUTO
;
1299 if( rPropSet
.GetProperty( nPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1301 using namespace cssc::DataLabelPlacement
;
1302 if( nPlacement
== rTypeInfo
.mnDefaultLabelPos
)
1304 nLabelPos
= EXC_CHTEXT_POS_DEFAULT
;
1306 else switch( nPlacement
)
1308 case AVOID_OVERLAP
: nLabelPos
= EXC_CHTEXT_POS_AUTO
; break;
1309 case CENTER
: nLabelPos
= EXC_CHTEXT_POS_CENTER
; break;
1310 case TOP
: nLabelPos
= EXC_CHTEXT_POS_ABOVE
; break;
1311 case TOP_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1312 case LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1313 case BOTTOM_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1314 case BOTTOM
: nLabelPos
= EXC_CHTEXT_POS_BELOW
; break;
1315 case BOTTOM_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1316 case RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1317 case TOP_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1318 case INSIDE
: nLabelPos
= EXC_CHTEXT_POS_INSIDE
; break;
1319 case OUTSIDE
: nLabelPos
= EXC_CHTEXT_POS_OUTSIDE
; break;
1320 case NEAR_ORIGIN
: nLabelPos
= EXC_CHTEXT_POS_AXIS
; break;
1321 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1324 ::insert_value( maData
.mnFlags2
, nLabelPos
, 0, 4 );
1325 // source link (contains number format)
1326 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1327 if( bShowValue
|| bShowPercent
)
1328 // percentage format wins over value format
1329 mxSrcLink
->ConvertNumFmt( rPropSet
, bShowPercent
);
1331 mxObjLink
= new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
);
1334 /* Return true to indicate valid label settings:
1335 - for existing labels at entire series
1336 - for any settings at single data point (to be able to delete a point label) */
1337 return bShowAny
|| (rPointPos
.mnPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
);
1340 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet
& rPropSet
, const XclChDataPointPos
& rPointPos
)
1343 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1344 if( GetBiff() == EXC_BIFF8
)
1345 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
); // must set this to make equation visible in Excel
1347 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_TEXT
);
1349 maData
.mnHAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1350 maData
.mnVAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1351 ConvertFontBase( GetChRoot(), rPropSet
);
1352 // source link (contains number format)
1353 mxSrcLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1354 mxSrcLink
->ConvertNumFmt( rPropSet
, false );
1356 mxObjLink
= new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
);
1359 sal_uInt16
XclExpChText::GetAttLabelFlags() const
1361 sal_uInt16 nFlags
= 0;
1362 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWVALUE
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
) );
1363 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWPERCENT
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
) );
1364 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEGPERC
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
) );
1365 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEG
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
) );
1369 void XclExpChText::WriteSubRecords( XclExpStream
& rStrm
)
1371 // CHFRAMEPOS record
1372 lclSaveRecord( rStrm
, mxFramePos
);
1374 lclSaveRecord( rStrm
, mxFont
);
1375 // CHSOURCELINK group
1376 lclSaveRecord( rStrm
, mxSrcLink
);
1378 lclSaveRecord( rStrm
, mxFrame
);
1379 // CHOBJECTLINK record
1380 lclSaveRecord( rStrm
, mxObjLink
);
1381 // CHFRLABELPROPS record
1382 lclSaveRecord( rStrm
, mxLabelProps
);
1385 void XclExpChText::WriteBody( XclExpStream
& rStrm
)
1387 rStrm
<< maData
.mnHAlign
1389 << maData
.mnBackMode
1390 << maData
.maTextColor
1394 if( GetBiff() == EXC_BIFF8
)
1396 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
)
1398 << maData
.mnRotation
;
1404 /** Creates and returns an Excel text object from the passed title. */
1405 XclExpChTextRef
lclCreateTitle( const XclExpChRoot
& rRoot
, Reference
< XTitled
> const & xTitled
, sal_uInt16 nTarget
,
1406 const OUString
* pSubTitle
= nullptr )
1408 Reference
< XTitle
> xTitle
;
1410 xTitle
= xTitled
->getTitleObject();
1412 XclExpChTextRef xText
= new XclExpChText( rRoot
);
1413 xText
->ConvertTitle( xTitle
, nTarget
, pSubTitle
);
1414 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1415 will be interpreted as auto-generated title showing the series title in
1416 charts that contain exactly one data series. */
1417 if( (nTarget
!= EXC_CHOBJLINK_TITLE
) && !xText
->HasString() )
1425 // Data series ================================================================
1427 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot
& rRoot
) :
1428 XclExpRecord( EXC_ID_CHMARKERFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 20 : 12 ),
1429 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) ),
1430 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
1434 void XclExpChMarkerFormat::Convert( const XclExpChRoot
& rRoot
,
1435 const ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
)
1437 XclChPropSetHelper::ReadMarkerProperties( maData
, rPropSet
, nFormatIdx
);
1438 /* Set marker line/fill color to series line color.
1439 TODO: remove this if OOChart supports own colors in markers. */
1441 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1442 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1443 // register colors in palette
1444 RegisterColors( rRoot
);
1447 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot
& rRoot
,
1448 const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1450 // clear the automatic flag
1451 ::set_flag( maData
.mnFlags
, EXC_CHMARKERFORMAT_AUTO
, false );
1452 // symbol type and color
1455 // set symbol type for the 'close' data series
1456 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_DOWJ
;
1457 maData
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
;
1458 // set symbol line/fill color to series line color
1460 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1462 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1463 RegisterColors( rRoot
);
1468 // set invisible symbol
1469 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_NOSYMBOL
;
1473 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot
& rRoot
)
1477 if( HasLineColor() )
1478 mnLineColorId
= rRoot
.GetPalette().InsertColor( maData
.maLineColor
, EXC_COLOR_CHARTLINE
);
1479 if( HasFillColor() )
1480 mnFillColorId
= rRoot
.GetPalette().InsertColor( maData
.maFillColor
, EXC_COLOR_CHARTAREA
);
1484 void XclExpChMarkerFormat::WriteBody( XclExpStream
& rStrm
)
1486 rStrm
<< maData
.maLineColor
<< maData
.maFillColor
<< maData
.mnMarkerType
<< maData
.mnFlags
;
1487 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
1489 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
1490 rStrm
<< rPal
.GetColorIndex( mnLineColorId
) << rPal
.GetColorIndex( mnFillColorId
) << maData
.mnMarkerSize
;
1494 XclExpChPieFormat::XclExpChPieFormat() :
1495 XclExpUInt16Record( EXC_ID_CHPIEFORMAT
, 0 )
1499 void XclExpChPieFormat::Convert( const ScfPropertySet
& rPropSet
)
1501 double fApiDist(0.0);
1502 if( rPropSet
.GetProperty( fApiDist
, EXC_CHPROP_OFFSET
) )
1503 SetValue( limit_cast
< sal_uInt16
>( fApiDist
* 100.0, 0, 100 ) );
1506 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1507 XclExpRecord( EXC_ID_CH3DDATAFORMAT
, 2 )
1511 void XclExpCh3dDataFormat::Convert( const ScfPropertySet
& rPropSet
)
1513 sal_Int32
nApiType(0);
1514 if( !rPropSet
.GetProperty( nApiType
, EXC_CHPROP_GEOMETRY3D
) )
1517 using namespace cssc2::DataPointGeometry3D
;
1521 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1522 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1525 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1526 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1529 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1530 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1533 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1534 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1537 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1541 void XclExpCh3dDataFormat::WriteBody( XclExpStream
& rStrm
)
1543 rStrm
<< maData
.mnBase
<< maData
.mnTop
;
1546 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags
) :
1547 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL
, nFlags
)
1551 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot
& rRoot
,
1552 const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
) :
1553 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DATAFORMAT
, EXC_ID_CHDATAFORMAT
, 8 )
1555 maData
.maPointPos
= rPointPos
;
1556 maData
.mnFormatIdx
= nFormatIdx
;
1559 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
)
1561 // line and area formatting
1562 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType() );
1564 // data point symbols
1565 bool bIsFrame
= rTypeInfo
.IsSeriesFrameFormat();
1568 mxMarkerFmt
= new XclExpChMarkerFormat( GetChRoot() );
1569 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1573 if( rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)
1575 mxPieFmt
= new XclExpChPieFormat();
1576 mxPieFmt
->Convert( rPropSet
);
1579 // 3D bars (only allowed for entire series in BIFF8)
1580 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8
) && rTypeInfo
.mb3dChart
&& (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
) )
1582 mx3dDataFmt
= new XclExpCh3dDataFormat();
1583 mx3dDataFmt
->Convert( rPropSet
);
1587 if( IsSeriesFormat() && rTypeInfo
.mbSpline
&& !bIsFrame
)
1588 mxSeriesFmt
= new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT
, EXC_CHSERIESFORMAT_SMOOTHED
);
1590 // data point labels
1591 XclExpChTextRef xLabel
= new XclExpChText( GetChRoot() );
1592 if( xLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, maData
.maPointPos
) )
1594 // CHTEXT groups for data labels are stored in global CHCHART group
1595 GetChartData().SetDataLabel( xLabel
);
1596 mxAttLabel
= new XclExpChAttachedLabel( xLabel
->GetAttLabelFlags() );
1600 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1602 // set line format to invisible
1603 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, false );
1604 // set symbols to invisible or to 'close' series symbol
1605 mxMarkerFmt
= new XclExpChMarkerFormat( GetChRoot() );
1606 mxMarkerFmt
->ConvertStockSymbol( GetChRoot(), rPropSet
, bCloseSymbol
);
1609 void XclExpChDataFormat::ConvertLine( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
1611 ConvertFrameBase( GetChRoot(), rPropSet
, eObjType
);
1614 void XclExpChDataFormat::WriteSubRecords( XclExpStream
& rStrm
)
1616 lclSaveRecord( rStrm
, mx3dDataFmt
);
1617 WriteFrameRecords( rStrm
);
1618 lclSaveRecord( rStrm
, mxPieFmt
);
1619 lclSaveRecord( rStrm
, mxMarkerFmt
);
1620 lclSaveRecord( rStrm
, mxSeriesFmt
);
1621 lclSaveRecord( rStrm
, mxAttLabel
);
1624 void XclExpChDataFormat::WriteBody( XclExpStream
& rStrm
)
1626 rStrm
<< maData
.maPointPos
.mnPointIdx
1627 << maData
.maPointPos
.mnSeriesIdx
1628 << maData
.mnFormatIdx
1632 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot
& rRoot
) :
1633 XclExpRecord( EXC_ID_CHSERTRENDLINE
, 28 ),
1634 XclExpChRoot( rRoot
)
1638 bool XclExpChSerTrendLine::Convert( Reference
< XRegressionCurve
> const & xRegCurve
, sal_uInt16 nSeriesIdx
)
1640 if( !xRegCurve
.is() )
1644 ScfPropertySet
aCurveProp( xRegCurve
);
1646 OUString aService
= aCurveProp
.GetServiceName();
1647 if( aService
== "com.sun.star.chart2.LinearRegressionCurve" )
1649 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1652 else if( aService
== "com.sun.star.chart2.ExponentialRegressionCurve" )
1654 maData
.mnLineType
= EXC_CHSERTREND_EXPONENTIAL
;
1656 else if( aService
== "com.sun.star.chart2.LogarithmicRegressionCurve" )
1658 maData
.mnLineType
= EXC_CHSERTREND_LOGARITHMIC
;
1660 else if( aService
== "com.sun.star.chart2.PotentialRegressionCurve" )
1662 maData
.mnLineType
= EXC_CHSERTREND_POWER
;
1664 else if( aService
== "com.sun.star.chart2.PolynomialRegressionCurve" )
1666 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1668 aCurveProp
.GetProperty(aDegree
, EXC_CHPROP_POLYNOMIAL_DEGREE
);
1669 maData
.mnOrder
= static_cast<sal_uInt8
> (aDegree
);
1671 else if( aService
== "com.sun.star.chart2.MovingAverageRegressionCurve" )
1673 maData
.mnLineType
= EXC_CHSERTREND_MOVING_AVG
;
1675 aCurveProp
.GetProperty(aPeriod
, EXC_CHPROP_MOVING_AVERAGE_PERIOD
);
1676 maData
.mnOrder
= static_cast<sal_uInt8
> (aPeriod
);
1683 aCurveProp
.GetProperty(maData
.mfForecastFor
, EXC_CHPROP_EXTRAPOLATE_FORWARD
);
1684 aCurveProp
.GetProperty(maData
.mfForecastBack
, EXC_CHPROP_EXTRAPOLATE_BACKWARD
);
1685 bool bIsForceIntercept
= false;
1686 aCurveProp
.GetProperty(bIsForceIntercept
, EXC_CHPROP_FORCE_INTERCEPT
);
1687 if (bIsForceIntercept
)
1688 aCurveProp
.GetProperty(maData
.mfIntercept
, EXC_CHPROP_INTERCEPT_VALUE
);
1691 XclChDataPointPos
aPointPos( nSeriesIdx
);
1692 mxDataFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, 0 );
1693 mxDataFmt
->ConvertLine( aCurveProp
, EXC_CHOBJTYPE_TRENDLINE
);
1695 // #i83100# show equation and correlation coefficient
1696 ScfPropertySet
aEquationProp( xRegCurve
->getEquationProperties() );
1697 maData
.mnShowEquation
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWEQUATION
) ? 1 : 0;
1698 maData
.mnShowRSquared
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION
) ? 1 : 0;
1700 // #i83100# formatting of the equation text box
1701 if( (maData
.mnShowEquation
!= 0) || (maData
.mnShowRSquared
!= 0) )
1703 mxLabel
= new XclExpChText( GetChRoot() );
1704 mxLabel
->ConvertTrendLineEquation( aEquationProp
, aPointPos
);
1708 // #i5085# manual trend line size
1709 // #i34093# manual crossing point
1713 void XclExpChSerTrendLine::WriteBody( XclExpStream
& rStrm
)
1715 rStrm
<< maData
.mnLineType
1717 << maData
.mfIntercept
1718 << maData
.mnShowEquation
1719 << maData
.mnShowRSquared
1720 << maData
.mfForecastFor
1721 << maData
.mfForecastBack
;
1724 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot
& rRoot
, sal_uInt8 nBarType
) :
1725 XclExpRecord( EXC_ID_CHSERERRORBAR
, 14 ),
1726 XclExpChRoot( rRoot
)
1728 maData
.mnBarType
= nBarType
;
1731 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink
& rValueLink
, sal_uInt16
& rnValueCount
, const ScfPropertySet
& rPropSet
)
1733 sal_Int32 nBarStyle
= 0;
1734 bool bOk
= rPropSet
.GetProperty( nBarStyle
, EXC_CHPROP_ERRORBARSTYLE
);
1739 case cssc::ErrorBarStyle::ABSOLUTE
:
1740 maData
.mnSourceType
= EXC_CHSERERR_FIXED
;
1741 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1743 case cssc::ErrorBarStyle::RELATIVE
:
1744 maData
.mnSourceType
= EXC_CHSERERR_PERCENT
;
1745 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1747 case cssc::ErrorBarStyle::STANDARD_DEVIATION
:
1748 maData
.mnSourceType
= EXC_CHSERERR_STDDEV
;
1749 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_WEIGHT
);
1751 case cssc::ErrorBarStyle::STANDARD_ERROR
:
1752 maData
.mnSourceType
= EXC_CHSERERR_STDERR
;
1754 case cssc::ErrorBarStyle::FROM_DATA
:
1757 maData
.mnSourceType
= EXC_CHSERERR_CUSTOM
;
1758 Reference
< XDataSource
> xDataSource( rPropSet
.GetApiPropertySet(), UNO_QUERY
);
1759 if( xDataSource
.is() )
1761 // find first sequence with current role
1762 OUString aRole
= XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
);
1763 Reference
< XDataSequence
> xValueSeq
;
1765 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1766 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1768 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1769 ScfPropertySet
aValueProp( xTmpValueSeq
);
1771 if( aValueProp
.GetProperty( aCurrRole
, EXC_CHPROP_ROLE
) && (aCurrRole
== aRole
) )
1773 xValueSeq
= xTmpValueSeq
;
1777 if( xValueSeq
.is() )
1779 // #i86465# pass value count back to series
1780 rnValueCount
= maData
.mnValueCount
= rValueLink
.ConvertDataSequence( xValueSeq
, true );
1781 bOk
= maData
.mnValueCount
> 0;
1793 void XclExpChSerErrorBar::WriteBody( XclExpStream
& rStrm
)
1795 rStrm
<< maData
.mnBarType
1796 << maData
.mnSourceType
1798 << sal_uInt8( 1 ) // must be 1 to make line visible
1800 << maData
.mnValueCount
;
1805 /** Returns the property set of the specified data point. */
1806 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> const & xDataSeries
, sal_Int32 nPointIdx
)
1808 ScfPropertySet aPropSet
;
1811 aPropSet
.Set( xDataSeries
->getDataPointByIndex( nPointIdx
) );
1815 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1822 XclExpChSeries::XclExpChSeries( const XclExpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1823 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_SERIES
, EXC_ID_CHSERIES
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 8 ),
1824 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1825 mnSeriesIdx( nSeriesIdx
),
1826 mnParentIdx( EXC_CHSERIES_INVALID
)
1828 // CHSOURCELINK records are always required, even if unused
1829 mxTitleLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
);
1830 mxValueLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES
);
1831 mxCategLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY
);
1832 if( GetBiff() == EXC_BIFF8
)
1833 mxBubbleLink
= new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES
);
1836 bool XclExpChSeries::ConvertDataSeries(
1837 Reference
< XDiagram
> const & xDiagram
, Reference
< XDataSeries
> const & xDataSeries
,
1838 const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
)
1841 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1842 if( xDataSource
.is() )
1844 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
, xXValueSeq
, xBubbleSeq
;
1846 // find first sequence with role 'values-y'
1847 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1848 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1850 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1851 ScfPropertySet
aValueProp( xTmpValueSeq
);
1853 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) )
1855 if( !xYValueSeq
.is() && (aRole
== EXC_CHPROP_ROLE_YVALUES
) )
1857 xYValueSeq
= xTmpValueSeq
;
1858 if( !xTitleSeq
.is() )
1859 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1861 else if( !xXValueSeq
.is() && !rTypeInfo
.mbCategoryAxis
&& (aRole
== EXC_CHPROP_ROLE_XVALUES
) )
1863 xXValueSeq
= xTmpValueSeq
;
1865 else if( !xBubbleSeq
.is() && (rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
) && (aRole
== EXC_CHPROP_ROLE_SIZEVALUES
) )
1867 xBubbleSeq
= xTmpValueSeq
;
1868 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1873 bOk
= xYValueSeq
.is();
1876 // chart type group index
1877 mnGroupIdx
= nGroupIdx
;
1879 // convert source links
1880 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1881 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1883 // X values of XY charts
1884 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xXValueSeq
, false, maData
.mnValueCount
);
1886 // size values of bubble charts
1888 mxBubbleLink
->ConvertDataSequence( xBubbleSeq
, false, maData
.mnValueCount
);
1890 // series formatting
1891 XclChDataPointPos
aPointPos( mnSeriesIdx
);
1892 ScfPropertySet
aSeriesProp( xDataSeries
);
1893 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
);
1894 mxSeriesFmt
->ConvertDataSeries( aSeriesProp
, rTypeInfo
);
1897 CreateTrendLines( xDataSeries
);
1900 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARX
, EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
1901 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARY
, EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
1903 if( maData
.mnValueCount
> 0 )
1905 const sal_Int32 nMaxPointCount
= maData
.mnValueCount
;
1907 /* #i91063# Create missing fill properties in pie/doughnut charts.
1908 If freshly created (never saved to ODF), these charts show
1909 varying point colors but do not return these points via API. */
1910 if( xDiagram
.is() && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
1912 Reference
< XColorScheme
> xColorScheme
= xDiagram
->getDefaultColorScheme();
1913 if( xColorScheme
.is() )
1915 static const OUStringLiteral aFillStyleName
= u
"FillStyle";
1916 static const OUStringLiteral aColorName
= u
"Color";
1917 namespace cssd
= ::com::sun::star::drawing
;
1918 for( sal_Int32 nPointIdx
= 0; nPointIdx
< nMaxPointCount
; ++nPointIdx
)
1920 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( nPointIdx
);
1921 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
1922 // test that the point fill style is solid, but no color is set
1923 cssd::FillStyle eFillStyle
= cssd::FillStyle_NONE
;
1924 if( aPointProp
.GetProperty( eFillStyle
, aFillStyleName
) &&
1925 (eFillStyle
== cssd::FillStyle_SOLID
) &&
1926 !aPointProp
.HasProperty( aColorName
) )
1928 aPointProp
.SetProperty( aColorName
, xColorScheme
->getColorByIndex( nPointIdx
) );
1934 // data point formatting
1935 Sequence
< sal_Int32
> aPointIndexes
;
1936 if( aSeriesProp
.GetProperty( aPointIndexes
, EXC_CHPROP_ATTRIBDATAPOINTS
) && aPointIndexes
.hasElements() )
1938 for( const sal_Int32 nPointIndex
: std::as_const(aPointIndexes
) )
1940 if (nPointIndex
>= nMaxPointCount
)
1942 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( nPointIndex
);
1943 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIndex
);
1944 XclExpChDataFormatRef xPointFmt
= new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
);
1945 xPointFmt
->ConvertDataSeries( aPointProp
, rTypeInfo
);
1946 maPointFmts
.AppendRecord( xPointFmt
);
1955 bool XclExpChSeries::ConvertStockSeries( css::uno::Reference
< css::chart2::XDataSeries
> const & xDataSeries
,
1956 std::u16string_view rValueRole
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
, bool bCloseSymbol
)
1959 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1960 if( xDataSource
.is() )
1962 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
;
1964 // find first sequence with passed role
1965 const Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1966 for( const Reference
< XLabeledDataSequence
>& rLabeledSeq
: aLabeledSeqVec
)
1968 Reference
< XDataSequence
> xTmpValueSeq
= rLabeledSeq
->getValues();
1969 ScfPropertySet
aValueProp( xTmpValueSeq
);
1971 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) && (aRole
== rValueRole
) )
1973 xYValueSeq
= xTmpValueSeq
;
1974 xTitleSeq
= rLabeledSeq
->getLabel(); // ignore role of label sequence
1979 bOk
= xYValueSeq
.is();
1982 // chart type group index
1983 mnGroupIdx
= nGroupIdx
;
1984 // convert source links
1985 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1986 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1987 // series formatting
1988 ScfPropertySet
aSeriesProp( xDataSeries
);
1989 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), nFormatIdx
);
1990 mxSeriesFmt
->ConvertStockSeries( aSeriesProp
, bCloseSymbol
);
1996 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries
& rParent
, Reference
< XRegressionCurve
> const & xRegCurve
)
1998 InitFromParent( rParent
);
2000 mxTrendLine
= new XclExpChSerTrendLine( GetChRoot() );
2001 bool bOk
= mxTrendLine
->Convert( xRegCurve
, mnSeriesIdx
);
2005 ScfPropertySet
aProperties( xRegCurve
);
2006 aProperties
.GetProperty(aName
, EXC_CHPROP_CURVENAME
);
2007 mxTitleLink
->ConvertString(aName
);
2009 mxSeriesFmt
= mxTrendLine
->GetDataFormat();
2010 GetChartData().SetDataLabel( mxTrendLine
->GetDataLabel() );
2015 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries
& rParent
, const ScfPropertySet
& rPropSet
, sal_uInt8 nBarId
)
2017 InitFromParent( rParent
);
2018 // error bar settings
2019 mxErrorBar
= new XclExpChSerErrorBar( GetChRoot(), nBarId
);
2020 bool bOk
= mxErrorBar
->Convert( *mxValueLink
, maData
.mnValueCount
, rPropSet
);
2023 // error bar formatting
2024 mxSeriesFmt
= new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), 0 );
2025 mxSeriesFmt
->ConvertLine( rPropSet
, EXC_CHOBJTYPE_ERRORBAR
);
2030 void XclExpChSeries::ConvertCategSequence( Reference
< XLabeledDataSequence
> const & xCategSeq
)
2032 if( xCategSeq
.is() )
2033 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xCategSeq
->getValues(), false );
2036 void XclExpChSeries::WriteSubRecords( XclExpStream
& rStrm
)
2038 lclSaveRecord( rStrm
, mxTitleLink
);
2039 lclSaveRecord( rStrm
, mxValueLink
);
2040 lclSaveRecord( rStrm
, mxCategLink
);
2041 lclSaveRecord( rStrm
, mxBubbleLink
);
2042 lclSaveRecord( rStrm
, mxSeriesFmt
);
2043 maPointFmts
.Save( rStrm
);
2044 if( mnGroupIdx
!= EXC_CHSERGROUP_NONE
)
2045 XclExpUInt16Record( EXC_ID_CHSERGROUP
, mnGroupIdx
).Save( rStrm
);
2046 if( mnParentIdx
!= EXC_CHSERIES_INVALID
)
2047 XclExpUInt16Record( EXC_ID_CHSERPARENT
, mnParentIdx
).Save( rStrm
);
2048 lclSaveRecord( rStrm
, mxTrendLine
);
2049 lclSaveRecord( rStrm
, mxErrorBar
);
2052 void XclExpChSeries::InitFromParent( const XclExpChSeries
& rParent
)
2054 // index to parent series is stored 1-based
2055 mnParentIdx
= rParent
.mnSeriesIdx
+ 1;
2056 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2057 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2058 maData
.mnCategCount
= rParent
.maData
.mnCategCount
;
2059 maData
.mnValueCount
= rParent
.maData
.mnValueCount
;
2062 void XclExpChSeries::CreateTrendLines( css::uno::Reference
< css::chart2::XDataSeries
> const & xDataSeries
)
2064 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2065 if( xRegCurveCont
.is() )
2067 const Sequence
< Reference
< XRegressionCurve
> > aRegCurveSeq
= xRegCurveCont
->getRegressionCurves();
2068 for( const Reference
< XRegressionCurve
>& rRegCurve
: aRegCurveSeq
)
2070 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2071 if( xSeries
&& !xSeries
->ConvertTrendLine( *this, rRegCurve
) )
2072 GetChartData().RemoveLastSeries();
2077 void XclExpChSeries::CreateErrorBars( const ScfPropertySet
& rPropSet
,
2078 const OUString
& rBarPropName
, sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
)
2080 Reference
< XPropertySet
> xErrorBar
;
2081 if( rPropSet
.GetProperty( xErrorBar
, rBarPropName
) && xErrorBar
.is() )
2083 ScfPropertySet
aErrorProp( xErrorBar
);
2084 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWPOSITIVEERROR
, nPosBarId
);
2085 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWNEGATIVEERROR
, nNegBarId
);
2089 void XclExpChSeries::CreateErrorBar( const ScfPropertySet
& rPropSet
,
2090 const OUString
& rShowPropName
, sal_uInt8 nBarId
)
2092 if( rPropSet
.GetBoolProperty( rShowPropName
) )
2094 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2095 if( xSeries
&& !xSeries
->ConvertErrorBar( *this, rPropSet
, nBarId
) )
2096 GetChartData().RemoveLastSeries();
2100 void XclExpChSeries::WriteBody( XclExpStream
& rStrm
)
2102 rStrm
<< maData
.mnCategType
<< maData
.mnValueType
<< maData
.mnCategCount
<< maData
.mnValueCount
;
2103 if( GetBiff() == EXC_BIFF8
)
2104 rStrm
<< maData
.mnBubbleType
<< maData
.mnBubbleCount
;
2107 // Chart type groups ==========================================================
2109 XclExpChType::XclExpChType( const XclExpChRoot
& rRoot
) :
2110 XclExpRecord( EXC_ID_CHUNKNOWN
),
2111 XclExpChRoot( rRoot
),
2112 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2116 void XclExpChType::Convert( Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2117 sal_Int32 nApiAxesSetIdx
, bool bSwappedAxesSet
, bool bHasXLabels
)
2119 if( !xChartType
.is() )
2122 maTypeInfo
= GetChartTypeInfo( xChartType
->getChartType() );
2123 // special handling for some chart types
2124 switch( maTypeInfo
.meTypeCateg
)
2126 case EXC_CHTYPECATEG_BAR
:
2128 maTypeInfo
= GetChartTypeInfo( bSwappedAxesSet
? EXC_CHTYPEID_HORBAR
: EXC_CHTYPEID_BAR
);
2129 ::set_flag( maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
, bSwappedAxesSet
);
2130 ScfPropertySet
aTypeProp( xChartType
);
2131 Sequence
< sal_Int32
> aInt32Seq
;
2132 maData
.mnOverlap
= 0;
2133 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_OVERLAPSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2134 maData
.mnOverlap
= limit_cast
< sal_Int16
>( -aInt32Seq
[ nApiAxesSetIdx
], -100, 100 );
2136 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_GAPWIDTHSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2137 maData
.mnGap
= limit_cast
< sal_uInt16
>( aInt32Seq
[ nApiAxesSetIdx
], 0, 500 );
2140 case EXC_CHTYPECATEG_RADAR
:
2141 ::set_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
, bHasXLabels
);
2143 case EXC_CHTYPECATEG_PIE
:
2145 ScfPropertySet
aTypeProp( xChartType
);
2146 bool bDonut
= aTypeProp
.GetBoolProperty( EXC_CHPROP_USERINGS
);
2147 maTypeInfo
= GetChartTypeInfo( bDonut
? EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2148 maData
.mnPieHole
= bDonut
? 50 : 0;
2149 // #i85166# starting angle of first pie slice
2150 ScfPropertySet
aDiaProp( xDiagram
);
2151 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( aDiaProp
);
2154 case EXC_CHTYPECATEG_SCATTER
:
2155 if( GetBiff() == EXC_BIFF8
)
2156 ::set_flag( maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
);
2160 SetRecId( maTypeInfo
.mnRecId
);
2163 void XclExpChType::SetStacked( bool bPercent
)
2165 switch( maTypeInfo
.meTypeCateg
)
2167 case EXC_CHTYPECATEG_LINE
:
2168 ::set_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
);
2169 ::set_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
, bPercent
);
2171 case EXC_CHTYPECATEG_BAR
:
2172 ::set_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
);
2173 ::set_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
, bPercent
);
2174 maData
.mnOverlap
= -100;
2180 void XclExpChType::WriteBody( XclExpStream
& rStrm
)
2182 switch( GetRecId() )
2185 rStrm
<< maData
.mnOverlap
<< maData
.mnGap
<< maData
.mnFlags
;
2190 case EXC_ID_CHRADARLINE
:
2191 case EXC_ID_CHRADARAREA
:
2192 rStrm
<< maData
.mnFlags
;
2196 rStrm
<< maData
.mnRotation
<< maData
.mnPieHole
;
2197 if( GetBiff() == EXC_BIFF8
)
2198 rStrm
<< maData
.mnFlags
;
2201 case EXC_ID_CHSCATTER
:
2202 if( GetBiff() == EXC_BIFF8
)
2203 rStrm
<< maData
.mnBubbleSize
<< maData
.mnBubbleType
<< maData
.mnFlags
;
2207 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" );
2211 XclExpChChart3d::XclExpChChart3d() :
2212 XclExpRecord( EXC_ID_CHCHART3D
, 14 )
2216 void XclExpChChart3d::Convert( const ScfPropertySet
& rPropSet
, bool b3dWallChart
)
2218 sal_Int32 nRotationY
= 0;
2219 rPropSet
.GetProperty( nRotationY
, EXC_CHPROP_ROTATIONVERTICAL
);
2220 sal_Int32 nRotationX
= 0;
2221 rPropSet
.GetProperty( nRotationX
, EXC_CHPROP_ROTATIONHORIZONTAL
);
2222 sal_Int32 nPerspective
= 15;
2223 rPropSet
.GetProperty( nPerspective
, EXC_CHPROP_PERSPECTIVE
);
2227 // Y rotation (Excel [0..359], Chart2 [-179,180])
2228 if( nRotationY
< 0 ) nRotationY
+= 360;
2229 maData
.mnRotation
= static_cast< sal_uInt16
>( nRotationY
);
2230 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2231 maData
.mnElevation
= limit_cast
< sal_Int16
>( nRotationX
, -90, 90 );
2232 // perspective (Excel and Chart2 [0,100])
2233 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2236 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
, !rPropSet
.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
) );
2237 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_AUTOHEIGHT
);
2238 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_HASWALLS
);
2242 // Y rotation not used in pie charts, but 'first pie slice angle'
2243 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( rPropSet
);
2244 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2245 maData
.mnElevation
= limit_cast
< sal_Int16
>( (nRotationX
+ 270) % 180, 10, 80 );
2246 // perspective (Excel and Chart2 [0,100])
2247 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2253 void XclExpChChart3d::WriteBody( XclExpStream
& rStrm
)
2255 rStrm
<< maData
.mnRotation
2256 << maData
.mnElevation
2258 << maData
.mnRelHeight
2259 << maData
.mnRelDepth
2260 << maData
.mnDepthGap
2264 XclExpChLegend::XclExpChLegend( const XclExpChRoot
& rRoot
) :
2265 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_LEGEND
, EXC_ID_CHLEGEND
, 20 )
2269 void XclExpChLegend::Convert( const ScfPropertySet
& rPropSet
)
2272 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_LEGEND
);
2274 mxText
= new XclExpChText( GetChRoot() );
2275 mxText
->ConvertLegend( rPropSet
);
2277 // legend position and size
2278 Any aRelPosAny
, aRelSizeAny
;
2279 rPropSet
.GetAnyProperty( aRelPosAny
, EXC_CHPROP_RELATIVEPOSITION
);
2280 rPropSet
.GetAnyProperty( aRelSizeAny
, EXC_CHPROP_RELATIVESIZE
);
2281 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2282 rPropSet
.GetProperty( eApiExpand
, EXC_CHPROP_EXPANSION
);
2283 if( aRelPosAny
.has
< RelativePosition
>() || ((eApiExpand
== cssc::ChartLegendExpansion_CUSTOM
) && aRelSizeAny
.has
< RelativeSize
>()) )
2287 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2288 indicator of manually changed legend position/size, but due to
2289 the different anchor modes used by this property (in the
2290 RelativePosition.Anchor member) it cannot be used to calculate
2291 the position easily. For this, the Chart1 API will be used
2293 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
2294 Reference
< XShape
> xChart1Legend( xChart1Doc
->getLegend(), UNO_SET_THROW
);
2295 // coordinates in CHLEGEND record written but not used by Excel
2296 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE
);
2297 XclChFramePos
& rFramePos
= mxFramePos
->GetFramePosData();
2298 rFramePos
.mnTLMode
= EXC_CHFRAMEPOS_CHARTSIZE
;
2299 css::awt::Point aLegendPos
= xChart1Legend
->getPosition();
2300 rFramePos
.maRect
.mnX
= maData
.maRect
.mnX
= CalcChartXFromHmm( aLegendPos
.X
);
2301 rFramePos
.maRect
.mnY
= maData
.maRect
.mnY
= CalcChartYFromHmm( aLegendPos
.Y
);
2302 // legend size, Excel expects points in CHFRAMEPOS record
2303 rFramePos
.mnBRMode
= EXC_CHFRAMEPOS_ABSSIZE_POINTS
;
2304 css::awt::Size aLegendSize
= xChart1Legend
->getSize();
2305 rFramePos
.maRect
.mnWidth
= o3tl::convert(aLegendSize
.Width
, o3tl::Length::mm100
, o3tl::Length::pt
);
2306 rFramePos
.maRect
.mnHeight
= o3tl::convert(aLegendSize
.Height
, o3tl::Length::mm100
, o3tl::Length::pt
);
2307 maData
.maRect
.mnWidth
= CalcChartXFromHmm( aLegendSize
.Width
);
2308 maData
.maRect
.mnHeight
= CalcChartYFromHmm( aLegendSize
.Height
);
2309 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2310 // manual legend position implies manual plot area
2311 GetChartData().SetManualPlotArea();
2312 maData
.mnDockMode
= EXC_CHLEGEND_NOTDOCKED
;
2313 // a CHFRAME record with cleared auto flags is needed
2315 mxFrame
= new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND
);
2316 mxFrame
->SetAutoFlags( false, false );
2320 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
2321 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2322 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2327 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_LINE_END
;
2328 rPropSet
.GetProperty( eApiPos
, EXC_CHPROP_ANCHORPOSITION
);
2331 case cssc2::LegendPosition_LINE_START
: maData
.mnDockMode
= EXC_CHLEGEND_LEFT
; break;
2332 case cssc2::LegendPosition_LINE_END
: maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
; break;
2333 case cssc2::LegendPosition_PAGE_START
: maData
.mnDockMode
= EXC_CHLEGEND_TOP
; break;
2334 case cssc2::LegendPosition_PAGE_END
: maData
.mnDockMode
= EXC_CHLEGEND_BOTTOM
; break;
2336 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
2337 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2338 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2341 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_STACKED
, eApiExpand
== cssc::ChartLegendExpansion_HIGH
);
2344 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_AUTOSERIES
);
2345 const sal_uInt16 nAutoFlags
= EXC_CHLEGEND_DOCKED
| EXC_CHLEGEND_AUTOPOSX
| EXC_CHLEGEND_AUTOPOSY
;
2346 ::set_flag( maData
.mnFlags
, nAutoFlags
, maData
.mnDockMode
!= EXC_CHLEGEND_NOTDOCKED
);
2349 void XclExpChLegend::WriteSubRecords( XclExpStream
& rStrm
)
2351 lclSaveRecord( rStrm
, mxFramePos
);
2352 lclSaveRecord( rStrm
, mxText
);
2353 lclSaveRecord( rStrm
, mxFrame
);
2356 void XclExpChLegend::WriteBody( XclExpStream
& rStrm
)
2358 rStrm
<< maData
.maRect
<< maData
.mnDockMode
<< maData
.mnSpacing
<< maData
.mnFlags
;
2361 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
2362 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DROPBAR
, EXC_ID_CHDROPBAR
, 2 ),
2363 meObjType( eObjType
)
2367 void XclExpChDropBar::Convert( const ScfPropertySet
& rPropSet
)
2370 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
2372 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, true );
2375 void XclExpChDropBar::WriteSubRecords( XclExpStream
& rStrm
)
2377 WriteFrameRecords( rStrm
);
2380 void XclExpChDropBar::WriteBody( XclExpStream
& rStrm
)
2382 rStrm
<< sal_uInt16(100); // Distance between bars (CHDROPBAR record).
2385 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot
& rRoot
, sal_uInt16 nGroupIdx
) :
2386 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TYPEGROUP
, EXC_ID_CHTYPEGROUP
, 20 ),
2388 maTypeInfo( maType
.GetTypeInfo() )
2390 maData
.mnGroupIdx
= nGroupIdx
;
2393 void XclExpChTypeGroup::ConvertType(
2394 Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2395 sal_Int32 nApiAxesSetIdx
, bool b3dChart
, bool bSwappedAxesSet
, bool bHasXLabels
)
2397 // chart type settings
2398 maType
.Convert( xDiagram
, xChartType
, nApiAxesSetIdx
, bSwappedAxesSet
, bHasXLabels
);
2400 // spline - TODO: get from single series (#i66858#)
2401 ScfPropertySet
aTypeProp( xChartType
);
2402 cssc2::CurveStyle eCurveStyle
;
2403 bool bSpline
= aTypeProp
.GetProperty( eCurveStyle
, EXC_CHPROP_CURVESTYLE
) &&
2404 (eCurveStyle
!= cssc2::CurveStyle_LINES
);
2406 // extended type info
2407 maTypeInfo
.Set( maType
.GetTypeInfo(), b3dChart
, bSpline
);
2409 // 3d chart settings
2410 if( maTypeInfo
.mb3dChart
) // only true, if Excel chart supports 3d mode
2412 mxChart3d
= new XclExpChChart3d();
2413 ScfPropertySet
aDiaProp( xDiagram
);
2414 mxChart3d
->Convert( aDiaProp
, Is3dWallChart() );
2418 void XclExpChTypeGroup::ConvertSeries(
2419 Reference
< XDiagram
> const & xDiagram
, Reference
< XChartType
> const & xChartType
,
2420 sal_Int32 nGroupAxesSetIdx
, bool bPercent
, bool bConnectBars
)
2422 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2423 if( !xSeriesCont
.is() )
2426 std::vector
< Reference
< XDataSeries
> > aSeriesVec
;
2428 // copy data series attached to the current axes set to the vector
2429 const Sequence
< Reference
< XDataSeries
> > aSeriesSeq
= xSeriesCont
->getDataSeries();
2430 for( const Reference
< XDataSeries
>& rSeries
: aSeriesSeq
)
2432 ScfPropertySet
aSeriesProp( rSeries
);
2433 sal_Int32
nSeriesAxesSetIdx(0);
2434 if( aSeriesProp
.GetProperty( nSeriesAxesSetIdx
, EXC_CHPROP_ATTAXISINDEX
) && (nSeriesAxesSetIdx
== nGroupAxesSetIdx
) )
2435 aSeriesVec
.push_back( rSeries
);
2438 // Are there any series in the current axes set?
2439 if( aSeriesVec
.empty() )
2442 // stacking direction (stacked/percent/deep 3d) from first series
2443 ScfPropertySet
aSeriesProp( aSeriesVec
.front() );
2444 cssc2::StackingDirection eStacking
;
2445 if( !aSeriesProp
.GetProperty( eStacking
, EXC_CHPROP_STACKINGDIR
) )
2446 eStacking
= cssc2::StackingDirection_NO_STACKING
;
2448 // stacked or percent chart
2449 if( maTypeInfo
.mbSupportsStacking
&& (eStacking
== cssc2::StackingDirection_Y_STACKING
) )
2451 // percent overrides simple stacking
2452 maType
.SetStacked( bPercent
);
2454 // connected data points (only in stacked bar charts)
2455 if (bConnectBars
&& (maTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
))
2457 sal_uInt16 nKey
= EXC_CHCHARTLINE_CONNECT
;
2458 m_ChartLines
.insert(std::make_pair(nKey
, std::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2463 // reverse series order for some unstacked 2D chart types
2464 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() )
2465 ::std::reverse( aSeriesVec
.begin(), aSeriesVec
.end() );
2468 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2469 if( (eStacking
== cssc2::StackingDirection_NO_STACKING
) && Is3dWallChart() )
2470 mxChart3d
->SetClustered();
2472 // varied point colors
2473 ::set_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
, aSeriesProp
.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY
) );
2475 // process all series
2476 for( const auto& rxSeries
: aSeriesVec
)
2478 // create Excel series object, stock charts need special processing
2479 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2480 CreateAllStockSeries( xChartType
, rxSeries
);
2482 CreateDataSeries( xDiagram
, rxSeries
);
2486 void XclExpChTypeGroup::ConvertCategSequence( Reference
< XLabeledDataSequence
> const & xCategSeq
)
2488 for( size_t nIdx
= 0, nSize
= maSeries
.GetSize(); nIdx
< nSize
; ++nIdx
)
2489 maSeries
.GetRecord( nIdx
)->ConvertCategSequence( xCategSeq
);
2492 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet
& rPropSet
)
2494 if( rPropSet
.GetBoolProperty( EXC_CHPROP_SHOW
) )
2496 mxLegend
= new XclExpChLegend( GetChRoot() );
2497 mxLegend
->Convert( rPropSet
);
2501 void XclExpChTypeGroup::WriteSubRecords( XclExpStream
& rStrm
)
2503 maType
.Save( rStrm
);
2504 lclSaveRecord( rStrm
, mxChart3d
);
2505 lclSaveRecord( rStrm
, mxLegend
);
2506 lclSaveRecord( rStrm
, mxUpBar
);
2507 lclSaveRecord( rStrm
, mxDownBar
);
2508 for (auto const& it
: m_ChartLines
)
2510 lclSaveRecord( rStrm
, it
.second
.get(), EXC_ID_CHCHARTLINE
, it
.first
);
2514 sal_uInt16
XclExpChTypeGroup::GetFreeFormatIdx() const
2516 return static_cast< sal_uInt16
>( maSeries
.GetSize() );
2519 void XclExpChTypeGroup::CreateDataSeries(
2520 Reference
< XDiagram
> const & xDiagram
, Reference
< XDataSeries
> const & xDataSeries
)
2522 // let chart create series object with correct series index
2523 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2526 if( xSeries
->ConvertDataSeries( xDiagram
, xDataSeries
, maTypeInfo
, GetGroupIdx(), GetFreeFormatIdx() ) )
2527 maSeries
.AppendRecord( xSeries
);
2529 GetChartData().RemoveLastSeries();
2533 void XclExpChTypeGroup::CreateAllStockSeries(
2534 Reference
< XChartType
> const & xChartType
, Reference
< XDataSeries
> const & xDataSeries
)
2536 // create existing series objects
2537 bool bHasOpen
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_OPENVALUES
, false );
2538 bool bHasHigh
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_HIGHVALUES
, false );
2539 bool bHasLow
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_LOWVALUES
, false );
2540 bool bHasClose
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_CLOSEVALUES
, !bHasOpen
);
2542 // formatting of special stock chart elements
2543 ScfPropertySet
aTypeProp( xChartType
);
2545 if( bHasHigh
&& bHasLow
&& aTypeProp
.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
) )
2547 ScfPropertySet
aSeriesProp( xDataSeries
);
2548 XclExpChLineFormatRef xLineFmt
= new XclExpChLineFormat( GetChRoot() );
2549 xLineFmt
->Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2550 sal_uInt16 nKey
= EXC_CHCHARTLINE_HILO
;
2551 m_ChartLines
.insert(std::make_pair(nKey
, std::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2554 if( !(bHasOpen
&& bHasClose
) )
2557 // dropbar type is dependent on position in the file - always create both
2558 Reference
< XPropertySet
> xWhitePropSet
, xBlackPropSet
;
2559 // white dropbar format
2560 aTypeProp
.GetProperty( xWhitePropSet
, EXC_CHPROP_WHITEDAY
);
2561 ScfPropertySet
aWhiteProp( xWhitePropSet
);
2562 mxUpBar
= new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR
);
2563 mxUpBar
->Convert( aWhiteProp
);
2564 // black dropbar format
2565 aTypeProp
.GetProperty( xBlackPropSet
, EXC_CHPROP_BLACKDAY
);
2566 ScfPropertySet
aBlackProp( xBlackPropSet
);
2567 mxDownBar
= new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR
);
2568 mxDownBar
->Convert( aBlackProp
);
2571 bool XclExpChTypeGroup::CreateStockSeries( Reference
< XDataSeries
> const & xDataSeries
,
2572 std::u16string_view rValueRole
, bool bCloseSymbol
)
2575 // let chart create series object with correct series index
2576 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2579 bOk
= xSeries
->ConvertStockSeries( xDataSeries
,
2580 rValueRole
, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol
);
2582 maSeries
.AppendRecord( xSeries
);
2584 GetChartData().RemoveLastSeries();
2589 void XclExpChTypeGroup::WriteBody( XclExpStream
& rStrm
)
2591 rStrm
.WriteZeroBytes( 16 );
2592 rStrm
<< maData
.mnFlags
<< maData
.mnGroupIdx
;
2595 // Axes =======================================================================
2597 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot
& rRoot
) :
2598 XclExpRecord( EXC_ID_CHLABELRANGE
, 8 ),
2599 XclExpChRoot( rRoot
)
2603 void XclExpChLabelRange::Convert( const ScaleData
& rScaleData
, const ScfPropertySet
& rChart1Axis
, bool bMirrorOrient
)
2605 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2606 chart API allows to detect axis type (date axis, if property exists),
2607 and to receive the base time unit currently used in case the base time
2608 unit is set to 'automatic'. */
2609 cssc::TimeIncrement aTimeIncrement
;
2610 if( rChart1Axis
.GetProperty( aTimeIncrement
, EXC_CHPROP_EXPTIMEINCREMENT
) )
2612 // property exists -> this is a date axis currently
2613 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2615 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2616 bool bAutoBase
= !rScaleData
.TimeIncrement
.TimeResolution
.has
< cssc::TimeIncrement
>();
2617 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
, bAutoBase
);
2619 // ...but get the current base time unit from the property of the old chart API
2620 sal_Int32 nApiTimeUnit
= 0;
2621 bool bValidBaseUnit
= aTimeIncrement
.TimeResolution
>>= nApiTimeUnit
;
2622 OSL_ENSURE( bValidBaseUnit
, "XclExpChLabelRange::Convert - cannot get base time unit" );
2623 maDateData
.mnBaseUnit
= bValidBaseUnit
? lclGetTimeUnit( nApiTimeUnit
) : EXC_CHDATERANGE_DAYS
;
2625 /* Min/max values depend on base time unit, they specify the number of
2626 days, months, or years starting from null date. */
2627 bool bAutoMin
= lclConvertTimeValue( GetRoot(), maDateData
.mnMinDate
, rScaleData
.Minimum
, maDateData
.mnBaseUnit
);
2628 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
, bAutoMin
);
2629 bool bAutoMax
= lclConvertTimeValue( GetRoot(), maDateData
.mnMaxDate
, rScaleData
.Maximum
, maDateData
.mnBaseUnit
);
2630 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
, bAutoMax
);
2633 // automatic axis type detection
2634 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
, rScaleData
.AutoDateAxis
);
2637 bool bAutoMajor
= lclConvertTimeInterval( maDateData
.mnMajorStep
, maDateData
.mnMajorUnit
, rScaleData
.TimeIncrement
.MajorTimeInterval
);
2638 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
, bAutoMajor
);
2639 bool bAutoMinor
= lclConvertTimeInterval( maDateData
.mnMinorStep
, maDateData
.mnMinorUnit
, rScaleData
.TimeIncrement
.MinorTimeInterval
);
2640 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
, bAutoMinor
);
2643 double fOrigin
= 0.0;
2644 if( !lclIsAutoAnyOrGetValue( fOrigin
, rScaleData
.Origin
) )
2645 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fOrigin
, 1, 31999 );
2648 if( (rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
) != bMirrorOrient
)
2649 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
);
2652 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2654 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2655 rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
);
2656 double fCrossingPos
= 1.0;
2657 rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
);
2659 bool bDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2662 case cssc::ChartAxisPosition_ZERO
:
2663 case cssc::ChartAxisPosition_START
:
2664 maLabelData
.mnCross
= 1;
2665 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2667 case cssc::ChartAxisPosition_END
:
2668 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_MAXCROSS
);
2670 case cssc::ChartAxisPosition_VALUE
:
2671 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fCrossingPos
, 1, 31999 );
2672 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
, false );
2674 maDateData
.mnCross
= lclGetTimeValue( GetRoot(), fCrossingPos
, maDateData
.mnBaseUnit
);
2677 maLabelData
.mnCross
= 1;
2678 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2682 void XclExpChLabelRange::Save( XclExpStream
& rStrm
)
2684 // the CHLABELRANGE record
2685 XclExpRecord::Save( rStrm
);
2687 // the CHDATERANGE record with date axis settings (BIFF8 only)
2688 if( GetBiff() != EXC_BIFF8
)
2691 rStrm
.StartRecord( EXC_ID_CHDATERANGE
, 18 );
2692 rStrm
<< maDateData
.mnMinDate
2693 << maDateData
.mnMaxDate
2694 << maDateData
.mnMajorStep
2695 << maDateData
.mnMajorUnit
2696 << maDateData
.mnMinorStep
2697 << maDateData
.mnMinorUnit
2698 << maDateData
.mnBaseUnit
2699 << maDateData
.mnCross
2700 << maDateData
.mnFlags
;
2704 void XclExpChLabelRange::WriteBody( XclExpStream
& rStrm
)
2706 rStrm
<< maLabelData
.mnCross
<< maLabelData
.mnLabelFreq
<< maLabelData
.mnTickFreq
<< maLabelData
.mnFlags
;
2709 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot
& rRoot
) :
2710 XclExpRecord( EXC_ID_CHVALUERANGE
, 42 ),
2711 XclExpChRoot( rRoot
)
2715 void XclExpChValueRange::Convert( const ScaleData
& rScaleData
)
2717 // scaling algorithm
2718 bool bLogScale
= ScfApiHelper::GetServiceName( rScaleData
.Scaling
) == "com.sun.star.chart2.LogarithmicScaling";
2719 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, bLogScale
);
2722 bool bAutoMin
= lclIsAutoAnyOrGetScaledValue( maData
.mfMin
, rScaleData
.Minimum
, bLogScale
);
2723 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
, bAutoMin
);
2724 bool bAutoMax
= lclIsAutoAnyOrGetScaledValue( maData
.mfMax
, rScaleData
.Maximum
, bLogScale
);
2725 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
, bAutoMax
);
2728 bool bAutoCross
= lclIsAutoAnyOrGetScaledValue( maData
.mfCross
, rScaleData
.Origin
, bLogScale
);
2729 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, bAutoCross
);
2732 const IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
2733 const bool bAutoMajor
= lclIsAutoAnyOrGetValue( maData
.mfMajorStep
, rIncrementData
.Distance
) || (maData
.mfMajorStep
<= 0.0);
2734 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
, bAutoMajor
);
2736 const Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
2737 sal_Int32 nCount
= 0;
2739 // tdf#114168 If IntervalCount is 5, then enable automatic minor calculation.
2740 // During import, if minorUnit is set and majorUnit not, then it is impossible
2741 // to calculate IntervalCount.
2742 const bool bAutoMinor
= bLogScale
|| bAutoMajor
|| !rSubIncrementSeq
.hasElements() ||
2743 lclIsAutoAnyOrGetValue( nCount
, rSubIncrementSeq
[ 0 ].IntervalCount
) || (nCount
< 1) || (nCount
== 5);
2745 if( maData
.mfMajorStep
&& !bAutoMinor
)
2746 maData
.mfMinorStep
= maData
.mfMajorStep
/ nCount
;
2747 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
, bAutoMinor
);
2750 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
, rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
);
2753 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2755 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2756 double fCrossingPos
= 0.0;
2757 if( !(rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
) && rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
)) )
2762 case cssc::ChartAxisPosition_ZERO
:
2763 case cssc::ChartAxisPosition_START
:
2764 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2766 case cssc::ChartAxisPosition_END
:
2767 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
2769 case cssc::ChartAxisPosition_VALUE
:
2770 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, false );
2771 maData
.mfCross
= ::get_flagvalue
< double >( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, log( fCrossingPos
) / log( 10.0 ), fCrossingPos
);
2774 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2778 void XclExpChValueRange::WriteBody( XclExpStream
& rStrm
)
2780 rStrm
<< maData
.mfMin
2782 << maData
.mfMajorStep
2783 << maData
.mfMinorStep
2790 sal_uInt8
lclGetXclTickPos( sal_Int32 nApiTickmarks
)
2792 using namespace cssc2::TickmarkStyle
;
2793 sal_uInt8 nXclTickPos
= 0;
2794 ::set_flag( nXclTickPos
, EXC_CHTICK_INSIDE
, ::get_flag( nApiTickmarks
, INNER
) );
2795 ::set_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
, ::get_flag( nApiTickmarks
, OUTER
) );
2801 XclExpChTick::XclExpChTick( const XclExpChRoot
& rRoot
) :
2802 XclExpRecord( EXC_ID_CHTICK
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 30 : 26 ),
2803 XclExpChRoot( rRoot
),
2804 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
2808 void XclExpChTick::Convert( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nAxisType
)
2811 sal_Int32 nApiTickmarks
= 0;
2812 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MAJORTICKS
) )
2813 maData
.mnMajor
= lclGetXclTickPos( nApiTickmarks
);
2814 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MINORTICKS
) )
2815 maData
.mnMinor
= lclGetXclTickPos( nApiTickmarks
);
2818 if( (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) && (nAxisType
== EXC_CHAXIS_X
) )
2820 /* Radar charts disable their category labels via chart type, not via
2821 axis, and axis labels are always 'near axis'. */
2822 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2824 else if( !rPropSet
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
) )
2827 maData
.mnLabelPos
= EXC_CHTICK_NOLABEL
;
2829 else if( rTypeInfo
.mb3dChart
&& (nAxisType
== EXC_CHAXIS_Y
) )
2831 // Excel expects 'near axis' at Y axes in 3D charts
2832 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2836 cssc::ChartAxisLabelPosition eApiLabelPos
= cssc::ChartAxisLabelPosition_NEAR_AXIS
;
2837 rPropSet
.GetProperty( eApiLabelPos
, EXC_CHPROP_LABELPOSITION
);
2838 switch( eApiLabelPos
)
2840 case cssc::ChartAxisLabelPosition_NEAR_AXIS
:
2841 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
: maData
.mnLabelPos
= EXC_CHTICK_NEXT
; break;
2842 case cssc::ChartAxisLabelPosition_OUTSIDE_START
: maData
.mnLabelPos
= EXC_CHTICK_LOW
; break;
2843 case cssc::ChartAxisLabelPosition_OUTSIDE_END
: maData
.mnLabelPos
= EXC_CHTICK_HIGH
; break;
2844 default: maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2849 void XclExpChTick::SetFontColor( const Color
& rColor
, sal_uInt32 nColorId
)
2851 maData
.maTextColor
= rColor
;
2852 ::set_flag( maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
, rColor
== COL_AUTO
);
2853 mnTextColorId
= nColorId
;
2856 void XclExpChTick::SetRotation( sal_uInt16 nRotation
)
2858 maData
.mnRotation
= nRotation
;
2859 ::set_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
, false );
2860 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 2, 3 );
2863 void XclExpChTick::WriteBody( XclExpStream
& rStrm
)
2865 rStrm
<< maData
.mnMajor
2867 << maData
.mnLabelPos
2868 << maData
.mnBackMode
;
2869 rStrm
.WriteZeroBytes( 16 );
2870 rStrm
<< maData
.maTextColor
2872 if( GetBiff() == EXC_BIFF8
)
2873 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
) << maData
.mnRotation
;
2878 /** Returns an API axis object from the passed coordinate system. */
2879 Reference
< XAxis
> lclGetApiAxis( Reference
< XCoordinateSystem
> const & xCoordSystem
,
2880 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2882 Reference
< XAxis
> xAxis
;
2883 if( (nApiAxisDim
>= 0) && xCoordSystem
.is() ) try
2885 xAxis
= xCoordSystem
->getAxisByDimension( nApiAxisDim
, nApiAxesSetIdx
);
2893 Reference
< cssc::XAxis
> lclGetApiChart1Axis( Reference
< XChartDocument
> const & xChartDoc
,
2894 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2896 Reference
< cssc::XAxis
> xChart1Axis
;
2899 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY_THROW
);
2900 Reference
< cssc::XAxisSupplier
> xChart1AxisSupp( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
2901 switch( nApiAxesSetIdx
)
2903 case EXC_CHART_AXESSET_PRIMARY
:
2904 xChart1Axis
= xChart1AxisSupp
->getAxis( nApiAxisDim
);
2906 case EXC_CHART_AXESSET_SECONDARY
:
2907 xChart1Axis
= xChart1AxisSupp
->getSecondaryAxis( nApiAxisDim
);
2919 XclExpChAxis::XclExpChAxis( const XclExpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
2920 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXIS
, EXC_ID_CHAXIS
, 18 ),
2921 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
2923 maData
.mnType
= nAxisType
;
2926 void XclExpChAxis::SetFont( XclExpChFontRef xFont
, const Color
& rColor
, sal_uInt32 nColorId
)
2930 mxTick
->SetFontColor( rColor
, nColorId
);
2933 void XclExpChAxis::SetRotation( sal_uInt16 nRotation
)
2936 mxTick
->SetRotation( nRotation
);
2939 void XclExpChAxis::Convert( Reference
< XAxis
> const & xAxis
, Reference
< XAxis
> const & xCrossingAxis
,
2940 Reference
< cssc::XAxis
> const & xChart1Axis
, const XclChExtTypeInfo
& rTypeInfo
)
2942 ScfPropertySet
aAxisProp( xAxis
);
2943 bool bCategoryAxis
= ((GetAxisType() == EXC_CHAXIS_X
) && rTypeInfo
.mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
);
2945 // axis line format -------------------------------------------------------
2947 mxAxisLine
= new XclExpChLineFormat( GetChRoot() );
2948 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
2949 // #i58688# axis enabled
2950 mxAxisLine
->SetShowAxis( aAxisProp
.GetBoolProperty( EXC_CHPROP_SHOW
) );
2952 // axis scaling and increment ---------------------------------------------
2954 ScfPropertySet
aCrossingProp( xCrossingAxis
);
2957 mxLabelRange
= new XclExpChLabelRange( GetChRoot() );
2958 mxLabelRange
->SetTicksBetweenCateg( rTypeInfo
.mbTicksBetweenCateg
);
2961 ScfPropertySet
aChart1AxisProp( xChart1Axis
);
2962 // #i71684# radar charts have reversed rotation direction
2963 mxLabelRange
->Convert( xAxis
->getScaleData(), aChart1AxisProp
, (GetAxisType() == EXC_CHAXIS_X
) && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) );
2965 // get position of crossing axis on this axis from passed axis object
2966 if( aCrossingProp
.Is() )
2967 mxLabelRange
->ConvertAxisPosition( aCrossingProp
);
2971 mxValueRange
= new XclExpChValueRange( GetChRoot() );
2973 mxValueRange
->Convert( xAxis
->getScaleData() );
2974 // get position of crossing axis on this axis from passed axis object
2975 if( aCrossingProp
.Is() )
2976 mxValueRange
->ConvertAxisPosition( aCrossingProp
);
2979 // axis caption text ------------------------------------------------------
2981 // axis ticks properties
2982 mxTick
= new XclExpChTick( GetChRoot() );
2983 mxTick
->Convert( aAxisProp
, rTypeInfo
, GetAxisType() );
2985 // axis label formatting and rotation
2986 ConvertFontBase( GetChRoot(), aAxisProp
);
2987 ConvertRotationBase( aAxisProp
, true );
2989 // axis number format
2990 sal_Int32 nApiNumFmt
= 0;
2991 if( !bCategoryAxis
&& aAxisProp
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
2993 bool bLinkNumberFmtToSource
= false;
2994 if ( !aAxisProp
.GetProperty( bLinkNumberFmtToSource
, EXC_CHPROP_NUMBERFORMAT_LINKSRC
) || !bLinkNumberFmtToSource
)
2995 mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
2998 // grid -------------------------------------------------------------------
3004 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3005 if( aGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3006 mxMajorGrid
= lclCreateLineFormat( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3008 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3009 if( aSubGridPropSeq
.hasElements() )
3011 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3012 if( aSubGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3013 mxMinorGrid
= lclCreateLineFormat( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3017 void XclExpChAxis::ConvertWall( css::uno::Reference
< css::chart2::XDiagram
> const & xDiagram
)
3019 if( !xDiagram
.is() )
3022 switch( GetAxisType() )
3026 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3027 mxWallFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_WALL3D
);
3032 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3033 mxWallFrame
= lclCreateFrame( GetChRoot(), aFloorProp
, EXC_CHOBJTYPE_FLOOR3D
);
3037 mxWallFrame
.clear();
3041 void XclExpChAxis::WriteSubRecords( XclExpStream
& rStrm
)
3043 lclSaveRecord( rStrm
, mxLabelRange
);
3044 lclSaveRecord( rStrm
, mxValueRange
);
3045 if( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3046 XclExpUInt16Record( EXC_ID_CHFORMAT
, mnNumFmtIdx
).Save( rStrm
);
3047 lclSaveRecord( rStrm
, mxTick
);
3048 lclSaveRecord( rStrm
, mxFont
);
3049 lclSaveRecord( rStrm
, mxAxisLine
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_AXISLINE
);
3050 lclSaveRecord( rStrm
, mxMajorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MAJORGRID
);
3051 lclSaveRecord( rStrm
, mxMinorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MINORGRID
);
3052 lclSaveRecord( rStrm
, mxWallFrame
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_WALLS
);
3055 void XclExpChAxis::WriteBody( XclExpStream
& rStrm
)
3057 rStrm
<< maData
.mnType
;
3058 rStrm
.WriteZeroBytes( 16 );
3061 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3062 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXESSET
, EXC_ID_CHAXESSET
, 18 )
3064 maData
.mnAxesSetId
= nAxesSetId
;
3065 SetFutureRecordContext( 0, nAxesSetId
);
3067 /* Need to set a reasonable size for the plot area, otherwise Excel will
3068 move away embedded shapes while auto-sizing the plot area. This is just
3069 a wild guess, but will be fixed with implementing manual positioning of
3071 maData
.maRect
.mnX
= 262;
3072 maData
.maRect
.mnY
= 626;
3073 maData
.maRect
.mnWidth
= 3187;
3074 maData
.maRect
.mnHeight
= 2633;
3077 sal_uInt16
XclExpChAxesSet::Convert( Reference
< XDiagram
> const & xDiagram
, sal_uInt16 nFirstGroupIdx
)
3079 /* First unused chart type group index is passed to be able to continue
3080 counting of chart type groups for secondary axes set. */
3081 sal_uInt16 nGroupIdx
= nFirstGroupIdx
;
3082 Reference
< XCoordinateSystemContainer
> xCoordSysCont( xDiagram
, UNO_QUERY
);
3083 if( xCoordSysCont
.is() )
3085 Sequence
< Reference
< XCoordinateSystem
> > aCoordSysSeq
= xCoordSysCont
->getCoordinateSystems();
3086 if( aCoordSysSeq
.hasElements() )
3088 /* Process first coordinate system only. Import filter puts all
3089 chart types into one coordinate system. */
3090 Reference
< XCoordinateSystem
> xCoordSystem
= aCoordSysSeq
[ 0 ];
3091 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3094 bool b3dChart
= xCoordSystem
.is() && (xCoordSystem
->getDimension() == 3);
3097 namespace ApiAxisType
= cssc2::AxisType
;
3098 Reference
< XAxis
> xApiYAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_Y
, nApiAxesSetIdx
);
3099 bool bPercent
= xApiYAxis
.is() && (xApiYAxis
->getScaleData().AxisType
== ApiAxisType::PERCENT
);
3101 // connector lines in bar charts
3102 ScfPropertySet
aDiaProp( xDiagram
);
3103 bool bConnectBars
= aDiaProp
.GetBoolProperty( EXC_CHPROP_CONNECTBARS
);
3105 // swapped axes sets
3106 ScfPropertySet
aCoordSysProp( xCoordSystem
);
3107 bool bSwappedAxesSet
= aCoordSysProp
.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
);
3109 // X axis for later use
3110 Reference
< XAxis
> xApiXAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_X
, nApiAxesSetIdx
);
3112 ScfPropertySet
aXAxisProp( xApiXAxis
);
3113 bool bHasXLabels
= aXAxisProp
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
);
3115 // process chart types
3116 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3117 if( xChartTypeCont
.is() )
3119 const Sequence
< Reference
< XChartType
> > aChartTypeSeq
= xChartTypeCont
->getChartTypes();
3120 for( const Reference
< XChartType
>& rChartType
: aChartTypeSeq
)
3122 XclExpChTypeGroupRef xTypeGroup
= new XclExpChTypeGroup( GetChRoot(), nGroupIdx
);
3123 xTypeGroup
->ConvertType( xDiagram
, rChartType
, nApiAxesSetIdx
, b3dChart
, bSwappedAxesSet
, bHasXLabels
);
3124 /* If new chart type group cannot be inserted into a combination
3125 chart with existing type groups, insert all series into last
3126 contained chart type group instead of creating a new group. */
3127 XclExpChTypeGroupRef xLastGroup
= GetLastTypeGroup();
3128 if( xLastGroup
&& !(xTypeGroup
->IsCombinable2d() && xLastGroup
->IsCombinable2d()) )
3130 xLastGroup
->ConvertSeries( xDiagram
, rChartType
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3134 xTypeGroup
->ConvertSeries( xDiagram
, rChartType
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3135 if( xTypeGroup
->IsValidGroup() )
3137 maTypeGroups
.AppendRecord( xTypeGroup
);
3144 if( XclExpChTypeGroup
* pGroup
= GetFirstTypeGroup().get() )
3146 const XclChExtTypeInfo
& rTypeInfo
= pGroup
->GetTypeInfo();
3148 // create axes according to chart type (no axes for pie and donut charts)
3149 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
3151 ConvertAxis( mxXAxis
, EXC_CHAXIS_X
, mxXAxisTitle
, EXC_CHOBJLINK_XAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_Y
);
3152 ConvertAxis( mxYAxis
, EXC_CHAXIS_Y
, mxYAxisTitle
, EXC_CHOBJLINK_YAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_X
);
3153 if( pGroup
->Is3dDeepChart() )
3154 ConvertAxis( mxZAxis
, EXC_CHAXIS_Z
, mxZAxisTitle
, EXC_CHOBJLINK_ZAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_NONE
);
3157 // X axis category ranges
3158 if( rTypeInfo
.mbCategoryAxis
&& xApiXAxis
.is() )
3160 const ScaleData aScaleData
= xApiXAxis
->getScaleData();
3161 for( size_t nIdx
= 0, nSize
= maTypeGroups
.GetSize(); nIdx
< nSize
; ++nIdx
)
3162 maTypeGroups
.GetRecord( nIdx
)->ConvertCategSequence( aScaleData
.Categories
);
3166 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3168 Reference
< XLegend
> xLegend
= xDiagram
->getLegend();
3171 ScfPropertySet
aLegendProp( xLegend
);
3172 pGroup
->ConvertLegend( aLegendProp
);
3179 // wall/floor/diagram frame formatting
3180 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3182 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3183 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3185 // wall/floor formatting (3D charts)
3187 mxXAxis
->ConvertWall( xDiagram
);
3189 mxYAxis
->ConvertWall( xDiagram
);
3193 // diagram background formatting
3194 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3195 mxPlotFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_PLOTFRAME
);
3199 // inner and outer plot area position and size
3202 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
3203 Reference
< cssc::XDiagramPositioning
> xPositioning( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
3204 // set manual flag in chart data
3205 if( !xPositioning
->isAutomaticDiagramPositioning() )
3206 GetChartData().SetManualPlotArea();
3207 // the CHAXESSET record contains the inner plot area
3208 maData
.maRect
= CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionExcludingAxes() );
3209 // the embedded CHFRAMEPOS record contains the outer plot area
3210 mxFramePos
= new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
);
3211 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3212 const XclExpChTypeGroup
* pFirstTypeGroup
= GetFirstTypeGroup().get();
3213 bool bPieChart
= pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3214 mxFramePos
->GetFramePosData().maRect
= bPieChart
? maData
.maRect
:
3215 CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionIncludingAxes() );
3221 // return first unused chart type group index for next axes set
3225 bool XclExpChAxesSet::Is3dChart() const
3227 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3228 return xTypeGroup
&& xTypeGroup
->Is3dChart();
3231 void XclExpChAxesSet::WriteSubRecords( XclExpStream
& rStrm
)
3233 lclSaveRecord( rStrm
, mxFramePos
);
3234 lclSaveRecord( rStrm
, mxXAxis
);
3235 lclSaveRecord( rStrm
, mxYAxis
);
3236 lclSaveRecord( rStrm
, mxZAxis
);
3237 lclSaveRecord( rStrm
, mxXAxisTitle
);
3238 lclSaveRecord( rStrm
, mxYAxisTitle
);
3239 lclSaveRecord( rStrm
, mxZAxisTitle
);
3242 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME
).Save( rStrm
);
3243 mxPlotFrame
->Save( rStrm
);
3245 maTypeGroups
.Save( rStrm
);
3248 XclExpChTypeGroupRef
XclExpChAxesSet::GetFirstTypeGroup() const
3250 return maTypeGroups
.GetFirstRecord();
3253 XclExpChTypeGroupRef
XclExpChAxesSet::GetLastTypeGroup() const
3255 return maTypeGroups
.GetLastRecord();
3258 void XclExpChAxesSet::ConvertAxis(
3259 XclExpChAxisRef
& rxChAxis
, sal_uInt16 nAxisType
,
3260 XclExpChTextRef
& rxChAxisTitle
, sal_uInt16 nTitleTarget
,
3261 Reference
< XCoordinateSystem
> const & xCoordSystem
, const XclChExtTypeInfo
& rTypeInfo
,
3262 sal_Int32 nCrossingAxisDim
)
3264 // create and convert axis object
3265 rxChAxis
= new XclExpChAxis( GetChRoot(), nAxisType
);
3266 sal_Int32 nApiAxisDim
= rxChAxis
->GetApiAxisDimension();
3267 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3268 Reference
< XAxis
> xAxis
= lclGetApiAxis( xCoordSystem
, nApiAxisDim
, nApiAxesSetIdx
);
3269 Reference
< XAxis
> xCrossingAxis
= lclGetApiAxis( xCoordSystem
, nCrossingAxisDim
, nApiAxesSetIdx
);
3270 Reference
< cssc::XAxis
> xChart1Axis
= lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim
, nApiAxesSetIdx
);
3271 rxChAxis
->Convert( xAxis
, xCrossingAxis
, xChart1Axis
, rTypeInfo
);
3273 // create and convert axis title
3274 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY
);
3275 rxChAxisTitle
= lclCreateTitle( GetChRoot(), xTitled
, nTitleTarget
);
3278 void XclExpChAxesSet::WriteBody( XclExpStream
& rStrm
)
3280 rStrm
<< maData
.mnAxesSetId
<< maData
.maRect
;
3283 // The chart object ===========================================================
3285 static void lcl_getChartSubTitle(const Reference
<XChartDocument
>& xChartDoc
,
3286 OUString
& rSubTitle
)
3288 Reference
< css::chart::XChartDocument
> xChartDoc1(xChartDoc
, UNO_QUERY
);
3289 if (!xChartDoc1
.is())
3292 Reference
< XPropertySet
> xProp(xChartDoc1
->getSubTitle(), UNO_QUERY
);
3297 Any any
= xProp
->getPropertyValue("String");
3302 XclExpChChart::XclExpChChart( const XclExpRoot
& rRoot
,
3303 Reference
< XChartDocument
> const & xChartDoc
, const tools::Rectangle
& rChartRect
) :
3304 XclExpChGroupBase( XclExpChRoot( rRoot
, *this ), EXC_CHFRBLOCK_TYPE_CHART
, EXC_ID_CHCHART
, 16 )
3306 Size aPtSize
= OutputDevice::LogicToLogic( rChartRect
.GetSize(), MapMode( MapUnit::Map100thMM
), MapMode( MapUnit::MapPoint
) );
3307 // rectangle is stored in 16.16 fixed-point format
3308 maRect
.mnX
= maRect
.mnY
= 0;
3309 maRect
.mnWidth
= static_cast< sal_Int32
>( aPtSize
.Width() << 16 );
3310 maRect
.mnHeight
= static_cast< sal_Int32
>( aPtSize
.Height() << 16 );
3312 // global chart properties (default values)
3313 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, false );
3314 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_MANPLOTAREA
);
3315 maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
;
3317 // always create both axes set objects
3318 mxPrimAxesSet
= std::make_shared
<XclExpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_PRIMARY
);
3319 mxSecnAxesSet
= std::make_shared
<XclExpChAxesSet
>( GetChRoot(), EXC_CHAXESSET_SECONDARY
);
3321 if( !xChartDoc
.is() )
3324 Reference
< XDiagram
> xDiagram
= xChartDoc
->getFirstDiagram();
3326 // global chart properties (only 'include hidden cells' attribute for now)
3327 ScfPropertySet
aDiagramProp( xDiagram
);
3328 bool bIncludeHidden
= aDiagramProp
.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
);
3329 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, !bIncludeHidden
);
3331 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3332 InitConversion( xChartDoc
, rChartRect
);
3335 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3336 mxFrame
= lclCreateFrame( GetChRoot(), aFrameProp
, EXC_CHOBJTYPE_BACKGROUND
);
3339 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY
);
3341 lcl_getChartSubTitle(xChartDoc
, aSubTitle
);
3342 mxTitle
= lclCreateTitle( GetChRoot(), xTitled
, EXC_CHOBJLINK_TITLE
,
3343 !aSubTitle
.isEmpty() ? &aSubTitle
: nullptr );
3345 // diagrams (axes sets)
3346 sal_uInt16 nFreeGroupIdx
= mxPrimAxesSet
->Convert( xDiagram
, 0 );
3347 if( !mxPrimAxesSet
->Is3dChart() )
3348 mxSecnAxesSet
->Convert( xDiagram
, nFreeGroupIdx
);
3350 // treatment of missing values
3351 ScfPropertySet
aDiaProp( xDiagram
);
3352 sal_Int32 nMissingValues
= 0;
3353 if( aDiaProp
.GetProperty( nMissingValues
, EXC_CHPROP_MISSINGVALUETREATMENT
) )
3355 using namespace cssc::MissingValueTreatment
;
3356 switch( nMissingValues
)
3358 case LEAVE_GAP
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
; break;
3359 case USE_ZERO
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_ZERO
; break;
3360 case CONTINUE
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_INTERPOLATE
; break;
3364 // finish API conversion
3368 XclExpChSeriesRef
XclExpChChart::CreateSeries()
3370 XclExpChSeriesRef xSeries
;
3371 sal_uInt16 nSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.GetSize() );
3372 if( nSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3374 xSeries
= new XclExpChSeries( GetChRoot(), nSeriesIdx
);
3375 maSeries
.AppendRecord( xSeries
);
3380 void XclExpChChart::RemoveLastSeries()
3382 if( !maSeries
.IsEmpty() )
3383 maSeries
.RemoveRecord( maSeries
.GetSize() - 1 );
3386 void XclExpChChart::SetDataLabel( XclExpChTextRef
const & xText
)
3389 maLabels
.AppendRecord( xText
);
3392 void XclExpChChart::SetManualPlotArea()
3394 // this flag does not exist in BIFF5
3395 if( GetBiff() == EXC_BIFF8
)
3396 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3399 void XclExpChChart::WriteSubRecords( XclExpStream
& rStrm
)
3401 // background format
3402 lclSaveRecord( rStrm
, mxFrame
);
3405 maSeries
.Save( rStrm
);
3407 // CHPROPERTIES record
3408 rStrm
.StartRecord( EXC_ID_CHPROPERTIES
, 4 );
3409 rStrm
<< maProps
.mnFlags
<< maProps
.mnEmptyMode
<< sal_uInt8( 0 );
3412 // axes sets (always save primary axes set)
3413 sal_uInt16 nUsedAxesSets
= mxSecnAxesSet
->IsValidAxesSet() ? 2 : 1;
3414 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS
, nUsedAxesSets
).Save( rStrm
);
3415 mxPrimAxesSet
->Save( rStrm
);
3416 if( mxSecnAxesSet
->IsValidAxesSet() )
3417 mxSecnAxesSet
->Save( rStrm
);
3419 // chart title and data labels
3420 lclSaveRecord( rStrm
, mxTitle
);
3421 maLabels
.Save( rStrm
);
3424 void XclExpChChart::WriteBody( XclExpStream
& rStrm
)
3429 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot
& rRoot
,
3430 const Reference
< XModel
>& rxModel
, const Size
& rChartSize
) :
3433 if( rChartSize
.IsEmpty() )
3436 ScfPropertySet
aPropSet( rxModel
);
3437 Reference
< XShapes
> xShapes
;
3438 if( !(aPropSet
.GetProperty( xShapes
, EXC_CHPROP_ADDITIONALSHAPES
) && xShapes
.is() && (xShapes
->getCount() > 0)) )
3441 /* Create a new independent object manager with own DFF stream for the
3442 DGCONTAINER, pass global manager as parent for shared usage of
3443 global DFF data (picture container etc.). */
3444 mxObjMgr
= std::make_shared
<XclExpEmbeddedObjectManager
>( GetObjectManager(), rChartSize
, EXC_CHART_TOTALUNITS
, EXC_CHART_TOTALUNITS
);
3445 // initialize the drawing object list
3446 mxObjMgr
->StartSheet();
3447 // process the draw page (convert all shapes)
3448 mxObjRecs
= mxObjMgr
->ProcessDrawing( xShapes
);
3449 // finalize the DFF stream
3450 mxObjMgr
->EndDocument();
3453 XclExpChartDrawing::~XclExpChartDrawing()
3457 void XclExpChartDrawing::Save( XclExpStream
& rStrm
)
3460 mxObjRecs
->Save( rStrm
);
3463 XclExpChart::XclExpChart( const XclExpRoot
& rRoot
, Reference
< XModel
> const & xModel
, const tools::Rectangle
& rChartRect
) :
3464 XclExpSubStream( EXC_BOF_CHART
),
3467 AppendNewRecord( new XclExpChartPageSettings( rRoot
) );
3468 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT
, false ) );
3469 AppendNewRecord( new XclExpChartDrawing( rRoot
, xModel
, rChartRect
.GetSize() ) );
3470 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS
, EXC_CHUNITS_TWIPS
) );
3472 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
3473 AppendNewRecord( new XclExpChChart( rRoot
, xChartDoc
, rChartRect
) );
3476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */