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 <o3tl/make_unique.hxx>
58 #include <tools/gen.hxx>
59 #include <vcl/outdev.hxx>
60 #include <filter/msfilter/escherex.hxx>
62 #include "document.hxx"
63 #include "rangelst.hxx"
64 #include "rangeutl.hxx"
65 #include "compiler.hxx"
66 #include "tokenarray.hxx"
68 #include "xeescher.hxx"
69 #include "xeformula.hxx"
70 #include "xehelper.hxx"
72 #include "xestyle.hxx"
76 using ::com::sun::star::uno::Any
;
77 using ::com::sun::star::uno::Reference
;
78 using ::com::sun::star::uno::Sequence
;
79 using ::com::sun::star::uno::UNO_QUERY
;
80 using ::com::sun::star::uno::UNO_QUERY_THROW
;
81 using ::com::sun::star::uno::UNO_SET_THROW
;
82 using ::com::sun::star::uno::Exception
;
83 using ::com::sun::star::beans::XPropertySet
;
84 using ::com::sun::star::i18n::XBreakIterator
;
85 using ::com::sun::star::frame::XModel
;
86 using ::com::sun::star::drawing::XShape
;
87 using ::com::sun::star::drawing::XShapes
;
89 using ::com::sun::star::chart2::IncrementData
;
90 using ::com::sun::star::chart2::RelativePosition
;
91 using ::com::sun::star::chart2::RelativeSize
;
92 using ::com::sun::star::chart2::ScaleData
;
93 using ::com::sun::star::chart2::SubIncrement
;
94 using ::com::sun::star::chart2::XAxis
;
95 using ::com::sun::star::chart2::XChartDocument
;
96 using ::com::sun::star::chart2::XChartTypeContainer
;
97 using ::com::sun::star::chart2::XColorScheme
;
98 using ::com::sun::star::chart2::XCoordinateSystem
;
99 using ::com::sun::star::chart2::XCoordinateSystemContainer
;
100 using ::com::sun::star::chart2::XChartType
;
101 using ::com::sun::star::chart2::XDataSeries
;
102 using ::com::sun::star::chart2::XDataSeriesContainer
;
103 using ::com::sun::star::chart2::XDiagram
;
104 using ::com::sun::star::chart2::XFormattedString
;
105 using ::com::sun::star::chart2::XLegend
;
106 using ::com::sun::star::chart2::XRegressionCurve
;
107 using ::com::sun::star::chart2::XRegressionCurveContainer
;
108 using ::com::sun::star::chart2::XTitle
;
109 using ::com::sun::star::chart2::XTitled
;
111 using ::com::sun::star::chart2::data::XDataSequence
;
112 using ::com::sun::star::chart2::data::XDataSource
;
113 using ::com::sun::star::chart2::data::XLabeledDataSequence
;
115 using ::formula::FormulaToken
;
117 namespace cssc
= ::com::sun::star::chart
;
118 namespace cssc2
= ::com::sun::star::chart2
;
120 // Helpers ====================================================================
124 XclExpStream
& operator<<( XclExpStream
& rStrm
, const XclChRectangle
& rRect
)
126 return rStrm
<< rRect
.mnX
<< rRect
.mnY
<< rRect
.mnWidth
<< rRect
.mnHeight
;
129 inline void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef xRec
)
135 /** Saves the passed record (group) together with a leading value record. */
136 template< typename Type
>
137 void lclSaveRecord( XclExpStream
& rStrm
, XclExpRecordRef xRec
, sal_uInt16 nRecId
, Type nValue
)
141 XclExpValueRecord
< Type
>( nRecId
, nValue
).Save( rStrm
);
146 template<typename ValueType
, typename KeyType
>
147 void lclSaveRecord(XclExpStream
& rStrm
, ValueType
* pRec
, sal_uInt16 nRecId
, KeyType nValue
)
151 XclExpValueRecord
<KeyType
>(nRecId
, nValue
).Save(rStrm
);
156 void lclWriteChFrBlockRecord( XclExpStream
& rStrm
, const XclChFrBlock
& rFrBlock
, bool bBegin
)
158 sal_uInt16 nRecId
= bBegin
? EXC_ID_CHFRBLOCKBEGIN
: EXC_ID_CHFRBLOCKEND
;
159 rStrm
.StartRecord( nRecId
, 12 );
160 rStrm
<< nRecId
<< EXC_FUTUREREC_EMPTYFLAGS
<< rFrBlock
.mnType
<< rFrBlock
.mnContext
<< rFrBlock
.mnValue1
<< rFrBlock
.mnValue2
;
164 template< typename Type
>
165 inline bool lclIsAutoAnyOrGetValue( Type
& rValue
, const Any
& rAny
)
167 return !rAny
.hasValue() || !(rAny
>>= rValue
);
170 bool lclIsAutoAnyOrGetScaledValue( double& rfValue
, const Any
& rAny
, bool bLogScale
)
172 bool bIsAuto
= lclIsAutoAnyOrGetValue( rfValue
, rAny
);
173 if( !bIsAuto
&& bLogScale
)
174 rfValue
= log( rfValue
) / log( 10.0 );
178 sal_uInt16
lclGetTimeValue( const XclExpRoot
& rRoot
, double fSerialDate
, sal_uInt16 nTimeUnit
)
180 DateTime aDateTime
= rRoot
.GetDateTimeFromDouble( fSerialDate
);
183 case EXC_CHDATERANGE_DAYS
:
184 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
185 case EXC_CHDATERANGE_MONTHS
:
186 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( 12 * (aDateTime
.GetYear() - rRoot
.GetBaseYear()) + aDateTime
.GetMonth() - 1, 0, SAL_MAX_INT16
);
187 case EXC_CHDATERANGE_YEARS
:
188 return ::limit_cast
< sal_uInt16
, sal_uInt16
>( aDateTime
.GetYear() - rRoot
.GetBaseYear(), 0, SAL_MAX_INT16
);
190 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
192 return ::limit_cast
< sal_uInt16
, double >( fSerialDate
, 0, SAL_MAX_UINT16
);
195 bool lclConvertTimeValue( const XclExpRoot
& rRoot
, sal_uInt16
& rnValue
, const Any
& rAny
, sal_uInt16 nTimeUnit
)
197 double fSerialDate
= 0;
198 bool bAuto
= lclIsAutoAnyOrGetValue( fSerialDate
, rAny
);
200 rnValue
= lclGetTimeValue( rRoot
, fSerialDate
, nTimeUnit
);
204 sal_uInt16
lclGetTimeUnit( sal_Int32 nApiTimeUnit
)
206 switch( nApiTimeUnit
)
208 case cssc::TimeUnit::DAY
: return EXC_CHDATERANGE_DAYS
;
209 case cssc::TimeUnit::MONTH
: return EXC_CHDATERANGE_MONTHS
;
210 case cssc::TimeUnit::YEAR
: return EXC_CHDATERANGE_YEARS
;
211 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
213 return EXC_CHDATERANGE_DAYS
;
216 bool lclConvertTimeInterval( sal_uInt16
& rnValue
, sal_uInt16
& rnTimeUnit
, const Any
& rAny
)
218 cssc::TimeInterval aInterval
;
219 bool bAuto
= lclIsAutoAnyOrGetValue( aInterval
, rAny
);
222 rnValue
= ::limit_cast
< sal_uInt16
, sal_Int32
>( aInterval
.Number
, 1, SAL_MAX_UINT16
);
223 rnTimeUnit
= lclGetTimeUnit( aInterval
.TimeUnit
);
230 // Common =====================================================================
232 /** Stores global data needed in various classes of the Chart export filter. */
233 struct XclExpChRootData
: public XclChRootData
235 typedef ::std::vector
< XclChFrBlock
> XclChFrBlockVector
;
237 XclExpChChart
& mrChartData
; /// The chart data object.
238 XclChFrBlockVector maWrittenFrBlocks
; /// Stack of future record levels already written out.
239 XclChFrBlockVector maUnwrittenFrBlocks
; /// Stack of future record levels not yet written out.
241 inline explicit XclExpChRootData( XclExpChChart
& rChartData
) : mrChartData( rChartData
) {}
243 /** Registers a new future record level. */
244 void RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
);
245 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
246 void InitializeFutureRecBlock( XclExpStream
& rStrm
);
247 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
248 void FinalizeFutureRecBlock( XclExpStream
& rStrm
);
251 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
253 maUnwrittenFrBlocks
.push_back( rFrBlock
);
256 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream
& rStrm
)
258 // first call from a future record writes all missing CHFRBLOCKBEGIN records
259 if( !maUnwrittenFrBlocks
.empty() )
261 // write the leading CHFRINFO record
262 if( maWrittenFrBlocks
.empty() )
264 rStrm
.StartRecord( EXC_ID_CHFRINFO
, 20 );
265 rStrm
<< EXC_ID_CHFRINFO
<< EXC_FUTUREREC_EMPTYFLAGS
<< EXC_CHFRINFO_EXCELXP2003
<< EXC_CHFRINFO_EXCELXP2003
<< sal_uInt16( 3 );
266 rStrm
<< sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
269 // write all unwritten CHFRBLOCKBEGIN records
270 for( XclChFrBlockVector::const_iterator aIt
= maUnwrittenFrBlocks
.begin(), aEnd
= maUnwrittenFrBlocks
.end(); aIt
!= aEnd
; ++aIt
)
272 OSL_ENSURE( aIt
->mnType
!= EXC_CHFRBLOCK_TYPE_UNKNOWN
, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
273 lclWriteChFrBlockRecord( rStrm
, *aIt
, true );
275 // move all record infos to vector of written blocks
276 maWrittenFrBlocks
.insert( maWrittenFrBlocks
.end(), maUnwrittenFrBlocks
.begin(), maUnwrittenFrBlocks
.end() );
277 maUnwrittenFrBlocks
.clear();
281 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
283 OSL_ENSURE( !maUnwrittenFrBlocks
.empty() || !maWrittenFrBlocks
.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
284 if( !maUnwrittenFrBlocks
.empty() )
286 // no future record has been written, just forget the topmost level
287 maUnwrittenFrBlocks
.pop_back();
289 else if( !maWrittenFrBlocks
.empty() )
291 // write the CHFRBLOCKEND record for the topmost block and delete it
292 lclWriteChFrBlockRecord( rStrm
, maWrittenFrBlocks
.back(), false );
293 maWrittenFrBlocks
.pop_back();
297 XclExpChRoot::XclExpChRoot( const XclExpRoot
& rRoot
, XclExpChChart
& rChartData
) :
299 mxChData( new XclExpChRootData( rChartData
) )
303 XclExpChRoot::~XclExpChRoot()
307 Reference
< XChartDocument
> XclExpChRoot::GetChartDocument() const
309 return mxChData
->mxChartDoc
;
312 XclExpChChart
& XclExpChRoot::GetChartData() const
314 return mxChData
->mrChartData
;
317 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType
) const
319 return mxChData
->mxTypeInfoProv
->GetTypeInfo( eType
);
322 const XclChTypeInfo
& XclExpChRoot::GetChartTypeInfo( const OUString
& rServiceName
) const
324 return mxChData
->mxTypeInfoProv
->GetTypeInfoFromService( rServiceName
);
327 const XclChFormatInfo
& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType
) const
329 return mxChData
->mxFmtInfoProv
->GetFormatInfo( eObjType
);
332 void XclExpChRoot::InitConversion( css::uno::Reference
< css::chart2::XChartDocument
> xChartDoc
, const Rectangle
& rChartRect
) const
334 mxChData
->InitConversion( GetRoot(), xChartDoc
, rChartRect
);
337 void XclExpChRoot::FinishConversion() const
339 mxChData
->FinishConversion();
342 bool XclExpChRoot::IsSystemColor( const Color
& rColor
, sal_uInt16 nSysColorIdx
) const
344 XclExpPalette
& rPal
= GetPalette();
345 return rPal
.IsSystemColor( nSysColorIdx
) && (rColor
== rPal
.GetDefColor( nSysColorIdx
));
348 void XclExpChRoot::SetSystemColor( Color
& rColor
, sal_uInt32
& rnColorId
, sal_uInt16 nSysColorIdx
) const
350 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx
), "XclExpChRoot::SetSystemColor - invalid color index" );
351 rColor
= GetPalette().GetDefColor( nSysColorIdx
);
352 rnColorId
= XclExpPalette::GetColorIdFromIndex( nSysColorIdx
);
355 sal_Int32
XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX
) const
357 return ::limit_cast
< sal_Int32
, double >( (nPosX
- mxChData
->mnBorderGapX
) / mxChData
->mfUnitSizeX
, 0, EXC_CHART_TOTALUNITS
);
360 sal_Int32
XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY
) const
362 return ::limit_cast
< sal_Int32
, double >( (nPosY
- mxChData
->mnBorderGapY
) / mxChData
->mfUnitSizeY
, 0, EXC_CHART_TOTALUNITS
);
365 XclChRectangle
XclExpChRoot::CalcChartRectFromHmm( const css::awt::Rectangle
& rRect
) const
367 XclChRectangle aRect
;
368 aRect
.mnX
= CalcChartXFromHmm( rRect
.X
);
369 aRect
.mnY
= CalcChartYFromHmm( rRect
.Y
);
370 aRect
.mnWidth
= CalcChartXFromHmm( rRect
.Width
);
371 aRect
.mnHeight
= CalcChartYFromHmm( rRect
.Height
);
375 void XclExpChRoot::ConvertLineFormat( XclChLineFormat
& rLineFmt
,
376 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
378 GetChartPropSetHelper().ReadLineProperties(
379 rLineFmt
, *mxChData
->mxLineDashTable
, rPropSet
, ePropMode
);
382 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat
& rAreaFmt
,
383 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
385 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt
, rPropSet
, ePropMode
);
388 void XclExpChRoot::ConvertEscherFormat(
389 XclChEscherFormat
& rEscherFmt
, XclChPicFormat
& rPicFmt
,
390 const ScfPropertySet
& rPropSet
, XclChPropertyMode ePropMode
) const
392 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt
, rPicFmt
,
393 *mxChData
->mxGradientTable
, *mxChData
->mxHatchTable
, *mxChData
->mxBitmapTable
, rPropSet
, ePropMode
);
396 sal_uInt16
XclExpChRoot::ConvertFont( const ScfPropertySet
& rPropSet
, sal_Int16 nScript
) const
398 XclFontData aFontData
;
399 GetFontPropSetHelper().ReadFontProperties( aFontData
, rPropSet
, EXC_FONTPROPSET_CHART
, nScript
);
400 return GetFontBuffer().Insert( aFontData
, EXC_COLOR_CHARTTEXT
);
403 sal_uInt16
XclExpChRoot::ConvertPieRotation( const ScfPropertySet
& rPropSet
)
405 sal_Int32 nApiRot
= 0;
406 rPropSet
.GetProperty( nApiRot
, EXC_CHPROP_STARTINGANGLE
);
407 return static_cast< sal_uInt16
>( (450 - (nApiRot
% 360)) % 360 );
410 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock
& rFrBlock
)
412 mxChData
->RegisterFutureRecBlock( rFrBlock
);
415 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream
& rStrm
)
417 mxChData
->InitializeFutureRecBlock( rStrm
);
420 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream
& rStrm
)
422 mxChData
->FinalizeFutureRecBlock( rStrm
);
425 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot
& rRoot
,
426 sal_uInt16 nFrType
, sal_uInt16 nRecId
, sal_Size nRecSize
) :
427 XclExpRecord( nRecId
, nRecSize
),
428 XclExpChRoot( rRoot
),
433 XclExpChGroupBase::~XclExpChGroupBase()
437 void XclExpChGroupBase::Save( XclExpStream
& rStrm
)
440 XclExpRecord::Save( rStrm
);
442 if( HasSubRecords() )
444 // register the future record context corresponding to this record group
445 RegisterFutureRecBlock( maFrBlock
);
447 XclExpEmptyRecord( EXC_ID_CHBEGIN
).Save( rStrm
);
449 WriteSubRecords( rStrm
);
450 // finalize the future records, must be done before the closing CHEND
451 FinalizeFutureRecBlock( rStrm
);
453 XclExpEmptyRecord( EXC_ID_CHEND
).Save( rStrm
);
457 bool XclExpChGroupBase::HasSubRecords() const
462 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext
, sal_uInt16 nFrValue1
, sal_uInt16 nFrValue2
)
464 maFrBlock
.mnContext
= nFrContext
;
465 maFrBlock
.mnValue1
= nFrValue1
;
466 maFrBlock
.mnValue2
= nFrValue2
;
469 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot
& rRoot
,
470 XclFutureRecType eRecType
, sal_uInt16 nRecId
, sal_Size nRecSize
) :
471 XclExpFutureRecord( eRecType
, nRecId
, nRecSize
),
472 XclExpChRoot( rRoot
)
476 void XclExpChFutureRecordBase::Save( XclExpStream
& rStrm
)
478 InitializeFutureRecBlock( rStrm
);
479 XclExpFutureRecord::Save( rStrm
);
482 // Frame formatting ===========================================================
484 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode
, sal_uInt16 nBRMode
) :
485 XclExpRecord( EXC_ID_CHFRAMEPOS
, 20 )
487 maData
.mnTLMode
= nTLMode
;
488 maData
.mnBRMode
= nBRMode
;
491 void XclExpChFramePos::WriteBody( XclExpStream
& rStrm
)
493 rStrm
<< maData
.mnTLMode
<< maData
.mnBRMode
<< maData
.maRect
;
496 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot
& rRoot
) :
497 XclExpRecord( EXC_ID_CHLINEFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 10 ),
498 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
502 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType
)
504 switch( eDefFrameType
)
506 case EXC_CHFRAMETYPE_AUTO
:
509 case EXC_CHFRAMETYPE_INVISIBLE
:
511 maData
.mnPattern
= EXC_CHLINEFORMAT_NONE
;
514 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" );
518 void XclExpChLineFormat::Convert( const XclExpChRoot
& rRoot
,
519 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
521 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
522 rRoot
.ConvertLineFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
525 // detect system color, set color identifier (TODO: detect automatic series line)
526 if( (eObjType
!= EXC_CHOBJTYPE_LINEARSERIES
) && rRoot
.IsSystemColor( maData
.maColor
, rFmtInfo
.mnAutoLineColorIdx
) )
528 // store color index from automatic format data
529 mnColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoLineColorIdx
);
530 // try to set automatic mode
531 bool bAuto
= (maData
.mnPattern
== EXC_CHLINEFORMAT_SOLID
) && (maData
.mnWeight
== rFmtInfo
.mnAutoLineWeight
);
532 ::set_flag( maData
.mnFlags
, EXC_CHLINEFORMAT_AUTO
, bAuto
);
536 // user defined color - register in palette
537 mnColorId
= rRoot
.GetPalette().InsertColor( maData
.maColor
, EXC_COLOR_CHARTLINE
);
542 // no line - set default system color
543 rRoot
.SetSystemColor( maData
.maColor
, mnColorId
, EXC_COLOR_CHWINDOWTEXT
);
547 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType
) const
550 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasLine()) ||
551 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
554 void XclExpChLineFormat::WriteBody( XclExpStream
& rStrm
)
556 rStrm
<< maData
.maColor
<< maData
.mnPattern
<< maData
.mnWeight
<< maData
.mnFlags
;
557 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
558 rStrm
<< rStrm
.GetRoot().GetPalette().GetColorIndex( mnColorId
);
563 /** Creates a CHLINEFORMAT record from the passed property set. */
564 XclExpChLineFormatRef
lclCreateLineFormat( const XclExpChRoot
& rRoot
,
565 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
567 XclExpChLineFormatRef
xLineFmt( new XclExpChLineFormat( rRoot
) );
568 xLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
569 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
570 if( rFmtInfo
.mbDeleteDefFrame
&& xLineFmt
->IsDefault( rFmtInfo
.meDefFrameType
) )
577 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot
& rRoot
) :
578 XclExpRecord( EXC_ID_CHAREAFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 16 : 12 ),
579 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
580 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
584 bool XclExpChAreaFormat::Convert( const XclExpChRoot
& rRoot
,
585 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
587 const XclChFormatInfo
& rFmtInfo
= rRoot
.GetFormatInfo( eObjType
);
588 bool bComplexFill
= rRoot
.ConvertAreaFormat( maData
, rPropSet
, rFmtInfo
.mePropMode
);
591 bool bSolid
= maData
.mnPattern
== EXC_PATT_SOLID
;
592 // detect system color, set color identifier (TODO: detect automatic series area)
593 if( (eObjType
!= EXC_CHOBJTYPE_FILLEDSERIES
) && rRoot
.IsSystemColor( maData
.maPattColor
, rFmtInfo
.mnAutoPattColorIdx
) )
595 // store color index from automatic format data
596 mnPattColorId
= XclExpPalette::GetColorIdFromIndex( rFmtInfo
.mnAutoPattColorIdx
);
597 // set automatic mode
598 ::set_flag( maData
.mnFlags
, EXC_CHAREAFORMAT_AUTO
, bSolid
);
602 // user defined color - register color in palette
603 mnPattColorId
= rRoot
.GetPalette().InsertColor( maData
.maPattColor
, EXC_COLOR_CHARTAREA
);
605 // background color (default system color for solid fills)
607 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
609 mnBackColorId
= rRoot
.GetPalette().InsertColor( maData
.maBackColor
, EXC_COLOR_CHARTAREA
);
613 // no area - set default system colors
614 rRoot
.SetSystemColor( maData
.maPattColor
, mnPattColorId
, EXC_COLOR_CHWINDOWBACK
);
615 rRoot
.SetSystemColor( maData
.maBackColor
, mnBackColorId
, EXC_COLOR_CHWINDOWTEXT
);
620 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType
)
622 switch( eDefFrameType
)
624 case EXC_CHFRAMETYPE_AUTO
:
627 case EXC_CHFRAMETYPE_INVISIBLE
:
629 maData
.mnPattern
= EXC_PATT_NONE
;
632 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" );
636 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType
) const
639 ((eDefFrameType
== EXC_CHFRAMETYPE_INVISIBLE
) && !HasArea()) ||
640 ((eDefFrameType
== EXC_CHFRAMETYPE_AUTO
) && IsAuto());
643 void XclExpChAreaFormat::WriteBody( XclExpStream
& rStrm
)
645 rStrm
<< maData
.maPattColor
<< maData
.maBackColor
<< maData
.mnPattern
<< maData
.mnFlags
;
646 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
648 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
649 rStrm
<< rPal
.GetColorIndex( mnPattColorId
) << rPal
.GetColorIndex( mnBackColorId
);
653 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot
& rRoot
) :
654 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_UNKNOWN
, EXC_ID_CHESCHERFORMAT
),
655 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) ),
656 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
658 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8
);
661 void XclExpChEscherFormat::Convert( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
663 const XclChFormatInfo
& rFmtInfo
= GetFormatInfo( eObjType
);
664 ConvertEscherFormat( maData
, maPicFmt
, rPropSet
, rFmtInfo
.mePropMode
);
665 // register colors in palette
666 mnColor1Id
= RegisterColor( ESCHER_Prop_fillColor
);
667 mnColor2Id
= RegisterColor( ESCHER_Prop_fillBackColor
);
670 bool XclExpChEscherFormat::IsValid() const
672 return static_cast< bool >(maData
.mxEscherSet
);
675 void XclExpChEscherFormat::Save( XclExpStream
& rStrm
)
677 if( maData
.mxEscherSet
)
679 // replace RGB colors with palette indexes in the Escher container
680 const XclExpPalette
& rPal
= GetPalette();
681 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillColor
, 0x08000000 | rPal
.GetColorIndex( mnColor1Id
) );
682 maData
.mxEscherSet
->AddOpt( ESCHER_Prop_fillBackColor
, 0x08000000 | rPal
.GetColorIndex( mnColor2Id
) );
684 // save the record group
685 XclExpChGroupBase::Save( rStrm
);
689 bool XclExpChEscherFormat::HasSubRecords() const
691 // no subrecords for gradients
692 return maPicFmt
.mnBmpMode
!= EXC_CHPICFORMAT_NONE
;
695 void XclExpChEscherFormat::WriteSubRecords( XclExpStream
& rStrm
)
697 rStrm
.StartRecord( EXC_ID_CHPICFORMAT
, 14 );
698 rStrm
<< maPicFmt
.mnBmpMode
<< sal_uInt16( 0 ) << maPicFmt
.mnFlags
<< maPicFmt
.mfScale
;
702 sal_uInt32
XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId
)
704 sal_uInt32 nBGRValue
;
705 if( maData
.mxEscherSet
&& maData
.mxEscherSet
->GetOpt( nPropId
, nBGRValue
) )
708 Color
aColor( RGB_COLORDATA(
709 COLORDATA_BLUE( nBGRValue
),
710 COLORDATA_GREEN( nBGRValue
),
711 COLORDATA_RED( nBGRValue
) ) );
712 return GetPalette().InsertColor( aColor
, EXC_COLOR_CHARTAREA
);
714 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
);
717 void XclExpChEscherFormat::WriteBody( XclExpStream
& rStrm
)
719 OSL_ENSURE( maData
.mxEscherSet
, "XclExpChEscherFormat::WriteBody - missing property container" );
720 // write Escher property container via temporary memory stream
721 SvMemoryStream aMemStrm
;
722 maData
.mxEscherSet
->Commit( aMemStrm
);
724 aMemStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
725 rStrm
.CopyFromStream( aMemStrm
);
728 XclExpChFrameBase::XclExpChFrameBase()
732 XclExpChFrameBase::~XclExpChFrameBase()
736 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot
& rRoot
,
737 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
740 mxLineFmt
.reset( new XclExpChLineFormat( rRoot
) );
741 mxLineFmt
->Convert( rRoot
, rPropSet
, eObjType
);
742 // area format (only for frame objects)
743 if( rRoot
.GetFormatInfo( eObjType
).mbIsFrame
)
745 mxAreaFmt
.reset( new XclExpChAreaFormat( rRoot
) );
746 bool bComplexFill
= mxAreaFmt
->Convert( rRoot
, rPropSet
, eObjType
);
747 if( (rRoot
.GetBiff() == EXC_BIFF8
) && bComplexFill
)
749 mxEscherFmt
.reset( new XclExpChEscherFormat( rRoot
) );
750 mxEscherFmt
->Convert( rPropSet
, eObjType
);
751 if( mxEscherFmt
->IsValid() )
752 mxAreaFmt
->SetAuto( false );
759 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot
& rRoot
,
760 XclChFrameType eDefFrameType
, bool bIsFrame
)
763 mxLineFmt
.reset( new XclExpChLineFormat( rRoot
) );
764 mxLineFmt
->SetDefault( eDefFrameType
);
765 // area format (only for frame objects)
768 mxAreaFmt
.reset( new XclExpChAreaFormat( rRoot
) );
769 mxAreaFmt
->SetDefault( eDefFrameType
);
774 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType
) const
777 (!mxLineFmt
|| mxLineFmt
->IsDefault( eDefFrameType
)) &&
778 (!mxAreaFmt
|| mxAreaFmt
->IsDefault( eDefFrameType
));
781 void XclExpChFrameBase::WriteFrameRecords( XclExpStream
& rStrm
)
783 lclSaveRecord( rStrm
, mxLineFmt
);
784 lclSaveRecord( rStrm
, mxAreaFmt
);
785 lclSaveRecord( rStrm
, mxEscherFmt
);
788 XclExpChFrame::XclExpChFrame( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
789 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_FRAME
, EXC_ID_CHFRAME
, 4 ),
790 meObjType( eObjType
)
794 void XclExpChFrame::Convert( const ScfPropertySet
& rPropSet
)
796 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
799 void XclExpChFrame::SetAutoFlags( bool bAutoPos
, bool bAutoSize
)
801 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOPOS
, bAutoPos
);
802 ::set_flag( maData
.mnFlags
, EXC_CHFRAME_AUTOSIZE
, bAutoSize
);
805 bool XclExpChFrame::IsDefault() const
807 return IsDefaultFrameBase( GetFormatInfo( meObjType
).meDefFrameType
);
810 bool XclExpChFrame::IsDeleteable() const
812 return IsDefault() && GetFormatInfo( meObjType
).mbDeleteDefFrame
;
815 void XclExpChFrame::Save( XclExpStream
& rStrm
)
819 // wall/floor frame without CHFRAME header record
820 case EXC_CHOBJTYPE_WALL3D
:
821 case EXC_CHOBJTYPE_FLOOR3D
:
822 WriteFrameRecords( rStrm
);
825 XclExpChGroupBase::Save( rStrm
);
829 void XclExpChFrame::WriteSubRecords( XclExpStream
& rStrm
)
831 WriteFrameRecords( rStrm
);
834 void XclExpChFrame::WriteBody( XclExpStream
& rStrm
)
836 rStrm
<< maData
.mnFormat
<< maData
.mnFlags
;
841 /** Creates a CHFRAME record from the passed property set. */
842 XclExpChFrameRef
lclCreateFrame( const XclExpChRoot
& rRoot
,
843 const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
845 XclExpChFrameRef
xFrame( new XclExpChFrame( rRoot
, eObjType
) );
846 xFrame
->Convert( rPropSet
);
847 if( xFrame
->IsDeleteable() )
854 // Source links ===============================================================
858 void lclAddDoubleRefData(
859 ScTokenArray
& orArray
, const FormulaToken
& rToken
,
860 SCsTAB nScTab1
, SCsCOL nScCol1
, SCsROW nScRow1
,
861 SCsTAB nScTab2
, SCsCOL nScCol2
, SCsROW nScRow2
)
863 ScComplexRefData aComplexRef
;
864 aComplexRef
.InitRange(ScRange(nScCol1
,nScRow1
,nScTab1
,nScCol2
,nScRow2
,nScTab2
));
865 aComplexRef
.Ref1
.SetFlag3D( true );
867 if( orArray
.GetLen() > 0 )
868 orArray
.AddOpCode( ocUnion
);
870 OSL_ENSURE( (rToken
.GetType() == ::formula::svDoubleRef
) || (rToken
.GetType() == ::formula::svExternalDoubleRef
),
871 "lclAddDoubleRefData - double reference token expected");
872 if( rToken
.GetType() == ::formula::svExternalDoubleRef
)
873 orArray
.AddExternalDoubleReference(
874 rToken
.GetIndex(), rToken
.GetString().getString(), aComplexRef
);
876 orArray
.AddDoubleReference( aComplexRef
);
881 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot
& rRoot
, sal_uInt8 nDestType
) :
882 XclExpRecord( EXC_ID_CHSOURCELINK
),
883 XclExpChRoot( rRoot
)
885 maData
.mnDestType
= nDestType
;
886 maData
.mnLinkType
= EXC_CHSRCLINK_DIRECTLY
;
889 sal_uInt16
XclExpChSourceLink::ConvertDataSequence( Reference
< XDataSequence
> xDataSeq
, bool bSplitToColumns
, sal_uInt16 nDefCount
)
892 maData
.mnLinkType
= EXC_CHSRCLINK_DEFAULT
;
897 // Compile the range representation string into token array. Note that the
898 // source range text depends on the current grammar.
899 OUString aRangeRepr
= xDataSeq
->getSourceRangeRepresentation();
900 ScCompiler
aComp( &GetDocRef(), ScAddress() );
901 aComp
.SetGrammar( GetDocRef().GetGrammar() );
902 std::unique_ptr
<ScTokenArray
> pArray(aComp
.CompileString(aRangeRepr
));
907 sal_uInt32 nValueCount
= 0;
909 for( const FormulaToken
* pToken
= pArray
->First(); pToken
; pToken
= pArray
->Next() )
911 switch( pToken
->GetType() )
913 case ::formula::svSingleRef
:
914 case ::formula::svExternalSingleRef
:
915 // for a single ref token, just add it to the new token array as is
916 if( aArray
.GetLen() > 0 )
917 aArray
.AddOpCode( ocUnion
);
918 aArray
.AddToken( *pToken
);
922 case ::formula::svDoubleRef
:
923 case ::formula::svExternalDoubleRef
:
925 // split 3-dimensional ranges into single sheets
926 const ScComplexRefData
& rComplexRef
= *pToken
->GetDoubleRef();
927 ScAddress aAbs1
= rComplexRef
.Ref1
.toAbs(ScAddress());
928 ScAddress aAbs2
= rComplexRef
.Ref2
.toAbs(ScAddress());
929 for (SCsTAB nScTab
= aAbs1
.Tab(); nScTab
<= aAbs2
.Tab(); ++nScTab
)
931 // split 2-dimensional ranges into single columns
932 if (bSplitToColumns
&& (aAbs1
.Col() < aAbs2
.Col()) && (aAbs1
.Row() < aAbs2
.Row()))
933 for (SCCOL nScCol
= aAbs1
.Col(); nScCol
<= aAbs2
.Col(); ++nScCol
)
934 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, nScCol
, aAbs1
.Row(), nScTab
, nScCol
, aAbs2
.Row());
936 lclAddDoubleRefData(aArray
, *pToken
, nScTab
, aAbs1
.Col(), aAbs1
.Row(), nScTab
, aAbs2
.Col(), aAbs2
.Row());
938 sal_uInt32 nTabs
= static_cast<sal_uInt32
>(aAbs2
.Tab() - aAbs1
.Tab() + 1);
939 sal_uInt32 nCols
= static_cast<sal_uInt32
>(aAbs2
.Col() - aAbs1
.Col() + 1);
940 sal_uInt32 nRows
= static_cast<sal_uInt32
>(aAbs2
.Row() - aAbs1
.Row() + 1);
941 nValueCount
+= nCols
* nRows
* nTabs
;
949 const ScAddress aBaseCell
;
950 mxLinkFmla
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART
, aArray
, &aBaseCell
);
951 maData
.mnLinkType
= EXC_CHSRCLINK_WORKSHEET
;
952 return ulimit_cast
< sal_uInt16
>( nValueCount
, EXC_CHDATAFORMAT_MAXPOINTCOUNT
);
955 void XclExpChSourceLink::ConvertString( const OUString
& aString
)
957 mxString
= XclExpStringHelper::CreateString( GetRoot(), aString
, EXC_STR_FORCEUNICODE
| EXC_STR_8BITLENGTH
| EXC_STR_SEPARATEFORMATS
);
960 sal_uInt16
XclExpChSourceLink::ConvertStringSequence( const Sequence
< Reference
< XFormattedString
> >& rStringSeq
)
963 sal_uInt16 nFontIdx
= EXC_FONT_APP
;
964 if( rStringSeq
.hasElements() )
966 mxString
= XclExpStringHelper::CreateString( GetRoot(), OUString(), EXC_STR_FORCEUNICODE
| EXC_STR_8BITLENGTH
| EXC_STR_SEPARATEFORMATS
);
967 Reference
< XBreakIterator
> xBreakIt
= GetDoc().GetBreakIterator();
968 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
970 // convert all formatted string entries from the sequence
971 const Reference
< XFormattedString
>* pBeg
= rStringSeq
.getConstArray();
972 const Reference
< XFormattedString
>* pEnd
= pBeg
+ rStringSeq
.getLength();
973 for( const Reference
< XFormattedString
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
977 sal_uInt16 nWstrnFontIdx
= EXC_FONT_NOTFOUND
;
978 sal_uInt16 nAsianFontIdx
= EXC_FONT_NOTFOUND
;
979 sal_uInt16 nCmplxFontIdx
= EXC_FONT_NOTFOUND
;
980 OUString aText
= (*pIt
)->getString();
981 ScfPropertySet
aStrProp( *pIt
);
983 // #i63255# get script type for leading weak characters
984 sal_Int16 nLastScript
= XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText
);
986 // process all script portions
987 sal_Int32 nPortionPos
= 0;
988 sal_Int32 nTextLen
= aText
.getLength();
989 while( nPortionPos
< nTextLen
)
991 // get script type and end position of next script portion
992 sal_Int16 nScript
= xBreakIt
->getScriptType( aText
, nPortionPos
);
993 sal_Int32 nPortionEnd
= xBreakIt
->endOfScript( aText
, nPortionPos
, nScript
);
995 // reuse previous script for following weak portions
996 if( nScript
== ApiScriptType::WEAK
)
997 nScript
= nLastScript
;
999 // Excel start position of this portion
1000 sal_uInt16 nXclPortionStart
= mxString
->Len();
1001 // add portion text to Excel string
1002 XclExpStringHelper::AppendString( *mxString
, GetRoot(), aText
.copy( nPortionPos
, nPortionEnd
- nPortionPos
) );
1003 if( nXclPortionStart
< mxString
->Len() )
1005 // find font index variable dependent on script type
1006 sal_uInt16
& rnFontIdx
= (nScript
== ApiScriptType::COMPLEX
) ? nCmplxFontIdx
:
1007 ((nScript
== ApiScriptType::ASIAN
) ? nAsianFontIdx
: nWstrnFontIdx
);
1009 // insert font into buffer (if not yet done)
1010 if( rnFontIdx
== EXC_FONT_NOTFOUND
)
1011 rnFontIdx
= ConvertFont( aStrProp
, nScript
);
1013 // insert font index into format run vector
1014 mxString
->AppendFormat( nXclPortionStart
, rnFontIdx
);
1017 // go to next script portion
1018 nLastScript
= nScript
;
1019 nPortionPos
= nPortionEnd
;
1023 if( !mxString
->IsEmpty() )
1025 // get leading font index
1026 const XclFormatRunVec
& rFormats
= mxString
->GetFormats();
1027 OSL_ENSURE( !rFormats
.empty() && (rFormats
.front().mnChar
== 0),
1028 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1029 // remove leading format run, if entire string is equally formatted
1030 if( rFormats
.size() == 1 )
1031 nFontIdx
= mxString
->RemoveLeadingFont();
1032 else if( !rFormats
.empty() )
1033 nFontIdx
= rFormats
.front().mnFontIdx
;
1034 // add trailing format run, if string is rich-formatted
1035 if( mxString
->IsRich() )
1036 mxString
->AppendTrailingFormat( EXC_FONT_APP
);
1042 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet
& rPropSet
, bool bPercent
)
1044 sal_Int32 nApiNumFmt
= 0;
1045 if( bPercent
? rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_PERCENTAGENUMFMT
) : rPropSet
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
1047 ::set_flag( maData
.mnFlags
, EXC_CHSRCLINK_NUMFMT
);
1048 maData
.mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
1052 void XclExpChSourceLink::AppendString( const OUString
& rStr
)
1056 XclExpStringHelper::AppendString( *mxString
, GetRoot(), rStr
);
1059 void XclExpChSourceLink::Save( XclExpStream
& rStrm
)
1061 // CHFORMATRUNS record
1062 if( mxString
&& mxString
->IsRich() )
1064 sal_Size nRecSize
= (1 + mxString
->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8
) ? 2 : 1);
1065 rStrm
.StartRecord( EXC_ID_CHFORMATRUNS
, nRecSize
);
1066 mxString
->WriteFormats( rStrm
, true );
1069 // CHSOURCELINK record
1070 XclExpRecord::Save( rStrm
);
1072 if( mxString
&& !mxString
->IsEmpty() )
1074 rStrm
.StartRecord( EXC_ID_CHSTRING
, 2 + mxString
->GetSize() );
1075 rStrm
<< sal_uInt16( 0 ) << *mxString
;
1080 void XclExpChSourceLink::WriteBody( XclExpStream
& rStrm
)
1082 rStrm
<< maData
.mnDestType
1083 << maData
.mnLinkType
1085 << maData
.mnNumFmtIdx
1089 // Text =======================================================================
1091 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx
) :
1092 XclExpUInt16Record( EXC_ID_CHFONT
, nFontIdx
)
1096 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget
, const XclChDataPointPos
& rPointPos
) :
1097 XclExpRecord( EXC_ID_CHOBJECTLINK
, 6 )
1099 maData
.mnTarget
= nLinkTarget
;
1100 maData
.maPointPos
= rPointPos
;
1103 void XclExpChObjectLink::WriteBody( XclExpStream
& rStrm
)
1105 rStrm
<< maData
.mnTarget
<< maData
.maPointPos
.mnSeriesIdx
<< maData
.maPointPos
.mnPointIdx
;
1108 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot
& rRoot
) :
1109 XclExpChFutureRecordBase( rRoot
, EXC_FUTUREREC_UNUSEDREF
, EXC_ID_CHFRLABELPROPS
, 4 )
1113 void XclExpChFrLabelProps::Convert( const ScfPropertySet
& rPropSet
,
1114 bool bShowCateg
, bool bShowValue
, bool bShowPercent
, bool bShowBubble
)
1116 // label value flags
1117 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWSERIES
, false );
1118 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWCATEG
, bShowCateg
);
1119 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWVALUE
, bShowValue
);
1120 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWPERCENT
, bShowPercent
);
1121 ::set_flag( maData
.mnFlags
, EXC_CHFRLABELPROPS_SHOWBUBBLE
, bShowBubble
);
1123 // label value separator
1124 maData
.maSeparator
= rPropSet
.GetStringProperty( EXC_CHPROP_LABELSEPARATOR
);
1125 if( maData
.maSeparator
.isEmpty() )
1126 maData
.maSeparator
= " ";
1129 void XclExpChFrLabelProps::WriteBody( XclExpStream
& rStrm
)
1131 XclExpString
aXclSep( maData
.maSeparator
, EXC_STR_FORCEUNICODE
| EXC_STR_SMARTFLAGS
);
1132 rStrm
<< maData
.mnFlags
<< aXclSep
;
1135 XclExpChFontBase::~XclExpChFontBase()
1139 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, sal_uInt16 nFontIdx
)
1141 if( const XclExpFont
* pFont
= rRoot
.GetFontBuffer().GetFont( nFontIdx
) )
1143 XclExpChFontRef
xFont( new XclExpChFont( nFontIdx
) );
1144 SetFont( xFont
, pFont
->GetFontData().maColor
, pFont
->GetFontColorId() );
1148 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot
& rRoot
, const ScfPropertySet
& rPropSet
)
1150 ConvertFontBase( rRoot
, rRoot
.ConvertFont( rPropSet
, rRoot
.GetDefApiScript() ) );
1153 void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet
& rPropSet
, bool bSupportsStacked
)
1155 sal_uInt16 nRotation
= XclChPropSetHelper::ReadRotationProperties( rPropSet
, bSupportsStacked
);
1156 SetRotation( nRotation
);
1159 XclExpChText::XclExpChText( const XclExpChRoot
& rRoot
) :
1160 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TEXT
, EXC_ID_CHTEXT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 32 : 26 ),
1161 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
1165 void XclExpChText::SetFont( XclExpChFontRef xFont
, const Color
& rColor
, sal_uInt32 nColorId
)
1168 maData
.maTextColor
= rColor
;
1169 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOCOLOR
, rColor
== COL_AUTO
);
1170 mnTextColorId
= nColorId
;
1173 void XclExpChText::SetRotation( sal_uInt16 nRotation
)
1175 maData
.mnRotation
= nRotation
;
1176 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 8, 3 );
1179 void XclExpChText::ConvertTitle( Reference
< XTitle
> xTitle
, sal_uInt16 nTarget
, const OUString
* pSubTitle
)
1183 case EXC_CHOBJLINK_TITLE
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE
); break;
1184 case EXC_CHOBJLINK_YAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 1 ); break;
1185 case EXC_CHOBJLINK_XAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
); break;
1186 case EXC_CHOBJLINK_ZAXIS
: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE
, 2 ); break;
1190 mxObjLink
.reset( new XclExpChObjectLink( nTarget
, XclChDataPointPos( 0, 0 ) ) );
1194 // title frame formatting
1195 ScfPropertySet
aTitleProp( xTitle
);
1196 mxFrame
= lclCreateFrame( GetChRoot(), aTitleProp
, EXC_CHOBJTYPE_TEXT
);
1199 mxSrcLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
) );
1200 sal_uInt16 nFontIdx
= mxSrcLink
->ConvertStringSequence( xTitle
->getText() );
1203 // append subtitle as the 2nd line of the title.
1204 OUString
aSubTitle("\n");
1205 aSubTitle
+= *pSubTitle
;
1206 mxSrcLink
->AppendString(aSubTitle
);
1209 ConvertFontBase( GetChRoot(), nFontIdx
);
1212 ConvertRotationBase( aTitleProp
, true );
1214 // manual text position - only for main title
1215 mxFramePos
.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
, EXC_CHFRAMEPOS_PARENT
) );
1216 if( nTarget
== EXC_CHOBJLINK_TITLE
)
1219 if( aTitleProp
.GetAnyProperty( aRelPos
, EXC_CHPROP_RELATIVEPOSITION
) && aRelPos
.has
< RelativePosition
>() ) try
1221 // calculate absolute position for CHTEXT record
1222 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
1223 Reference
< XShape
> xTitleShape( xChart1Doc
->getTitle(), UNO_SET_THROW
);
1224 css::awt::Point aPos
= xTitleShape
->getPosition();
1225 css::awt::Size aSize
= xTitleShape
->getSize();
1226 css::awt::Rectangle
aRect( aPos
.X
, aPos
.Y
, aSize
.Width
, aSize
.Height
);
1227 maData
.maRect
= CalcChartRectFromHmm( aRect
);
1228 ::insert_value( maData
.mnFlags2
, EXC_CHTEXT_POS_MOVED
, 0, 4 );
1229 // manual title position implies manual plot area
1230 GetChartData().SetManualPlotArea();
1231 // calculate the default title position in chart units
1232 sal_Int32 nDefPosX
= ::std::max
< sal_Int32
>( (EXC_CHART_TOTALUNITS
- maData
.maRect
.mnWidth
) / 2, 0 );
1233 sal_Int32 nDefPosY
= 85;
1234 // set the position relative to the standard position
1235 XclChRectangle
& rFrameRect
= mxFramePos
->GetFramePosData().maRect
;
1236 rFrameRect
.mnX
= maData
.maRect
.mnX
- nDefPosX
;
1237 rFrameRect
.mnY
= maData
.maRect
.mnY
- nDefPosY
;
1246 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
);
1250 void XclExpChText::ConvertLegend( const ScfPropertySet
& rPropSet
)
1252 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1253 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOGEN
);
1254 ConvertFontBase( GetChRoot(), rPropSet
);
1257 bool XclExpChText::ConvertDataLabel( const ScfPropertySet
& rPropSet
,
1258 const XclChTypeInfo
& rTypeInfo
, const XclChDataPointPos
& rPointPos
)
1260 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL
, rPointPos
.mnPointIdx
, rPointPos
.mnSeriesIdx
);
1262 cssc2::DataPointLabel aPointLabel
;
1263 if( !rPropSet
.GetProperty( aPointLabel
, EXC_CHPROP_LABEL
) )
1266 // percentage only allowed in pie and donut charts
1267 bool bIsPie
= rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
;
1268 // bubble sizes only allowed in bubble charts
1269 bool bIsBubble
= rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
;
1270 OSL_ENSURE( (GetBiff() == EXC_BIFF8
) || !bIsBubble
, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1273 bool bShowValue
= !bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1274 bool bShowPercent
= bIsPie
&& aPointLabel
.ShowNumberInPercent
; // percentage only in pie/donut charts
1275 bool bShowCateg
= aPointLabel
.ShowCategoryName
;
1276 bool bShowBubble
= bIsBubble
&& aPointLabel
.ShowNumber
; // Chart2 uses 'ShowNumber' for bubble size
1277 bool bShowAny
= bShowValue
|| bShowPercent
|| bShowCateg
|| bShowBubble
;
1279 // create the CHFRLABELPROPS record for extended settings in BIFF8
1280 if( bShowAny
&& (GetBiff() == EXC_BIFF8
) )
1282 mxLabelProps
.reset( new XclExpChFrLabelProps( GetChRoot() ) );
1283 mxLabelProps
->Convert( rPropSet
, bShowCateg
, bShowValue
, bShowPercent
, bShowBubble
);
1286 // restrict to combinations allowed in CHTEXT
1287 if( bShowPercent
) bShowValue
= false; // percent wins over value
1288 if( bShowValue
) bShowCateg
= false; // value wins over category
1289 if( bShowValue
|| bShowCateg
) bShowBubble
= false; // value or category wins over bubble size
1292 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1293 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
, bShowValue
);
1294 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
, bShowPercent
);
1295 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
, bShowCateg
);
1296 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
, bShowPercent
&& bShowCateg
);
1297 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWBUBBLE
, bShowBubble
);
1298 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWSYMBOL
, bShowAny
&& aPointLabel
.ShowLegendSymbol
);
1299 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_DELETED
, !bShowAny
);
1304 ConvertFontBase( GetChRoot(), rPropSet
);
1305 ConvertRotationBase( rPropSet
, false );
1307 sal_Int32 nPlacement
= 0;
1308 sal_uInt16 nLabelPos
= EXC_CHTEXT_POS_AUTO
;
1309 if( rPropSet
.GetProperty( nPlacement
, EXC_CHPROP_LABELPLACEMENT
) )
1311 using namespace cssc::DataLabelPlacement
;
1312 if( nPlacement
== rTypeInfo
.mnDefaultLabelPos
)
1314 nLabelPos
= EXC_CHTEXT_POS_DEFAULT
;
1316 else switch( nPlacement
)
1318 case AVOID_OVERLAP
: nLabelPos
= EXC_CHTEXT_POS_AUTO
; break;
1319 case CENTER
: nLabelPos
= EXC_CHTEXT_POS_CENTER
; break;
1320 case TOP
: nLabelPos
= EXC_CHTEXT_POS_ABOVE
; break;
1321 case TOP_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1322 case LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1323 case BOTTOM_LEFT
: nLabelPos
= EXC_CHTEXT_POS_LEFT
; break;
1324 case BOTTOM
: nLabelPos
= EXC_CHTEXT_POS_BELOW
; break;
1325 case BOTTOM_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1326 case RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1327 case TOP_RIGHT
: nLabelPos
= EXC_CHTEXT_POS_RIGHT
; break;
1328 case INSIDE
: nLabelPos
= EXC_CHTEXT_POS_INSIDE
; break;
1329 case OUTSIDE
: nLabelPos
= EXC_CHTEXT_POS_OUTSIDE
; break;
1330 case NEAR_ORIGIN
: nLabelPos
= EXC_CHTEXT_POS_AXIS
; break;
1331 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1334 ::insert_value( maData
.mnFlags2
, nLabelPos
, 0, 4 );
1335 // source link (contains number format)
1336 mxSrcLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
) );
1337 if( bShowValue
|| bShowPercent
)
1338 // percentage format wins over value format
1339 mxSrcLink
->ConvertNumFmt( rPropSet
, bShowPercent
);
1341 mxObjLink
.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
) );
1344 /* Return true to indicate valid label settings:
1345 - for existing labels at entire series
1346 - for any settings at single data point (to be able to delete a point label) */
1347 return bShowAny
|| (rPointPos
.mnPointIdx
!= EXC_CHDATAFORMAT_ALLPOINTS
);
1350 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet
& rPropSet
, const XclChDataPointPos
& rPointPos
)
1353 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_AUTOTEXT
);
1354 if( GetBiff() == EXC_BIFF8
)
1355 ::set_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
); // must set this to make equation visible in Excel
1357 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_TEXT
);
1359 maData
.mnHAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1360 maData
.mnVAlign
= EXC_CHTEXT_ALIGN_TOPLEFT
;
1361 ConvertFontBase( GetChRoot(), rPropSet
);
1362 // source link (contains number format)
1363 mxSrcLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
) );
1364 mxSrcLink
->ConvertNumFmt( rPropSet
, false );
1366 mxObjLink
.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA
, rPointPos
) );
1369 sal_uInt16
XclExpChText::GetAttLabelFlags() const
1371 sal_uInt16 nFlags
= 0;
1372 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWVALUE
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWVALUE
) );
1373 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWPERCENT
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWPERCENT
) );
1374 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEGPERC
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEGPERC
) );
1375 ::set_flag( nFlags
, EXC_CHATTLABEL_SHOWCATEG
, ::get_flag( maData
.mnFlags
, EXC_CHTEXT_SHOWCATEG
) );
1379 void XclExpChText::WriteSubRecords( XclExpStream
& rStrm
)
1381 // CHFRAMEPOS record
1382 lclSaveRecord( rStrm
, mxFramePos
);
1384 lclSaveRecord( rStrm
, mxFont
);
1385 // CHSOURCELINK group
1386 lclSaveRecord( rStrm
, mxSrcLink
);
1388 lclSaveRecord( rStrm
, mxFrame
);
1389 // CHOBJECTLINK record
1390 lclSaveRecord( rStrm
, mxObjLink
);
1391 // CHFRLABELPROPS record
1392 lclSaveRecord( rStrm
, mxLabelProps
);
1395 void XclExpChText::WriteBody( XclExpStream
& rStrm
)
1397 rStrm
<< maData
.mnHAlign
1399 << maData
.mnBackMode
1400 << maData
.maTextColor
1404 if( GetBiff() == EXC_BIFF8
)
1406 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
)
1408 << maData
.mnRotation
;
1414 /** Creates and returns an Excel text object from the passed title. */
1415 XclExpChTextRef
lclCreateTitle( const XclExpChRoot
& rRoot
, Reference
< XTitled
> xTitled
, sal_uInt16 nTarget
,
1416 const OUString
* pSubTitle
= nullptr )
1418 Reference
< XTitle
> xTitle
;
1420 xTitle
= xTitled
->getTitleObject();
1422 XclExpChTextRef
xText( new XclExpChText( rRoot
) );
1423 xText
->ConvertTitle( xTitle
, nTarget
, pSubTitle
);
1424 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1425 will be interpreted as auto-generated title showing the series title in
1426 charts that contain exactly one data series. */
1427 if( (nTarget
!= EXC_CHOBJLINK_TITLE
) && !xText
->HasString() )
1435 // Data series ================================================================
1437 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot
& rRoot
) :
1438 XclExpRecord( EXC_ID_CHMARKERFORMAT
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 20 : 12 ),
1439 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) ),
1440 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK
) )
1444 void XclExpChMarkerFormat::Convert( const XclExpChRoot
& rRoot
,
1445 const ScfPropertySet
& rPropSet
, sal_uInt16 nFormatIdx
)
1447 XclChPropSetHelper::ReadMarkerProperties( maData
, rPropSet
, nFormatIdx
);
1448 /* Set marker line/fill color to series line color.
1449 TODO: remove this if OOChart supports own colors in markers. */
1451 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1452 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1453 // register colors in palette
1454 RegisterColors( rRoot
);
1457 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot
& rRoot
,
1458 const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1460 // clear the automatic flag
1461 ::set_flag( maData
.mnFlags
, EXC_CHMARKERFORMAT_AUTO
, false );
1462 // symbol type and color
1465 // set symbol type for the 'close' data series
1466 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_DOWJ
;
1467 maData
.mnMarkerSize
= EXC_CHMARKERFORMAT_DOUBLESIZE
;
1468 // set symbol line/fill color to series line color
1470 if( rPropSet
.GetColorProperty( aLineColor
, EXC_CHPROP_COLOR
) )
1472 maData
.maLineColor
= maData
.maFillColor
= aLineColor
;
1473 RegisterColors( rRoot
);
1478 // set invisible symbol
1479 maData
.mnMarkerType
= EXC_CHMARKERFORMAT_NOSYMBOL
;
1483 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot
& rRoot
)
1487 if( HasLineColor() )
1488 mnLineColorId
= rRoot
.GetPalette().InsertColor( maData
.maLineColor
, EXC_COLOR_CHARTLINE
);
1489 if( HasFillColor() )
1490 mnFillColorId
= rRoot
.GetPalette().InsertColor( maData
.maFillColor
, EXC_COLOR_CHARTAREA
);
1494 void XclExpChMarkerFormat::WriteBody( XclExpStream
& rStrm
)
1496 rStrm
<< maData
.maLineColor
<< maData
.maFillColor
<< maData
.mnMarkerType
<< maData
.mnFlags
;
1497 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
1499 const XclExpPalette
& rPal
= rStrm
.GetRoot().GetPalette();
1500 rStrm
<< rPal
.GetColorIndex( mnLineColorId
) << rPal
.GetColorIndex( mnFillColorId
) << maData
.mnMarkerSize
;
1504 XclExpChPieFormat::XclExpChPieFormat() :
1505 XclExpUInt16Record( EXC_ID_CHPIEFORMAT
, 0 )
1509 void XclExpChPieFormat::Convert( const ScfPropertySet
& rPropSet
)
1511 double fApiDist(0.0);
1512 if( rPropSet
.GetProperty( fApiDist
, EXC_CHPROP_OFFSET
) )
1513 SetValue( limit_cast
< sal_uInt16
>( fApiDist
* 100.0, 0, 100 ) );
1516 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1517 XclExpRecord( EXC_ID_CH3DDATAFORMAT
, 2 )
1521 void XclExpCh3dDataFormat::Convert( const ScfPropertySet
& rPropSet
)
1523 sal_Int32
nApiType(0);
1524 if( rPropSet
.GetProperty( nApiType
, EXC_CHPROP_GEOMETRY3D
) )
1526 using namespace cssc2::DataPointGeometry3D
;
1530 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1531 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1534 maData
.mnBase
= EXC_CH3DDATAFORMAT_RECT
;
1535 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1538 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1539 maData
.mnTop
= EXC_CH3DDATAFORMAT_STRAIGHT
;
1542 maData
.mnBase
= EXC_CH3DDATAFORMAT_CIRC
;
1543 maData
.mnTop
= EXC_CH3DDATAFORMAT_SHARP
;
1546 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1551 void XclExpCh3dDataFormat::WriteBody( XclExpStream
& rStrm
)
1553 rStrm
<< maData
.mnBase
<< maData
.mnTop
;
1556 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags
) :
1557 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL
, nFlags
)
1561 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot
& rRoot
,
1562 const XclChDataPointPos
& rPointPos
, sal_uInt16 nFormatIdx
) :
1563 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DATAFORMAT
, EXC_ID_CHDATAFORMAT
, 8 )
1565 maData
.maPointPos
= rPointPos
;
1566 maData
.mnFormatIdx
= nFormatIdx
;
1569 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
)
1571 // line and area formatting
1572 ConvertFrameBase( GetChRoot(), rPropSet
, rTypeInfo
.GetSeriesObjectType() );
1574 // data point symbols
1575 bool bIsFrame
= rTypeInfo
.IsSeriesFrameFormat();
1578 mxMarkerFmt
.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1579 mxMarkerFmt
->Convert( GetChRoot(), rPropSet
, maData
.mnFormatIdx
);
1583 if( rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
)
1585 mxPieFmt
.reset( new XclExpChPieFormat
);
1586 mxPieFmt
->Convert( rPropSet
);
1589 // 3D bars (only allowed for entire series in BIFF8)
1590 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8
) && rTypeInfo
.mb3dChart
&& (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
) )
1592 mx3dDataFmt
.reset( new XclExpCh3dDataFormat
);
1593 mx3dDataFmt
->Convert( rPropSet
);
1597 if( IsSeriesFormat() && rTypeInfo
.mbSpline
&& !bIsFrame
)
1598 mxSeriesFmt
.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT
, EXC_CHSERIESFORMAT_SMOOTHED
) );
1600 // data point labels
1601 XclExpChTextRef
xLabel( new XclExpChText( GetChRoot() ) );
1602 if( xLabel
->ConvertDataLabel( rPropSet
, rTypeInfo
, maData
.maPointPos
) )
1604 // CHTEXT groups for data labels are stored in global CHCHART group
1605 GetChartData().SetDataLabel( xLabel
);
1606 mxAttLabel
.reset( new XclExpChAttachedLabel( xLabel
->GetAttLabelFlags() ) );
1610 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet
& rPropSet
, bool bCloseSymbol
)
1612 // set line format to invisible
1613 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, false );
1614 // set symbols to invisible or to 'close' series symbol
1615 mxMarkerFmt
.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1616 mxMarkerFmt
->ConvertStockSymbol( GetChRoot(), rPropSet
, bCloseSymbol
);
1619 void XclExpChDataFormat::ConvertLine( const ScfPropertySet
& rPropSet
, XclChObjectType eObjType
)
1621 ConvertFrameBase( GetChRoot(), rPropSet
, eObjType
);
1624 void XclExpChDataFormat::WriteSubRecords( XclExpStream
& rStrm
)
1626 lclSaveRecord( rStrm
, mx3dDataFmt
);
1627 WriteFrameRecords( rStrm
);
1628 lclSaveRecord( rStrm
, mxPieFmt
);
1629 lclSaveRecord( rStrm
, mxMarkerFmt
);
1630 lclSaveRecord( rStrm
, mxSeriesFmt
);
1631 lclSaveRecord( rStrm
, mxAttLabel
);
1634 void XclExpChDataFormat::WriteBody( XclExpStream
& rStrm
)
1636 rStrm
<< maData
.maPointPos
.mnPointIdx
1637 << maData
.maPointPos
.mnSeriesIdx
1638 << maData
.mnFormatIdx
1642 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot
& rRoot
) :
1643 XclExpRecord( EXC_ID_CHSERTRENDLINE
, 28 ),
1644 XclExpChRoot( rRoot
)
1648 bool XclExpChSerTrendLine::Convert( Reference
< XRegressionCurve
> xRegCurve
, sal_uInt16 nSeriesIdx
)
1650 if( !xRegCurve
.is() )
1654 ScfPropertySet
aCurveProp( xRegCurve
);
1656 OUString aService
= aCurveProp
.GetServiceName();
1657 if( aService
== "com.sun.star.chart2.LinearRegressionCurve" )
1659 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1662 else if( aService
== "com.sun.star.chart2.ExponentialRegressionCurve" )
1664 maData
.mnLineType
= EXC_CHSERTREND_EXPONENTIAL
;
1666 else if( aService
== "com.sun.star.chart2.LogarithmicRegressionCurve" )
1668 maData
.mnLineType
= EXC_CHSERTREND_LOGARITHMIC
;
1670 else if( aService
== "com.sun.star.chart2.PotentialRegressionCurve" )
1672 maData
.mnLineType
= EXC_CHSERTREND_POWER
;
1674 else if( aService
== "com.sun.star.chart2.PolynomialRegressionCurve" )
1676 maData
.mnLineType
= EXC_CHSERTREND_POLYNOMIAL
;
1678 aCurveProp
.GetProperty(aDegree
, EXC_CHPROP_POLYNOMIAL_DEGREE
);
1679 maData
.mnOrder
= static_cast<sal_uInt8
> (aDegree
);
1681 else if( aService
== "com.sun.star.chart2.MovingAverageRegressionCurve" )
1683 maData
.mnLineType
= EXC_CHSERTREND_MOVING_AVG
;
1685 aCurveProp
.GetProperty(aPeriod
, EXC_CHPROP_MOVING_AVERAGE_PERIOD
);
1686 maData
.mnOrder
= static_cast<sal_uInt8
> (aPeriod
);
1693 aCurveProp
.GetProperty(maData
.mfForecastFor
, EXC_CHPROP_EXTRAPOLATE_FORWARD
);
1694 aCurveProp
.GetProperty(maData
.mfForecastBack
, EXC_CHPROP_EXTRAPOLATE_BACKWARD
);
1695 bool bIsForceIntercept
= false;
1696 aCurveProp
.GetProperty(bIsForceIntercept
, EXC_CHPROP_FORCE_INTERCEPT
);
1697 if (bIsForceIntercept
)
1698 aCurveProp
.GetProperty(maData
.mfIntercept
, EXC_CHPROP_INTERCEPT_VALUE
);
1701 XclChDataPointPos
aPointPos( nSeriesIdx
);
1702 mxDataFmt
.reset( new XclExpChDataFormat( GetChRoot(), aPointPos
, 0 ) );
1703 mxDataFmt
->ConvertLine( aCurveProp
, EXC_CHOBJTYPE_TRENDLINE
);
1705 // #i83100# show equation and correlation coefficient
1706 ScfPropertySet
aEquationProp( xRegCurve
->getEquationProperties() );
1707 maData
.mnShowEquation
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWEQUATION
) ? 1 : 0;
1708 maData
.mnShowRSquared
= aEquationProp
.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION
) ? 1 : 0;
1710 // #i83100# formatting of the equation text box
1711 if( (maData
.mnShowEquation
!= 0) || (maData
.mnShowRSquared
!= 0) )
1713 mxLabel
.reset( new XclExpChText( GetChRoot() ) );
1714 mxLabel
->ConvertTrendLineEquation( aEquationProp
, aPointPos
);
1718 // #i5085# manual trend line size
1719 // #i34093# manual crossing point
1723 void XclExpChSerTrendLine::WriteBody( XclExpStream
& rStrm
)
1725 rStrm
<< maData
.mnLineType
1727 << maData
.mfIntercept
1728 << maData
.mnShowEquation
1729 << maData
.mnShowRSquared
1730 << maData
.mfForecastFor
1731 << maData
.mfForecastBack
;
1734 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot
& rRoot
, sal_uInt8 nBarType
) :
1735 XclExpRecord( EXC_ID_CHSERERRORBAR
, 14 ),
1736 XclExpChRoot( rRoot
)
1738 maData
.mnBarType
= nBarType
;
1741 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink
& rValueLink
, sal_uInt16
& rnValueCount
, const ScfPropertySet
& rPropSet
)
1743 sal_Int32 nBarStyle
= 0;
1744 bool bOk
= rPropSet
.GetProperty( nBarStyle
, EXC_CHPROP_ERRORBARSTYLE
);
1749 case cssc::ErrorBarStyle::ABSOLUTE
:
1750 maData
.mnSourceType
= EXC_CHSERERR_FIXED
;
1751 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1753 case cssc::ErrorBarStyle::RELATIVE
:
1754 maData
.mnSourceType
= EXC_CHSERERR_PERCENT
;
1755 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_POSITIVEERROR
);
1757 case cssc::ErrorBarStyle::STANDARD_DEVIATION
:
1758 maData
.mnSourceType
= EXC_CHSERERR_STDDEV
;
1759 rPropSet
.GetProperty( maData
.mfValue
, EXC_CHPROP_WEIGHT
);
1761 case cssc::ErrorBarStyle::STANDARD_ERROR
:
1762 maData
.mnSourceType
= EXC_CHSERERR_STDERR
;
1764 case cssc::ErrorBarStyle::FROM_DATA
:
1767 maData
.mnSourceType
= EXC_CHSERERR_CUSTOM
;
1768 Reference
< XDataSource
> xDataSource( rPropSet
.GetApiPropertySet(), UNO_QUERY
);
1769 if( xDataSource
.is() )
1771 // find first sequence with current role
1772 OUString aRole
= XclChartHelper::GetErrorBarValuesRole( maData
.mnBarType
);
1773 Reference
< XDataSequence
> xValueSeq
;
1775 Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1776 const Reference
< XLabeledDataSequence
>* pBeg
= aLabeledSeqVec
.getConstArray();
1777 const Reference
< XLabeledDataSequence
>* pEnd
= pBeg
+ aLabeledSeqVec
.getLength();
1778 for( const Reference
< XLabeledDataSequence
>* pIt
= pBeg
; !xValueSeq
.is() && (pIt
!= pEnd
); ++pIt
)
1780 Reference
< XDataSequence
> xTmpValueSeq
= (*pIt
)->getValues();
1781 ScfPropertySet
aValueProp( xTmpValueSeq
);
1783 if( aValueProp
.GetProperty( aCurrRole
, EXC_CHPROP_ROLE
) && (aCurrRole
== aRole
) )
1784 xValueSeq
= xTmpValueSeq
;
1786 if( xValueSeq
.is() )
1788 // #i86465# pass value count back to series
1789 rnValueCount
= maData
.mnValueCount
= rValueLink
.ConvertDataSequence( xValueSeq
, true );
1790 bOk
= maData
.mnValueCount
> 0;
1802 void XclExpChSerErrorBar::WriteBody( XclExpStream
& rStrm
)
1804 rStrm
<< maData
.mnBarType
1805 << maData
.mnSourceType
1807 << sal_uInt8( 1 ) // must be 1 to make line visible
1809 << maData
.mnValueCount
;
1814 /** Returns the property set of the specified data point. */
1815 ScfPropertySet
lclGetPointPropSet( Reference
< XDataSeries
> xDataSeries
, sal_Int32 nPointIdx
)
1817 ScfPropertySet aPropSet
;
1820 aPropSet
.Set( xDataSeries
->getDataPointByIndex( nPointIdx
) );
1824 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1831 XclExpChSeries::XclExpChSeries( const XclExpChRoot
& rRoot
, sal_uInt16 nSeriesIdx
) :
1832 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_SERIES
, EXC_ID_CHSERIES
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 12 : 8 ),
1833 mnGroupIdx( EXC_CHSERGROUP_NONE
),
1834 mnSeriesIdx( nSeriesIdx
),
1835 mnParentIdx( EXC_CHSERIES_INVALID
)
1837 // CHSOURCELINK records are always required, even if unused
1838 mxTitleLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE
) );
1839 mxValueLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES
) );
1840 mxCategLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY
) );
1841 if( GetBiff() == EXC_BIFF8
)
1842 mxBubbleLink
.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES
) );
1845 bool XclExpChSeries::ConvertDataSeries(
1846 Reference
< XDiagram
> xDiagram
, Reference
< XDataSeries
> xDataSeries
,
1847 const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
)
1850 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1851 if( xDataSource
.is() )
1853 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
, xXValueSeq
, xBubbleSeq
;
1855 // find first sequence with role 'values-y'
1856 Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1857 const Reference
< XLabeledDataSequence
>* pBeg
= aLabeledSeqVec
.getConstArray();
1858 const Reference
< XLabeledDataSequence
>* pEnd
= pBeg
+ aLabeledSeqVec
.getLength();
1859 for( const Reference
< XLabeledDataSequence
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
1861 Reference
< XDataSequence
> xTmpValueSeq
= (*pIt
)->getValues();
1862 ScfPropertySet
aValueProp( xTmpValueSeq
);
1864 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) )
1866 if( !xYValueSeq
.is() && (aRole
== EXC_CHPROP_ROLE_YVALUES
) )
1868 xYValueSeq
= xTmpValueSeq
;
1869 if( !xTitleSeq
.is() )
1870 xTitleSeq
= (*pIt
)->getLabel(); // ignore role of label sequence
1872 else if( !xXValueSeq
.is() && !rTypeInfo
.mbCategoryAxis
&& (aRole
== EXC_CHPROP_ROLE_XVALUES
) )
1874 xXValueSeq
= xTmpValueSeq
;
1876 else if( !xBubbleSeq
.is() && (rTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
) && (aRole
== EXC_CHPROP_ROLE_SIZEVALUES
) )
1878 xBubbleSeq
= xTmpValueSeq
;
1879 xTitleSeq
= (*pIt
)->getLabel(); // ignore role of label sequence
1884 bOk
= xYValueSeq
.is();
1887 // chart type group index
1888 mnGroupIdx
= nGroupIdx
;
1890 // convert source links
1891 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1892 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1894 // X values of XY charts
1895 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xXValueSeq
, false, maData
.mnValueCount
);
1897 // size values of bubble charts
1899 mxBubbleLink
->ConvertDataSequence( xBubbleSeq
, false, maData
.mnValueCount
);
1901 // series formatting
1902 XclChDataPointPos
aPointPos( mnSeriesIdx
);
1903 ScfPropertySet
aSeriesProp( xDataSeries
);
1904 mxSeriesFmt
.reset( new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
) );
1905 mxSeriesFmt
->ConvertDataSeries( aSeriesProp
, rTypeInfo
);
1908 CreateTrendLines( xDataSeries
);
1911 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARX
, EXC_CHSERERR_XPLUS
, EXC_CHSERERR_XMINUS
);
1912 CreateErrorBars( aSeriesProp
, EXC_CHPROP_ERRORBARY
, EXC_CHSERERR_YPLUS
, EXC_CHSERERR_YMINUS
);
1914 if( maData
.mnValueCount
> 0 )
1916 const sal_Int32 nMaxPointCount
= maData
.mnValueCount
;
1918 /* #i91063# Create missing fill properties in pie/doughnut charts.
1919 If freshly created (never saved to ODF), these charts show
1920 varying point colors but do not return these points via API. */
1921 if( xDiagram
.is() && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_PIE
) )
1923 Reference
< XColorScheme
> xColorScheme
= xDiagram
->getDefaultColorScheme();
1924 if( xColorScheme
.is() )
1926 const OUString aFillStyleName
= "FillStyle";
1927 const OUString aColorName
= "Color";
1928 namespace cssd
= ::com::sun::star::drawing
;
1929 for( sal_Int32 nPointIdx
= 0; nPointIdx
< nMaxPointCount
; ++nPointIdx
)
1931 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( nPointIdx
);
1932 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, nPointIdx
);
1933 // test that the point fill style is solid, but no color is set
1934 cssd::FillStyle eFillStyle
= cssd::FillStyle_NONE
;
1935 if( aPointProp
.GetProperty( eFillStyle
, aFillStyleName
) &&
1936 (eFillStyle
== cssd::FillStyle_SOLID
) &&
1937 !aPointProp
.HasProperty( aColorName
) )
1939 aPointProp
.SetProperty( aColorName
, xColorScheme
->getColorByIndex( nPointIdx
) );
1945 // data point formatting
1946 Sequence
< sal_Int32
> aPointIndexes
;
1947 if( aSeriesProp
.GetProperty( aPointIndexes
, EXC_CHPROP_ATTRIBDATAPOINTS
) && aPointIndexes
.hasElements() )
1949 const sal_Int32
* pnBeg
= aPointIndexes
.getConstArray();
1950 const sal_Int32
* pnEnd
= pnBeg
+ aPointIndexes
.getLength();
1951 for( const sal_Int32
* pnIt
= pnBeg
; (pnIt
!= pnEnd
) && (*pnIt
< nMaxPointCount
); ++pnIt
)
1953 aPointPos
.mnPointIdx
= static_cast< sal_uInt16
>( *pnIt
);
1954 ScfPropertySet aPointProp
= lclGetPointPropSet( xDataSeries
, *pnIt
);
1955 XclExpChDataFormatRef
xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos
, nFormatIdx
) );
1956 xPointFmt
->ConvertDataSeries( aPointProp
, rTypeInfo
);
1957 maPointFmts
.AppendRecord( xPointFmt
);
1966 bool XclExpChSeries::ConvertStockSeries( css::uno::Reference
< css::chart2::XDataSeries
> xDataSeries
,
1967 const OUString
& rValueRole
, sal_uInt16 nGroupIdx
, sal_uInt16 nFormatIdx
, bool bCloseSymbol
)
1970 Reference
< XDataSource
> xDataSource( xDataSeries
, UNO_QUERY
);
1971 if( xDataSource
.is() )
1973 Reference
< XDataSequence
> xYValueSeq
, xTitleSeq
;
1975 // find first sequence with passed role
1976 Sequence
< Reference
< XLabeledDataSequence
> > aLabeledSeqVec
= xDataSource
->getDataSequences();
1977 const Reference
< XLabeledDataSequence
>* pBeg
= aLabeledSeqVec
.getConstArray();
1978 const Reference
< XLabeledDataSequence
>* pEnd
= pBeg
+ aLabeledSeqVec
.getLength();
1979 for( const Reference
< XLabeledDataSequence
>* pIt
= pBeg
; !xYValueSeq
.is() && (pIt
!= pEnd
); ++pIt
)
1981 Reference
< XDataSequence
> xTmpValueSeq
= (*pIt
)->getValues();
1982 ScfPropertySet
aValueProp( xTmpValueSeq
);
1984 if( aValueProp
.GetProperty( aRole
, EXC_CHPROP_ROLE
) && (aRole
== rValueRole
) )
1986 xYValueSeq
= xTmpValueSeq
;
1987 xTitleSeq
= (*pIt
)->getLabel(); // ignore role of label sequence
1991 bOk
= xYValueSeq
.is();
1994 // chart type group index
1995 mnGroupIdx
= nGroupIdx
;
1996 // convert source links
1997 maData
.mnValueCount
= mxValueLink
->ConvertDataSequence( xYValueSeq
, true );
1998 mxTitleLink
->ConvertDataSequence( xTitleSeq
, true );
1999 // series formatting
2000 ScfPropertySet
aSeriesProp( xDataSeries
);
2001 mxSeriesFmt
.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), nFormatIdx
) );
2002 mxSeriesFmt
->ConvertStockSeries( aSeriesProp
, bCloseSymbol
);
2008 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries
& rParent
, Reference
< XRegressionCurve
> xRegCurve
)
2010 InitFromParent( rParent
);
2012 mxTrendLine
.reset( new XclExpChSerTrendLine( GetChRoot() ) );
2013 bool bOk
= mxTrendLine
->Convert( xRegCurve
, mnSeriesIdx
);
2017 ScfPropertySet
aProperties( xRegCurve
);
2018 aProperties
.GetProperty(aName
, EXC_CHPROP_CURVENAME
);
2019 mxTitleLink
->ConvertString(aName
);
2021 mxSeriesFmt
= mxTrendLine
->GetDataFormat();
2022 GetChartData().SetDataLabel( mxTrendLine
->GetDataLabel() );
2027 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries
& rParent
, const ScfPropertySet
& rPropSet
, sal_uInt8 nBarId
)
2029 InitFromParent( rParent
);
2030 // error bar settings
2031 mxErrorBar
.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId
) );
2032 bool bOk
= mxErrorBar
->Convert( *mxValueLink
, maData
.mnValueCount
, rPropSet
);
2035 // error bar formatting
2036 mxSeriesFmt
.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx
), 0 ) );
2037 mxSeriesFmt
->ConvertLine( rPropSet
, EXC_CHOBJTYPE_ERRORBAR
);
2042 void XclExpChSeries::ConvertCategSequence( Reference
< XLabeledDataSequence
> xCategSeq
)
2044 if( xCategSeq
.is() )
2045 maData
.mnCategCount
= mxCategLink
->ConvertDataSequence( xCategSeq
->getValues(), false );
2048 void XclExpChSeries::WriteSubRecords( XclExpStream
& rStrm
)
2050 lclSaveRecord( rStrm
, mxTitleLink
);
2051 lclSaveRecord( rStrm
, mxValueLink
);
2052 lclSaveRecord( rStrm
, mxCategLink
);
2053 lclSaveRecord( rStrm
, mxBubbleLink
);
2054 lclSaveRecord( rStrm
, mxSeriesFmt
);
2055 maPointFmts
.Save( rStrm
);
2056 if( mnGroupIdx
!= EXC_CHSERGROUP_NONE
)
2057 XclExpUInt16Record( EXC_ID_CHSERGROUP
, mnGroupIdx
).Save( rStrm
);
2058 if( mnParentIdx
!= EXC_CHSERIES_INVALID
)
2059 XclExpUInt16Record( EXC_ID_CHSERPARENT
, mnParentIdx
).Save( rStrm
);
2060 lclSaveRecord( rStrm
, mxTrendLine
);
2061 lclSaveRecord( rStrm
, mxErrorBar
);
2064 void XclExpChSeries::InitFromParent( const XclExpChSeries
& rParent
)
2066 // index to parent series is stored 1-based
2067 mnParentIdx
= rParent
.mnSeriesIdx
+ 1;
2068 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2069 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2070 maData
.mnCategCount
= rParent
.maData
.mnCategCount
;
2071 maData
.mnValueCount
= rParent
.maData
.mnValueCount
;
2074 void XclExpChSeries::CreateTrendLines( css::uno::Reference
< css::chart2::XDataSeries
> xDataSeries
)
2076 Reference
< XRegressionCurveContainer
> xRegCurveCont( xDataSeries
, UNO_QUERY
);
2077 if( xRegCurveCont
.is() )
2079 Sequence
< Reference
< XRegressionCurve
> > aRegCurveSeq
= xRegCurveCont
->getRegressionCurves();
2080 const Reference
< XRegressionCurve
>* pBeg
= aRegCurveSeq
.getConstArray();
2081 const Reference
< XRegressionCurve
>* pEnd
= pBeg
+ aRegCurveSeq
.getLength();
2082 for( const Reference
< XRegressionCurve
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
2084 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2085 if( xSeries
&& !xSeries
->ConvertTrendLine( *this, *pIt
) )
2086 GetChartData().RemoveLastSeries();
2091 void XclExpChSeries::CreateErrorBars( const ScfPropertySet
& rPropSet
,
2092 const OUString
& rBarPropName
, sal_uInt8 nPosBarId
, sal_uInt8 nNegBarId
)
2094 Reference
< XPropertySet
> xErrorBar
;
2095 if( rPropSet
.GetProperty( xErrorBar
, rBarPropName
) && xErrorBar
.is() )
2097 ScfPropertySet
aErrorProp( xErrorBar
);
2098 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWPOSITIVEERROR
, nPosBarId
);
2099 CreateErrorBar( aErrorProp
, EXC_CHPROP_SHOWNEGATIVEERROR
, nNegBarId
);
2103 void XclExpChSeries::CreateErrorBar( const ScfPropertySet
& rPropSet
,
2104 const OUString
& rShowPropName
, sal_uInt8 nBarId
)
2106 if( rPropSet
.GetBoolProperty( rShowPropName
) )
2108 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2109 if( xSeries
&& !xSeries
->ConvertErrorBar( *this, rPropSet
, nBarId
) )
2110 GetChartData().RemoveLastSeries();
2114 void XclExpChSeries::WriteBody( XclExpStream
& rStrm
)
2116 rStrm
<< maData
.mnCategType
<< maData
.mnValueType
<< maData
.mnCategCount
<< maData
.mnValueCount
;
2117 if( GetBiff() == EXC_BIFF8
)
2118 rStrm
<< maData
.mnBubbleType
<< maData
.mnBubbleCount
;
2121 // Chart type groups ==========================================================
2123 XclExpChType::XclExpChType( const XclExpChRoot
& rRoot
) :
2124 XclExpRecord( EXC_ID_CHUNKNOWN
),
2125 XclExpChRoot( rRoot
),
2126 maTypeInfo( rRoot
.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN
) )
2130 void XclExpChType::Convert( Reference
< XDiagram
> xDiagram
, Reference
< XChartType
> xChartType
,
2131 sal_Int32 nApiAxesSetIdx
, bool bSwappedAxesSet
, bool bHasXLabels
)
2133 if( xChartType
.is() )
2135 maTypeInfo
= GetChartTypeInfo( xChartType
->getChartType() );
2136 // special handling for some chart types
2137 switch( maTypeInfo
.meTypeCateg
)
2139 case EXC_CHTYPECATEG_BAR
:
2141 maTypeInfo
= GetChartTypeInfo( bSwappedAxesSet
? EXC_CHTYPEID_HORBAR
: EXC_CHTYPEID_BAR
);
2142 ::set_flag( maData
.mnFlags
, EXC_CHBAR_HORIZONTAL
, bSwappedAxesSet
);
2143 ScfPropertySet
aTypeProp( xChartType
);
2144 Sequence
< sal_Int32
> aInt32Seq
;
2145 maData
.mnOverlap
= 0;
2146 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_OVERLAPSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2147 maData
.mnOverlap
= limit_cast
< sal_Int16
>( -aInt32Seq
[ nApiAxesSetIdx
], -100, 100 );
2149 if( aTypeProp
.GetProperty( aInt32Seq
, EXC_CHPROP_GAPWIDTHSEQ
) && (nApiAxesSetIdx
< aInt32Seq
.getLength()) )
2150 maData
.mnGap
= limit_cast
< sal_uInt16
>( aInt32Seq
[ nApiAxesSetIdx
], 0, 500 );
2153 case EXC_CHTYPECATEG_RADAR
:
2154 ::set_flag( maData
.mnFlags
, EXC_CHRADAR_AXISLABELS
, bHasXLabels
);
2156 case EXC_CHTYPECATEG_PIE
:
2158 ScfPropertySet
aTypeProp( xChartType
);
2159 bool bDonut
= aTypeProp
.GetBoolProperty( EXC_CHPROP_USERINGS
);
2160 maTypeInfo
= GetChartTypeInfo( bDonut
? EXC_CHTYPEID_DONUT
: EXC_CHTYPEID_PIE
);
2161 maData
.mnPieHole
= bDonut
? 50 : 0;
2162 // #i85166# starting angle of first pie slice
2163 ScfPropertySet
aDiaProp( xDiagram
);
2164 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( aDiaProp
);
2167 case EXC_CHTYPECATEG_SCATTER
:
2168 if( GetBiff() == EXC_BIFF8
)
2169 ::set_flag( maData
.mnFlags
, EXC_CHSCATTER_BUBBLES
, maTypeInfo
.meTypeId
== EXC_CHTYPEID_BUBBLES
);
2173 SetRecId( maTypeInfo
.mnRecId
);
2177 void XclExpChType::SetStacked( bool bPercent
)
2179 switch( maTypeInfo
.meTypeCateg
)
2181 case EXC_CHTYPECATEG_LINE
:
2182 ::set_flag( maData
.mnFlags
, EXC_CHLINE_STACKED
);
2183 ::set_flag( maData
.mnFlags
, EXC_CHLINE_PERCENT
, bPercent
);
2185 case EXC_CHTYPECATEG_BAR
:
2186 ::set_flag( maData
.mnFlags
, EXC_CHBAR_STACKED
);
2187 ::set_flag( maData
.mnFlags
, EXC_CHBAR_PERCENT
, bPercent
);
2188 maData
.mnOverlap
= -100;
2194 void XclExpChType::WriteBody( XclExpStream
& rStrm
)
2196 switch( GetRecId() )
2199 rStrm
<< maData
.mnOverlap
<< maData
.mnGap
<< maData
.mnFlags
;
2204 case EXC_ID_CHRADARLINE
:
2205 case EXC_ID_CHRADARAREA
:
2206 rStrm
<< maData
.mnFlags
;
2210 rStrm
<< maData
.mnRotation
<< maData
.mnPieHole
;
2211 if( GetBiff() == EXC_BIFF8
)
2212 rStrm
<< maData
.mnFlags
;
2215 case EXC_ID_CHSCATTER
:
2216 if( GetBiff() == EXC_BIFF8
)
2217 rStrm
<< maData
.mnBubbleSize
<< maData
.mnBubbleType
<< maData
.mnFlags
;
2221 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" );
2225 XclExpChChart3d::XclExpChChart3d() :
2226 XclExpRecord( EXC_ID_CHCHART3D
, 14 )
2230 void XclExpChChart3d::Convert( const ScfPropertySet
& rPropSet
, bool b3dWallChart
)
2232 sal_Int32 nRotationY
= 0;
2233 rPropSet
.GetProperty( nRotationY
, EXC_CHPROP_ROTATIONVERTICAL
);
2234 sal_Int32 nRotationX
= 0;
2235 rPropSet
.GetProperty( nRotationX
, EXC_CHPROP_ROTATIONHORIZONTAL
);
2236 sal_Int32 nPerspective
= 15;
2237 rPropSet
.GetProperty( nPerspective
, EXC_CHPROP_PERSPECTIVE
);
2241 // Y rotation (Excel [0..359], Chart2 [-179,180])
2242 if( nRotationY
< 0 ) nRotationY
+= 360;
2243 maData
.mnRotation
= static_cast< sal_uInt16
>( nRotationY
);
2244 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2245 maData
.mnElevation
= limit_cast
< sal_Int16
>( nRotationX
, -90, 90 );
2246 // perspective (Excel and Chart2 [0,100])
2247 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2250 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_REAL3D
, !rPropSet
.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES
) );
2251 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_AUTOHEIGHT
);
2252 ::set_flag( maData
.mnFlags
, EXC_CHCHART3D_HASWALLS
);
2256 // Y rotation not used in pie charts, but 'first pie slice angle'
2257 maData
.mnRotation
= XclExpChRoot::ConvertPieRotation( rPropSet
);
2258 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2259 maData
.mnElevation
= limit_cast
< sal_Int16
>( (nRotationX
+ 270) % 180, 10, 80 );
2260 // perspective (Excel and Chart2 [0,100])
2261 maData
.mnEyeDist
= limit_cast
< sal_uInt16
>( nPerspective
, 0, 100 );
2267 void XclExpChChart3d::WriteBody( XclExpStream
& rStrm
)
2269 rStrm
<< maData
.mnRotation
2270 << maData
.mnElevation
2272 << maData
.mnRelHeight
2273 << maData
.mnRelDepth
2274 << maData
.mnDepthGap
2278 XclExpChLegend::XclExpChLegend( const XclExpChRoot
& rRoot
) :
2279 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_LEGEND
, EXC_ID_CHLEGEND
, 20 )
2283 void XclExpChLegend::Convert( const ScfPropertySet
& rPropSet
)
2286 mxFrame
= lclCreateFrame( GetChRoot(), rPropSet
, EXC_CHOBJTYPE_LEGEND
);
2288 mxText
.reset( new XclExpChText( GetChRoot() ) );
2289 mxText
->ConvertLegend( rPropSet
);
2291 // legend position and size
2292 Any aRelPosAny
, aRelSizeAny
;
2293 rPropSet
.GetAnyProperty( aRelPosAny
, EXC_CHPROP_RELATIVEPOSITION
);
2294 rPropSet
.GetAnyProperty( aRelSizeAny
, EXC_CHPROP_RELATIVESIZE
);
2295 cssc::ChartLegendExpansion eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2296 rPropSet
.GetProperty( eApiExpand
, EXC_CHPROP_EXPANSION
);
2297 if( aRelPosAny
.has
< RelativePosition
>() || ((eApiExpand
== cssc::ChartLegendExpansion_CUSTOM
) && aRelSizeAny
.has
< RelativeSize
>()) )
2301 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2302 indicator of manually changed legend position/size, but due to
2303 the different anchor modes used by this property (in the
2304 RelativePosition.Anchor member) it cannot be used to calculate
2305 the position easily. For this, the Chart1 API will be used
2307 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
2308 Reference
< XShape
> xChart1Legend( xChart1Doc
->getLegend(), UNO_SET_THROW
);
2309 // coordinates in CHLEGEND record written but not used by Excel
2310 mxFramePos
.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE
, EXC_CHFRAMEPOS_PARENT
) );
2311 XclChFramePos
& rFramePos
= mxFramePos
->GetFramePosData();
2312 rFramePos
.mnTLMode
= EXC_CHFRAMEPOS_CHARTSIZE
;
2313 css::awt::Point aLegendPos
= xChart1Legend
->getPosition();
2314 rFramePos
.maRect
.mnX
= maData
.maRect
.mnX
= CalcChartXFromHmm( aLegendPos
.X
);
2315 rFramePos
.maRect
.mnY
= maData
.maRect
.mnY
= CalcChartYFromHmm( aLegendPos
.Y
);
2316 // legend size, Excel expects points in CHFRAMEPOS record
2317 rFramePos
.mnBRMode
= EXC_CHFRAMEPOS_ABSSIZE_POINTS
;
2318 css::awt::Size aLegendSize
= xChart1Legend
->getSize();
2319 rFramePos
.maRect
.mnWidth
= static_cast< sal_uInt16
>( aLegendSize
.Width
* EXC_POINTS_PER_HMM
+ 0.5 );
2320 rFramePos
.maRect
.mnHeight
= static_cast< sal_uInt16
>( aLegendSize
.Height
* EXC_POINTS_PER_HMM
+ 0.5 );
2321 maData
.maRect
.mnWidth
= CalcChartXFromHmm( aLegendSize
.Width
);
2322 maData
.maRect
.mnHeight
= CalcChartYFromHmm( aLegendSize
.Height
);
2323 eApiExpand
= cssc::ChartLegendExpansion_CUSTOM
;
2324 // manual legend position implies manual plot area
2325 GetChartData().SetManualPlotArea();
2326 maData
.mnDockMode
= EXC_CHLEGEND_NOTDOCKED
;
2327 // a CHFRAME record with cleared auto flags is needed
2329 mxFrame
.reset( new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND
) );
2330 mxFrame
->SetAutoFlags( false, false );
2334 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
2335 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2336 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2341 cssc2::LegendPosition eApiPos
= cssc2::LegendPosition_CUSTOM
;
2342 rPropSet
.GetProperty( eApiPos
, EXC_CHPROP_ANCHORPOSITION
);
2345 case cssc2::LegendPosition_LINE_START
: maData
.mnDockMode
= EXC_CHLEGEND_LEFT
; break;
2346 case cssc2::LegendPosition_LINE_END
: maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
; break;
2347 case cssc2::LegendPosition_PAGE_START
: maData
.mnDockMode
= EXC_CHLEGEND_TOP
; break;
2348 case cssc2::LegendPosition_PAGE_END
: maData
.mnDockMode
= EXC_CHLEGEND_BOTTOM
; break;
2350 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
2351 maData
.mnDockMode
= EXC_CHLEGEND_RIGHT
;
2352 eApiExpand
= cssc::ChartLegendExpansion_HIGH
;
2355 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_STACKED
, eApiExpand
== cssc::ChartLegendExpansion_HIGH
);
2358 ::set_flag( maData
.mnFlags
, EXC_CHLEGEND_AUTOSERIES
);
2359 const sal_uInt16 nAutoFlags
= EXC_CHLEGEND_DOCKED
| EXC_CHLEGEND_AUTOPOSX
| EXC_CHLEGEND_AUTOPOSY
;
2360 ::set_flag( maData
.mnFlags
, nAutoFlags
, maData
.mnDockMode
!= EXC_CHLEGEND_NOTDOCKED
);
2363 void XclExpChLegend::WriteSubRecords( XclExpStream
& rStrm
)
2365 lclSaveRecord( rStrm
, mxFramePos
);
2366 lclSaveRecord( rStrm
, mxText
);
2367 lclSaveRecord( rStrm
, mxFrame
);
2370 void XclExpChLegend::WriteBody( XclExpStream
& rStrm
)
2372 rStrm
<< maData
.maRect
<< maData
.mnDockMode
<< maData
.mnSpacing
<< maData
.mnFlags
;
2375 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot
& rRoot
, XclChObjectType eObjType
) :
2376 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_DROPBAR
, EXC_ID_CHDROPBAR
, 2 ),
2377 meObjType( eObjType
),
2382 void XclExpChDropBar::Convert( const ScfPropertySet
& rPropSet
)
2385 ConvertFrameBase( GetChRoot(), rPropSet
, meObjType
);
2387 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE
, true );
2390 void XclExpChDropBar::WriteSubRecords( XclExpStream
& rStrm
)
2392 WriteFrameRecords( rStrm
);
2395 void XclExpChDropBar::WriteBody( XclExpStream
& rStrm
)
2400 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot
& rRoot
, sal_uInt16 nGroupIdx
) :
2401 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_TYPEGROUP
, EXC_ID_CHTYPEGROUP
, 20 ),
2403 maTypeInfo( maType
.GetTypeInfo() )
2405 maData
.mnGroupIdx
= nGroupIdx
;
2408 void XclExpChTypeGroup::ConvertType(
2409 Reference
< XDiagram
> xDiagram
, Reference
< XChartType
> xChartType
,
2410 sal_Int32 nApiAxesSetIdx
, bool b3dChart
, bool bSwappedAxesSet
, bool bHasXLabels
)
2412 // chart type settings
2413 maType
.Convert( xDiagram
, xChartType
, nApiAxesSetIdx
, bSwappedAxesSet
, bHasXLabels
);
2415 // spline - TODO: get from single series (#i66858#)
2416 ScfPropertySet
aTypeProp( xChartType
);
2417 cssc2::CurveStyle eCurveStyle
;
2418 bool bSpline
= aTypeProp
.GetProperty( eCurveStyle
, EXC_CHPROP_CURVESTYLE
) &&
2419 (eCurveStyle
!= cssc2::CurveStyle_LINES
);
2421 // extended type info
2422 maTypeInfo
.Set( maType
.GetTypeInfo(), b3dChart
, bSpline
);
2424 // 3d chart settings
2425 if( maTypeInfo
.mb3dChart
) // only true, if Excel chart supports 3d mode
2427 mxChart3d
.reset( new XclExpChChart3d
);
2428 ScfPropertySet
aDiaProp( xDiagram
);
2429 mxChart3d
->Convert( aDiaProp
, Is3dWallChart() );
2433 void XclExpChTypeGroup::ConvertSeries(
2434 Reference
< XDiagram
> xDiagram
, Reference
< XChartType
> xChartType
,
2435 sal_Int32 nGroupAxesSetIdx
, bool bPercent
, bool bConnectBars
)
2437 Reference
< XDataSeriesContainer
> xSeriesCont( xChartType
, UNO_QUERY
);
2438 if( xSeriesCont
.is() )
2440 typedef ::std::vector
< Reference
< XDataSeries
> > XDataSeriesVec
;
2441 XDataSeriesVec aSeriesVec
;
2443 // copy data series attached to the current axes set to the vector
2444 Sequence
< Reference
< XDataSeries
> > aSeriesSeq
= xSeriesCont
->getDataSeries();
2445 const Reference
< XDataSeries
>* pBeg
= aSeriesSeq
.getConstArray();
2446 const Reference
< XDataSeries
>* pEnd
= pBeg
+ aSeriesSeq
.getLength();
2447 for( const Reference
< XDataSeries
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
2449 ScfPropertySet
aSeriesProp( *pIt
);
2450 sal_Int32
nSeriesAxesSetIdx(0);
2451 if( aSeriesProp
.GetProperty( nSeriesAxesSetIdx
, EXC_CHPROP_ATTAXISINDEX
) && (nSeriesAxesSetIdx
== nGroupAxesSetIdx
) )
2452 aSeriesVec
.push_back( *pIt
);
2455 // Are there any series in the current axes set?
2456 if( !aSeriesVec
.empty() )
2458 // stacking direction (stacked/percent/deep 3d) from first series
2459 ScfPropertySet
aSeriesProp( aSeriesVec
.front() );
2460 cssc2::StackingDirection eStacking
;
2461 if( !aSeriesProp
.GetProperty( eStacking
, EXC_CHPROP_STACKINGDIR
) )
2462 eStacking
= cssc2::StackingDirection_NO_STACKING
;
2464 // stacked or percent chart
2465 if( maTypeInfo
.mbSupportsStacking
&& (eStacking
== cssc2::StackingDirection_Y_STACKING
) )
2467 // percent overrides simple stacking
2468 maType
.SetStacked( bPercent
);
2470 // connected data points (only in stacked bar charts)
2471 if (bConnectBars
&& (maTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_BAR
))
2473 sal_uInt16 nKey
= EXC_CHCHARTLINE_CONNECT
;
2474 m_ChartLines
.insert(std::make_pair(nKey
, o3tl::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2479 // reverse series order for some unstacked 2D chart types
2480 if( maTypeInfo
.mbReverseSeries
&& !Is3dChart() )
2481 ::std::reverse( aSeriesVec
.begin(), aSeriesVec
.end() );
2484 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2485 if( (eStacking
== cssc2::StackingDirection_NO_STACKING
) && Is3dWallChart() )
2486 mxChart3d
->SetClustered();
2488 // varied point colors
2489 ::set_flag( maData
.mnFlags
, EXC_CHTYPEGROUP_VARIEDCOLORS
, aSeriesProp
.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY
) );
2491 // process all series
2492 for( XDataSeriesVec::const_iterator aIt
= aSeriesVec
.begin(), aEnd
= aSeriesVec
.end(); aIt
!= aEnd
; ++aIt
)
2494 // create Excel series object, stock charts need special processing
2495 if( maTypeInfo
.meTypeId
== EXC_CHTYPEID_STOCK
)
2496 CreateAllStockSeries( xChartType
, *aIt
);
2498 CreateDataSeries( xDiagram
, *aIt
);
2504 void XclExpChTypeGroup::ConvertCategSequence( Reference
< XLabeledDataSequence
> xCategSeq
)
2506 for( size_t nIdx
= 0, nSize
= maSeries
.GetSize(); nIdx
< nSize
; ++nIdx
)
2507 maSeries
.GetRecord( nIdx
)->ConvertCategSequence( xCategSeq
);
2510 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet
& rPropSet
)
2512 if( rPropSet
.GetBoolProperty( EXC_CHPROP_SHOW
) )
2514 mxLegend
.reset( new XclExpChLegend( GetChRoot() ) );
2515 mxLegend
->Convert( rPropSet
);
2519 void XclExpChTypeGroup::WriteSubRecords( XclExpStream
& rStrm
)
2521 maType
.Save( rStrm
);
2522 lclSaveRecord( rStrm
, mxChart3d
);
2523 lclSaveRecord( rStrm
, mxLegend
);
2524 lclSaveRecord( rStrm
, mxUpBar
);
2525 lclSaveRecord( rStrm
, mxDownBar
);
2526 for (auto const& it
: m_ChartLines
)
2528 lclSaveRecord( rStrm
, it
.second
.get(), EXC_ID_CHCHARTLINE
, it
.first
);
2532 sal_uInt16
XclExpChTypeGroup::GetFreeFormatIdx() const
2534 return static_cast< sal_uInt16
>( maSeries
.GetSize() );
2537 void XclExpChTypeGroup::CreateDataSeries(
2538 Reference
< XDiagram
> xDiagram
, Reference
< XDataSeries
> xDataSeries
)
2540 // let chart create series object with correct series index
2541 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2544 if( xSeries
->ConvertDataSeries( xDiagram
, xDataSeries
, maTypeInfo
, GetGroupIdx(), GetFreeFormatIdx() ) )
2545 maSeries
.AppendRecord( xSeries
);
2547 GetChartData().RemoveLastSeries();
2551 void XclExpChTypeGroup::CreateAllStockSeries(
2552 Reference
< XChartType
> xChartType
, Reference
< XDataSeries
> xDataSeries
)
2554 // create existing series objects
2555 bool bHasOpen
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_OPENVALUES
, false );
2556 bool bHasHigh
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_HIGHVALUES
, false );
2557 bool bHasLow
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_LOWVALUES
, false );
2558 bool bHasClose
= CreateStockSeries( xDataSeries
, EXC_CHPROP_ROLE_CLOSEVALUES
, !bHasOpen
);
2560 // formatting of special stock chart elements
2561 ScfPropertySet
aTypeProp( xChartType
);
2563 if( bHasHigh
&& bHasLow
&& aTypeProp
.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW
) )
2565 ScfPropertySet
aSeriesProp( xDataSeries
);
2566 XclExpChLineFormatRef
xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2567 xLineFmt
->Convert( GetChRoot(), aSeriesProp
, EXC_CHOBJTYPE_HILOLINE
);
2568 sal_uInt16 nKey
= EXC_CHCHARTLINE_HILO
;
2569 m_ChartLines
.insert(std::make_pair(nKey
, o3tl::make_unique
<XclExpChLineFormat
>(GetChRoot())));
2572 if( bHasOpen
&& bHasClose
)
2574 // dropbar type is dependent on position in the file - always create both
2575 Reference
< XPropertySet
> xWhitePropSet
, xBlackPropSet
;
2576 // white dropbar format
2577 aTypeProp
.GetProperty( xWhitePropSet
, EXC_CHPROP_WHITEDAY
);
2578 ScfPropertySet
aWhiteProp( xWhitePropSet
);
2579 mxUpBar
.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR
) );
2580 mxUpBar
->Convert( aWhiteProp
);
2581 // black dropbar format
2582 aTypeProp
.GetProperty( xBlackPropSet
, EXC_CHPROP_BLACKDAY
);
2583 ScfPropertySet
aBlackProp( xBlackPropSet
);
2584 mxDownBar
.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR
) );
2585 mxDownBar
->Convert( aBlackProp
);
2589 bool XclExpChTypeGroup::CreateStockSeries( Reference
< XDataSeries
> xDataSeries
,
2590 const OUString
& rValueRole
, bool bCloseSymbol
)
2593 // let chart create series object with correct series index
2594 XclExpChSeriesRef xSeries
= GetChartData().CreateSeries();
2597 bOk
= xSeries
->ConvertStockSeries( xDataSeries
,
2598 rValueRole
, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol
);
2600 maSeries
.AppendRecord( xSeries
);
2602 GetChartData().RemoveLastSeries();
2607 void XclExpChTypeGroup::WriteBody( XclExpStream
& rStrm
)
2609 rStrm
.WriteZeroBytes( 16 );
2610 rStrm
<< maData
.mnFlags
<< maData
.mnGroupIdx
;
2613 // Axes =======================================================================
2615 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot
& rRoot
) :
2616 XclExpRecord( EXC_ID_CHLABELRANGE
, 8 ),
2617 XclExpChRoot( rRoot
)
2621 void XclExpChLabelRange::Convert( const ScaleData
& rScaleData
, const ScfPropertySet
& rChart1Axis
, bool bMirrorOrient
)
2623 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2624 chart API allows to detect axis type (date axis, if property exists),
2625 and to receive the base time unit currently used in case the base time
2626 unit is set to 'automatic'. */
2627 cssc::TimeIncrement aTimeIncrement
;
2628 if( rChart1Axis
.GetProperty( aTimeIncrement
, EXC_CHPROP_EXPTIMEINCREMENT
) )
2630 // property exists -> this is a date axis currently
2631 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2633 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2634 bool bAutoBase
= !rScaleData
.TimeIncrement
.TimeResolution
.has
< cssc::TimeIncrement
>();
2635 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOBASE
, bAutoBase
);
2637 // ...but get the current base time unit from the property of the old chart API
2638 sal_Int32 nApiTimeUnit
= 0;
2639 bool bValidBaseUnit
= aTimeIncrement
.TimeResolution
>>= nApiTimeUnit
;
2640 OSL_ENSURE( bValidBaseUnit
, "XclExpChLabelRange::Convert - cannot get base time unit" );
2641 maDateData
.mnBaseUnit
= bValidBaseUnit
? lclGetTimeUnit( nApiTimeUnit
) : EXC_CHDATERANGE_DAYS
;
2643 /* Min/max values depend on base time unit, they specify the number of
2644 days, months, or years starting from null date. */
2645 bool bAutoMin
= lclConvertTimeValue( GetRoot(), maDateData
.mnMinDate
, rScaleData
.Minimum
, maDateData
.mnBaseUnit
);
2646 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMIN
, bAutoMin
);
2647 bool bAutoMax
= lclConvertTimeValue( GetRoot(), maDateData
.mnMaxDate
, rScaleData
.Maximum
, maDateData
.mnBaseUnit
);
2648 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAX
, bAutoMax
);
2651 // automatic axis type detection
2652 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTODATE
, rScaleData
.AutoDateAxis
);
2655 bool bAutoMajor
= lclConvertTimeInterval( maDateData
.mnMajorStep
, maDateData
.mnMajorUnit
, rScaleData
.TimeIncrement
.MajorTimeInterval
);
2656 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMAJOR
, bAutoMajor
);
2657 bool bAutoMinor
= lclConvertTimeInterval( maDateData
.mnMinorStep
, maDateData
.mnMinorUnit
, rScaleData
.TimeIncrement
.MinorTimeInterval
);
2658 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOMINOR
, bAutoMinor
);
2661 double fOrigin
= 0.0;
2662 if( !lclIsAutoAnyOrGetValue( fOrigin
, rScaleData
.Origin
) )
2663 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fOrigin
, 1, 31999 );
2666 if( (rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
) != bMirrorOrient
)
2667 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_REVERSE
);
2670 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2672 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2673 rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
);
2674 double fCrossingPos
= 1.0;
2675 rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
);
2677 bool bDateAxis
= ::get_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_DATEAXIS
);
2680 case cssc::ChartAxisPosition_ZERO
:
2681 case cssc::ChartAxisPosition_START
:
2682 maLabelData
.mnCross
= 1;
2683 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2685 case cssc::ChartAxisPosition_END
:
2686 ::set_flag( maLabelData
.mnFlags
, EXC_CHLABELRANGE_MAXCROSS
);
2688 case cssc::ChartAxisPosition_VALUE
:
2689 maLabelData
.mnCross
= limit_cast
< sal_uInt16
>( fCrossingPos
, 1, 31999 );
2690 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
, false );
2692 maDateData
.mnCross
= lclGetTimeValue( GetRoot(), fCrossingPos
, maDateData
.mnBaseUnit
);
2695 maLabelData
.mnCross
= 1;
2696 ::set_flag( maDateData
.mnFlags
, EXC_CHDATERANGE_AUTOCROSS
);
2700 void XclExpChLabelRange::Save( XclExpStream
& rStrm
)
2702 // the CHLABELRANGE record
2703 XclExpRecord::Save( rStrm
);
2705 // the CHDATERANGE record with date axis settings (BIFF8 only)
2706 if( GetBiff() == EXC_BIFF8
)
2708 rStrm
.StartRecord( EXC_ID_CHDATERANGE
, 18 );
2709 rStrm
<< maDateData
.mnMinDate
2710 << maDateData
.mnMaxDate
2711 << maDateData
.mnMajorStep
2712 << maDateData
.mnMajorUnit
2713 << maDateData
.mnMinorStep
2714 << maDateData
.mnMinorUnit
2715 << maDateData
.mnBaseUnit
2716 << maDateData
.mnCross
2717 << maDateData
.mnFlags
;
2722 void XclExpChLabelRange::WriteBody( XclExpStream
& rStrm
)
2724 rStrm
<< maLabelData
.mnCross
<< maLabelData
.mnLabelFreq
<< maLabelData
.mnTickFreq
<< maLabelData
.mnFlags
;
2727 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot
& rRoot
) :
2728 XclExpRecord( EXC_ID_CHVALUERANGE
, 42 ),
2729 XclExpChRoot( rRoot
)
2733 void XclExpChValueRange::Convert( const ScaleData
& rScaleData
)
2735 // scaling algorithm
2736 bool bLogScale
= ScfApiHelper::GetServiceName( rScaleData
.Scaling
) == "com.sun.star.chart2.LogarithmicScaling";
2737 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, bLogScale
);
2740 bool bAutoMin
= lclIsAutoAnyOrGetScaledValue( maData
.mfMin
, rScaleData
.Minimum
, bLogScale
);
2741 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMIN
, bAutoMin
);
2742 bool bAutoMax
= lclIsAutoAnyOrGetScaledValue( maData
.mfMax
, rScaleData
.Maximum
, bLogScale
);
2743 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAX
, bAutoMax
);
2746 bool bAutoCross
= lclIsAutoAnyOrGetScaledValue( maData
.mfCross
, rScaleData
.Origin
, bLogScale
);
2747 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, bAutoCross
);
2750 const IncrementData
& rIncrementData
= rScaleData
.IncrementData
;
2751 bool bAutoMajor
= lclIsAutoAnyOrGetValue( maData
.mfMajorStep
, rIncrementData
.Distance
) || (maData
.mfMajorStep
<= 0.0);
2752 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMAJOR
, bAutoMajor
);
2754 const Sequence
< SubIncrement
>& rSubIncrementSeq
= rIncrementData
.SubIncrements
;
2755 sal_Int32 nCount
= 0;
2756 bool bAutoMinor
= bLogScale
|| bAutoMajor
|| (rSubIncrementSeq
.getLength() < 1) ||
2757 lclIsAutoAnyOrGetValue( nCount
, rSubIncrementSeq
[ 0 ].IntervalCount
) || (nCount
< 1);
2759 maData
.mfMinorStep
= maData
.mfMajorStep
/ nCount
;
2760 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOMINOR
, bAutoMinor
);
2763 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_REVERSE
, rScaleData
.Orientation
== cssc2::AxisOrientation_REVERSE
);
2766 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet
& rPropSet
)
2768 cssc::ChartAxisPosition eAxisPos
= cssc::ChartAxisPosition_VALUE
;
2769 double fCrossingPos
= 0.0;
2770 if( rPropSet
.GetProperty( eAxisPos
, EXC_CHPROP_CROSSOVERPOSITION
) && rPropSet
.GetProperty( fCrossingPos
, EXC_CHPROP_CROSSOVERVALUE
) )
2774 case cssc::ChartAxisPosition_ZERO
:
2775 case cssc::ChartAxisPosition_START
:
2776 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2778 case cssc::ChartAxisPosition_END
:
2779 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_MAXCROSS
);
2781 case cssc::ChartAxisPosition_VALUE
:
2782 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
, false );
2783 maData
.mfCross
= ::get_flagvalue
< double >( maData
.mnFlags
, EXC_CHVALUERANGE_LOGSCALE
, log( fCrossingPos
) / log( 10.0 ), fCrossingPos
);
2786 ::set_flag( maData
.mnFlags
, EXC_CHVALUERANGE_AUTOCROSS
);
2791 void XclExpChValueRange::WriteBody( XclExpStream
& rStrm
)
2793 rStrm
<< maData
.mfMin
2795 << maData
.mfMajorStep
2796 << maData
.mfMinorStep
2803 sal_uInt8
lclGetXclTickPos( sal_Int32 nApiTickmarks
)
2805 using namespace cssc2::TickmarkStyle
;
2806 sal_uInt8 nXclTickPos
= 0;
2807 ::set_flag( nXclTickPos
, EXC_CHTICK_INSIDE
, ::get_flag( nApiTickmarks
, INNER
) );
2808 ::set_flag( nXclTickPos
, EXC_CHTICK_OUTSIDE
, ::get_flag( nApiTickmarks
, OUTER
) );
2814 XclExpChTick::XclExpChTick( const XclExpChRoot
& rRoot
) :
2815 XclExpRecord( EXC_ID_CHTICK
, (rRoot
.GetBiff() == EXC_BIFF8
) ? 30 : 26 ),
2816 XclExpChRoot( rRoot
),
2817 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT
) )
2821 void XclExpChTick::Convert( const ScfPropertySet
& rPropSet
, const XclChExtTypeInfo
& rTypeInfo
, sal_uInt16 nAxisType
)
2824 sal_Int32 nApiTickmarks
= 0;
2825 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MAJORTICKS
) )
2826 maData
.mnMajor
= lclGetXclTickPos( nApiTickmarks
);
2827 if( rPropSet
.GetProperty( nApiTickmarks
, EXC_CHPROP_MINORTICKS
) )
2828 maData
.mnMinor
= lclGetXclTickPos( nApiTickmarks
);
2831 if( (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) && (nAxisType
== EXC_CHAXIS_X
) )
2833 /* Radar charts disable their category labels via chart type, not via
2834 axis, and axis labels are always 'near axis'. */
2835 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2837 else if( !rPropSet
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
) )
2840 maData
.mnLabelPos
= EXC_CHTICK_NOLABEL
;
2842 else if( rTypeInfo
.mb3dChart
&& (nAxisType
== EXC_CHAXIS_Y
) )
2844 // Excel expects 'near axis' at Y axes in 3D charts
2845 maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2849 cssc::ChartAxisLabelPosition eApiLabelPos
= cssc::ChartAxisLabelPosition_NEAR_AXIS
;
2850 rPropSet
.GetProperty( eApiLabelPos
, EXC_CHPROP_LABELPOSITION
);
2851 switch( eApiLabelPos
)
2853 case cssc::ChartAxisLabelPosition_NEAR_AXIS
:
2854 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
: maData
.mnLabelPos
= EXC_CHTICK_NEXT
; break;
2855 case cssc::ChartAxisLabelPosition_OUTSIDE_START
: maData
.mnLabelPos
= EXC_CHTICK_LOW
; break;
2856 case cssc::ChartAxisLabelPosition_OUTSIDE_END
: maData
.mnLabelPos
= EXC_CHTICK_HIGH
; break;
2857 default: maData
.mnLabelPos
= EXC_CHTICK_NEXT
;
2862 void XclExpChTick::SetFontColor( const Color
& rColor
, sal_uInt32 nColorId
)
2864 maData
.maTextColor
= rColor
;
2865 ::set_flag( maData
.mnFlags
, EXC_CHTICK_AUTOCOLOR
, rColor
== COL_AUTO
);
2866 mnTextColorId
= nColorId
;
2869 void XclExpChTick::SetRotation( sal_uInt16 nRotation
)
2871 maData
.mnRotation
= nRotation
;
2872 ::set_flag( maData
.mnFlags
, EXC_CHTICK_AUTOROT
, false );
2873 ::insert_value( maData
.mnFlags
, XclTools::GetXclOrientFromRot( nRotation
), 2, 3 );
2876 void XclExpChTick::WriteBody( XclExpStream
& rStrm
)
2878 rStrm
<< maData
.mnMajor
2880 << maData
.mnLabelPos
2881 << maData
.mnBackMode
;
2882 rStrm
.WriteZeroBytes( 16 );
2883 rStrm
<< maData
.maTextColor
2885 if( GetBiff() == EXC_BIFF8
)
2886 rStrm
<< GetPalette().GetColorIndex( mnTextColorId
) << maData
.mnRotation
;
2891 /** Returns an API axis object from the passed coordinate system. */
2892 Reference
< XAxis
> lclGetApiAxis( Reference
< XCoordinateSystem
> xCoordSystem
,
2893 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2895 Reference
< XAxis
> xAxis
;
2896 if( (nApiAxisDim
>= 0) && xCoordSystem
.is() ) try
2898 xAxis
= xCoordSystem
->getAxisByDimension( nApiAxisDim
, nApiAxesSetIdx
);
2906 Reference
< cssc::XAxis
> lclGetApiChart1Axis( Reference
< XChartDocument
> xChartDoc
,
2907 sal_Int32 nApiAxisDim
, sal_Int32 nApiAxesSetIdx
)
2909 Reference
< cssc::XAxis
> xChart1Axis
;
2912 Reference
< cssc::XChartDocument
> xChart1Doc( xChartDoc
, UNO_QUERY_THROW
);
2913 Reference
< cssc::XAxisSupplier
> xChart1AxisSupp( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
2914 switch( nApiAxesSetIdx
)
2916 case EXC_CHART_AXESSET_PRIMARY
:
2917 xChart1Axis
= xChart1AxisSupp
->getAxis( nApiAxisDim
);
2919 case EXC_CHART_AXESSET_SECONDARY
:
2920 xChart1Axis
= xChart1AxisSupp
->getSecondaryAxis( nApiAxisDim
);
2932 XclExpChAxis::XclExpChAxis( const XclExpChRoot
& rRoot
, sal_uInt16 nAxisType
) :
2933 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXIS
, EXC_ID_CHAXIS
, 18 ),
2934 mnNumFmtIdx( EXC_FORMAT_NOTFOUND
)
2936 maData
.mnType
= nAxisType
;
2939 void XclExpChAxis::SetFont( XclExpChFontRef xFont
, const Color
& rColor
, sal_uInt32 nColorId
)
2943 mxTick
->SetFontColor( rColor
, nColorId
);
2946 void XclExpChAxis::SetRotation( sal_uInt16 nRotation
)
2949 mxTick
->SetRotation( nRotation
);
2952 void XclExpChAxis::Convert( Reference
< XAxis
> xAxis
, Reference
< XAxis
> xCrossingAxis
,
2953 Reference
< cssc::XAxis
> xChart1Axis
, const XclChExtTypeInfo
& rTypeInfo
)
2955 ScfPropertySet
aAxisProp( xAxis
);
2956 bool bCategoryAxis
= ((GetAxisType() == EXC_CHAXIS_X
) && rTypeInfo
.mbCategoryAxis
) || (GetAxisType() == EXC_CHAXIS_Z
);
2958 // axis line format -------------------------------------------------------
2960 mxAxisLine
.reset( new XclExpChLineFormat( GetChRoot() ) );
2961 mxAxisLine
->Convert( GetChRoot(), aAxisProp
, EXC_CHOBJTYPE_AXISLINE
);
2962 // #i58688# axis enabled
2963 mxAxisLine
->SetShowAxis( aAxisProp
.GetBoolProperty( EXC_CHPROP_SHOW
) );
2965 // axis scaling and increment ---------------------------------------------
2967 ScfPropertySet
aCrossingProp( xCrossingAxis
);
2970 mxLabelRange
.reset( new XclExpChLabelRange( GetChRoot() ) );
2971 mxLabelRange
->SetTicksBetweenCateg( rTypeInfo
.mbTicksBetweenCateg
);
2974 ScfPropertySet
aChart1AxisProp( xChart1Axis
);
2975 // #i71684# radar charts have reversed rotation direction
2976 mxLabelRange
->Convert( xAxis
->getScaleData(), aChart1AxisProp
, (GetAxisType() == EXC_CHAXIS_X
) && (rTypeInfo
.meTypeCateg
== EXC_CHTYPECATEG_RADAR
) );
2978 // get position of crossing axis on this axis from passed axis object
2979 if( aCrossingProp
.Is() )
2980 mxLabelRange
->ConvertAxisPosition( aCrossingProp
);
2984 mxValueRange
.reset( new XclExpChValueRange( GetChRoot() ) );
2986 mxValueRange
->Convert( xAxis
->getScaleData() );
2987 // get position of crossing axis on this axis from passed axis object
2988 if( aCrossingProp
.Is() )
2989 mxValueRange
->ConvertAxisPosition( aCrossingProp
);
2992 // axis caption text ------------------------------------------------------
2994 // axis ticks properties
2995 mxTick
.reset( new XclExpChTick( GetChRoot() ) );
2996 mxTick
->Convert( aAxisProp
, rTypeInfo
, GetAxisType() );
2998 // axis label formatting and rotation
2999 ConvertFontBase( GetChRoot(), aAxisProp
);
3000 ConvertRotationBase( aAxisProp
, true );
3002 // axis number format
3003 sal_Int32 nApiNumFmt
= 0;
3004 if( !bCategoryAxis
&& aAxisProp
.GetProperty( nApiNumFmt
, EXC_CHPROP_NUMBERFORMAT
) )
3005 mnNumFmtIdx
= GetNumFmtBuffer().Insert( static_cast< sal_uInt32
>( nApiNumFmt
) );
3007 // grid -------------------------------------------------------------------
3012 ScfPropertySet
aGridProp( xAxis
->getGridProperties() );
3013 if( aGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3014 mxMajorGrid
= lclCreateLineFormat( GetChRoot(), aGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3016 Sequence
< Reference
< XPropertySet
> > aSubGridPropSeq
= xAxis
->getSubGridProperties();
3017 if( aSubGridPropSeq
.hasElements() )
3019 ScfPropertySet
aSubGridProp( aSubGridPropSeq
[ 0 ] );
3020 if( aSubGridProp
.GetBoolProperty( EXC_CHPROP_SHOW
) )
3021 mxMinorGrid
= lclCreateLineFormat( GetChRoot(), aSubGridProp
, EXC_CHOBJTYPE_GRIDLINE
);
3026 void XclExpChAxis::ConvertWall( css::uno::Reference
< css::chart2::XDiagram
> xDiagram
)
3028 if( xDiagram
.is() ) switch( GetAxisType() )
3032 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3033 mxWallFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_WALL3D
);
3038 ScfPropertySet
aFloorProp( xDiagram
->getFloor() );
3039 mxWallFrame
= lclCreateFrame( GetChRoot(), aFloorProp
, EXC_CHOBJTYPE_FLOOR3D
);
3043 mxWallFrame
.reset();
3047 void XclExpChAxis::WriteSubRecords( XclExpStream
& rStrm
)
3049 lclSaveRecord( rStrm
, mxLabelRange
);
3050 lclSaveRecord( rStrm
, mxValueRange
);
3051 if( mnNumFmtIdx
!= EXC_FORMAT_NOTFOUND
)
3052 XclExpUInt16Record( EXC_ID_CHFORMAT
, mnNumFmtIdx
).Save( rStrm
);
3053 lclSaveRecord( rStrm
, mxTick
);
3054 lclSaveRecord( rStrm
, mxFont
);
3055 lclSaveRecord( rStrm
, mxAxisLine
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_AXISLINE
);
3056 lclSaveRecord( rStrm
, mxMajorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MAJORGRID
);
3057 lclSaveRecord( rStrm
, mxMinorGrid
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_MINORGRID
);
3058 lclSaveRecord( rStrm
, mxWallFrame
, EXC_ID_CHAXISLINE
, EXC_CHAXISLINE_WALLS
);
3061 void XclExpChAxis::WriteBody( XclExpStream
& rStrm
)
3063 rStrm
<< maData
.mnType
;
3064 rStrm
.WriteZeroBytes( 16 );
3067 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot
& rRoot
, sal_uInt16 nAxesSetId
) :
3068 XclExpChGroupBase( rRoot
, EXC_CHFRBLOCK_TYPE_AXESSET
, EXC_ID_CHAXESSET
, 18 )
3070 maData
.mnAxesSetId
= nAxesSetId
;
3071 SetFutureRecordContext( 0, nAxesSetId
);
3073 /* Need to set a reasonable size for the plot area, otherwise Excel will
3074 move away embedded shapes while auto-sizing the plot area. This is just
3075 a wild guess, but will be fixed with implementing manual positioning of
3077 maData
.maRect
.mnX
= 262;
3078 maData
.maRect
.mnY
= 626;
3079 maData
.maRect
.mnWidth
= 3187;
3080 maData
.maRect
.mnHeight
= 2633;
3083 sal_uInt16
XclExpChAxesSet::Convert( Reference
< XDiagram
> xDiagram
, sal_uInt16 nFirstGroupIdx
)
3085 /* First unused chart type group index is passed to be able to continue
3086 counting of chart type groups for secondary axes set. */
3087 sal_uInt16 nGroupIdx
= nFirstGroupIdx
;
3088 Reference
< XCoordinateSystemContainer
> xCoordSysCont( xDiagram
, UNO_QUERY
);
3089 if( xCoordSysCont
.is() )
3091 Sequence
< Reference
< XCoordinateSystem
> > aCoordSysSeq
= xCoordSysCont
->getCoordinateSystems();
3092 if( aCoordSysSeq
.getLength() > 0 )
3094 /* Process first coordinate system only. Import filter puts all
3095 chart types into one coordinate system. */
3096 Reference
< XCoordinateSystem
> xCoordSystem
= aCoordSysSeq
[ 0 ];
3097 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3100 bool b3dChart
= xCoordSystem
.is() && (xCoordSystem
->getDimension() == 3);
3103 namespace ApiAxisType
= cssc2::AxisType
;
3104 Reference
< XAxis
> xApiYAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_Y
, nApiAxesSetIdx
);
3105 bool bPercent
= xApiYAxis
.is() && (xApiYAxis
->getScaleData().AxisType
== ApiAxisType::PERCENT
);
3107 // connector lines in bar charts
3108 ScfPropertySet
aDiaProp( xDiagram
);
3109 bool bConnectBars
= aDiaProp
.GetBoolProperty( EXC_CHPROP_CONNECTBARS
);
3111 // swapped axes sets
3112 ScfPropertySet
aCoordSysProp( xCoordSystem
);
3113 bool bSwappedAxesSet
= aCoordSysProp
.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS
);
3115 // X axis for later use
3116 Reference
< XAxis
> xApiXAxis
= lclGetApiAxis( xCoordSystem
, EXC_CHART_AXIS_X
, nApiAxesSetIdx
);
3118 ScfPropertySet
aXAxisProp( xApiXAxis
);
3119 bool bHasXLabels
= aXAxisProp
.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS
);
3121 // process chart types
3122 Reference
< XChartTypeContainer
> xChartTypeCont( xCoordSystem
, UNO_QUERY
);
3123 if( xChartTypeCont
.is() )
3125 Sequence
< Reference
< XChartType
> > aChartTypeSeq
= xChartTypeCont
->getChartTypes();
3126 const Reference
< XChartType
>* pBeg
= aChartTypeSeq
.getConstArray();
3127 const Reference
< XChartType
>* pEnd
= pBeg
+ aChartTypeSeq
.getLength();
3128 for( const Reference
< XChartType
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
3130 XclExpChTypeGroupRef
xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx
) );
3131 xTypeGroup
->ConvertType( xDiagram
, *pIt
, nApiAxesSetIdx
, b3dChart
, bSwappedAxesSet
, bHasXLabels
);
3132 /* If new chart type group cannot be inserted into a combination
3133 chart with existing type groups, insert all series into last
3134 contained chart type group instead of creating a new group. */
3135 XclExpChTypeGroupRef xLastGroup
= GetLastTypeGroup();
3136 if( xLastGroup
&& !(xTypeGroup
->IsCombinable2d() && xLastGroup
->IsCombinable2d()) )
3138 xLastGroup
->ConvertSeries( xDiagram
, *pIt
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3142 xTypeGroup
->ConvertSeries( xDiagram
, *pIt
, nApiAxesSetIdx
, bPercent
, bConnectBars
);
3143 if( xTypeGroup
->IsValidGroup() )
3145 maTypeGroups
.AppendRecord( xTypeGroup
);
3152 if( XclExpChTypeGroup
* pGroup
= GetFirstTypeGroup().get() )
3154 const XclChExtTypeInfo
& rTypeInfo
= pGroup
->GetTypeInfo();
3156 // create axes according to chart type (no axes for pie and donut charts)
3157 if( rTypeInfo
.meTypeCateg
!= EXC_CHTYPECATEG_PIE
)
3159 ConvertAxis( mxXAxis
, EXC_CHAXIS_X
, mxXAxisTitle
, EXC_CHOBJLINK_XAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_Y
);
3160 ConvertAxis( mxYAxis
, EXC_CHAXIS_Y
, mxYAxisTitle
, EXC_CHOBJLINK_YAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_X
);
3161 if( pGroup
->Is3dDeepChart() )
3162 ConvertAxis( mxZAxis
, EXC_CHAXIS_Z
, mxZAxisTitle
, EXC_CHOBJLINK_ZAXIS
, xCoordSystem
, rTypeInfo
, EXC_CHART_AXIS_NONE
);
3165 // X axis category ranges
3166 if( rTypeInfo
.mbCategoryAxis
&& xApiXAxis
.is() )
3168 const ScaleData aScaleData
= xApiXAxis
->getScaleData();
3169 for( size_t nIdx
= 0, nSize
= maTypeGroups
.GetSize(); nIdx
< nSize
; ++nIdx
)
3170 maTypeGroups
.GetRecord( nIdx
)->ConvertCategSequence( aScaleData
.Categories
);
3174 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3176 Reference
< XLegend
> xLegend
= xDiagram
->getLegend();
3179 ScfPropertySet
aLegendProp( xLegend
);
3180 pGroup
->ConvertLegend( aLegendProp
);
3187 // wall/floor/diagram frame formatting
3188 if( xDiagram
.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY
) )
3190 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3191 if( xTypeGroup
&& xTypeGroup
->Is3dWallChart() )
3193 // wall/floor formatting (3D charts)
3195 mxXAxis
->ConvertWall( xDiagram
);
3197 mxYAxis
->ConvertWall( xDiagram
);
3201 // diagram background formatting
3202 ScfPropertySet
aWallProp( xDiagram
->getWall() );
3203 mxPlotFrame
= lclCreateFrame( GetChRoot(), aWallProp
, EXC_CHOBJTYPE_PLOTFRAME
);
3207 // inner and outer plot area position and size
3210 Reference
< cssc::XChartDocument
> xChart1Doc( GetChartDocument(), UNO_QUERY_THROW
);
3211 Reference
< cssc::XDiagramPositioning
> xPositioning( xChart1Doc
->getDiagram(), UNO_QUERY_THROW
);
3212 // set manual flag in chart data
3213 if( !xPositioning
->isAutomaticDiagramPositioning() )
3214 GetChartData().SetManualPlotArea();
3215 // the CHAXESSET record contains the inner plot area
3216 maData
.maRect
= CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionExcludingAxes() );
3217 // the embedded CHFRAMEPOS record contains the outer plot area
3218 mxFramePos
.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT
, EXC_CHFRAMEPOS_PARENT
) );
3219 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3220 const XclExpChTypeGroup
* pFirstTypeGroup
= GetFirstTypeGroup().get();
3221 bool bPieChart
= pFirstTypeGroup
&& (pFirstTypeGroup
->GetTypeInfo().meTypeCateg
== EXC_CHTYPECATEG_PIE
);
3222 mxFramePos
->GetFramePosData().maRect
= bPieChart
? maData
.maRect
:
3223 CalcChartRectFromHmm( xPositioning
->calculateDiagramPositionIncludingAxes() );
3229 // return first unused chart type group index for next axes set
3233 bool XclExpChAxesSet::Is3dChart() const
3235 XclExpChTypeGroupRef xTypeGroup
= GetFirstTypeGroup();
3236 return xTypeGroup
&& xTypeGroup
->Is3dChart();
3239 void XclExpChAxesSet::WriteSubRecords( XclExpStream
& rStrm
)
3241 lclSaveRecord( rStrm
, mxFramePos
);
3242 lclSaveRecord( rStrm
, mxXAxis
);
3243 lclSaveRecord( rStrm
, mxYAxis
);
3244 lclSaveRecord( rStrm
, mxZAxis
);
3245 lclSaveRecord( rStrm
, mxXAxisTitle
);
3246 lclSaveRecord( rStrm
, mxYAxisTitle
);
3247 lclSaveRecord( rStrm
, mxZAxisTitle
);
3250 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME
).Save( rStrm
);
3251 mxPlotFrame
->Save( rStrm
);
3253 maTypeGroups
.Save( rStrm
);
3256 XclExpChTypeGroupRef
XclExpChAxesSet::GetFirstTypeGroup() const
3258 return maTypeGroups
.GetFirstRecord();
3261 XclExpChTypeGroupRef
XclExpChAxesSet::GetLastTypeGroup() const
3263 return maTypeGroups
.GetLastRecord();
3266 void XclExpChAxesSet::ConvertAxis(
3267 XclExpChAxisRef
& rxChAxis
, sal_uInt16 nAxisType
,
3268 XclExpChTextRef
& rxChAxisTitle
, sal_uInt16 nTitleTarget
,
3269 Reference
< XCoordinateSystem
> xCoordSystem
, const XclChExtTypeInfo
& rTypeInfo
,
3270 sal_Int32 nCrossingAxisDim
)
3272 // create and convert axis object
3273 rxChAxis
.reset( new XclExpChAxis( GetChRoot(), nAxisType
) );
3274 sal_Int32 nApiAxisDim
= rxChAxis
->GetApiAxisDimension();
3275 sal_Int32 nApiAxesSetIdx
= GetApiAxesSetIndex();
3276 Reference
< XAxis
> xAxis
= lclGetApiAxis( xCoordSystem
, nApiAxisDim
, nApiAxesSetIdx
);
3277 Reference
< XAxis
> xCrossingAxis
= lclGetApiAxis( xCoordSystem
, nCrossingAxisDim
, nApiAxesSetIdx
);
3278 Reference
< cssc::XAxis
> xChart1Axis
= lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim
, nApiAxesSetIdx
);
3279 rxChAxis
->Convert( xAxis
, xCrossingAxis
, xChart1Axis
, rTypeInfo
);
3281 // create and convert axis title
3282 Reference
< XTitled
> xTitled( xAxis
, UNO_QUERY
);
3283 rxChAxisTitle
= lclCreateTitle( GetChRoot(), xTitled
, nTitleTarget
);
3286 void XclExpChAxesSet::WriteBody( XclExpStream
& rStrm
)
3288 rStrm
<< maData
.mnAxesSetId
<< maData
.maRect
;
3291 // The chart object ===========================================================
3293 static void lcl_getChartSubTitle(const Reference
<XChartDocument
>& xChartDoc
,
3294 OUString
& rSubTitle
)
3296 Reference
< css::chart::XChartDocument
> xChartDoc1(xChartDoc
, UNO_QUERY
);
3297 if (!xChartDoc1
.is())
3300 Reference
< XPropertySet
> xProp(xChartDoc1
->getSubTitle(), UNO_QUERY
);
3305 Any any
= xProp
->getPropertyValue("String");
3310 XclExpChChart::XclExpChChart( const XclExpRoot
& rRoot
,
3311 Reference
< XChartDocument
> xChartDoc
, const Rectangle
& rChartRect
) :
3312 XclExpChGroupBase( XclExpChRoot( rRoot
, *this ), EXC_CHFRBLOCK_TYPE_CHART
, EXC_ID_CHCHART
, 16 )
3314 Size aPtSize
= OutputDevice::LogicToLogic( rChartRect
.GetSize(), MapMode( MAP_100TH_MM
), MapMode( MAP_POINT
) );
3315 // rectangle is stored in 16.16 fixed-point format
3316 maRect
.mnX
= maRect
.mnY
= 0;
3317 maRect
.mnWidth
= static_cast< sal_Int32
>( aPtSize
.Width() << 16 );
3318 maRect
.mnHeight
= static_cast< sal_Int32
>( aPtSize
.Height() << 16 );
3320 // global chart properties (default values)
3321 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, false );
3322 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_MANPLOTAREA
);
3323 maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
;
3325 // always create both axes set objects
3326 mxPrimAxesSet
.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY
) );
3327 mxSecnAxesSet
.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY
) );
3329 if( xChartDoc
.is() )
3331 Reference
< XDiagram
> xDiagram
= xChartDoc
->getFirstDiagram();
3333 // global chart properties (only 'include hidden cells' attribute for now)
3334 ScfPropertySet
aDiagramProp( xDiagram
);
3335 bool bIncludeHidden
= aDiagramProp
.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS
);
3336 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_SHOWVISIBLEONLY
, !bIncludeHidden
);
3338 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3339 InitConversion( xChartDoc
, rChartRect
);
3342 ScfPropertySet
aFrameProp( xChartDoc
->getPageBackground() );
3343 mxFrame
= lclCreateFrame( GetChRoot(), aFrameProp
, EXC_CHOBJTYPE_BACKGROUND
);
3346 Reference
< XTitled
> xTitled( xChartDoc
, UNO_QUERY
);
3348 lcl_getChartSubTitle(xChartDoc
, aSubTitle
);
3349 mxTitle
= lclCreateTitle( GetChRoot(), xTitled
, EXC_CHOBJLINK_TITLE
,
3350 !aSubTitle
.isEmpty() ? &aSubTitle
: nullptr );
3352 // diagrams (axes sets)
3353 sal_uInt16 nFreeGroupIdx
= mxPrimAxesSet
->Convert( xDiagram
, 0 );
3354 if( !mxPrimAxesSet
->Is3dChart() )
3355 mxSecnAxesSet
->Convert( xDiagram
, nFreeGroupIdx
);
3357 // treatment of missing values
3358 ScfPropertySet
aDiaProp( xDiagram
);
3359 sal_Int32 nMissingValues
= 0;
3360 if( aDiaProp
.GetProperty( nMissingValues
, EXC_CHPROP_MISSINGVALUETREATMENT
) )
3362 using namespace cssc::MissingValueTreatment
;
3363 switch( nMissingValues
)
3365 case LEAVE_GAP
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_SKIP
; break;
3366 case USE_ZERO
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_ZERO
; break;
3367 case CONTINUE
: maProps
.mnEmptyMode
= EXC_CHPROPS_EMPTY_INTERPOLATE
; break;
3371 // finish API conversion
3376 XclExpChSeriesRef
XclExpChChart::CreateSeries()
3378 XclExpChSeriesRef xSeries
;
3379 sal_uInt16 nSeriesIdx
= static_cast< sal_uInt16
>( maSeries
.GetSize() );
3380 if( nSeriesIdx
<= EXC_CHSERIES_MAXSERIES
)
3382 xSeries
.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx
) );
3383 maSeries
.AppendRecord( xSeries
);
3388 void XclExpChChart::RemoveLastSeries()
3390 if( !maSeries
.IsEmpty() )
3391 maSeries
.RemoveRecord( maSeries
.GetSize() - 1 );
3394 void XclExpChChart::SetDataLabel( XclExpChTextRef xText
)
3397 maLabels
.AppendRecord( xText
);
3400 void XclExpChChart::SetManualPlotArea()
3402 // this flag does not exist in BIFF5
3403 if( GetBiff() == EXC_BIFF8
)
3404 ::set_flag( maProps
.mnFlags
, EXC_CHPROPS_USEMANPLOTAREA
);
3407 void XclExpChChart::WriteSubRecords( XclExpStream
& rStrm
)
3409 // background format
3410 lclSaveRecord( rStrm
, mxFrame
);
3413 maSeries
.Save( rStrm
);
3415 // CHPROPERTIES record
3416 rStrm
.StartRecord( EXC_ID_CHPROPERTIES
, 4 );
3417 rStrm
<< maProps
.mnFlags
<< maProps
.mnEmptyMode
<< sal_uInt8( 0 );
3420 // axes sets (always save primary axes set)
3421 sal_uInt16 nUsedAxesSets
= mxSecnAxesSet
->IsValidAxesSet() ? 2 : 1;
3422 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS
, nUsedAxesSets
).Save( rStrm
);
3423 mxPrimAxesSet
->Save( rStrm
);
3424 if( mxSecnAxesSet
->IsValidAxesSet() )
3425 mxSecnAxesSet
->Save( rStrm
);
3427 // chart title and data labels
3428 lclSaveRecord( rStrm
, mxTitle
);
3429 maLabels
.Save( rStrm
);
3432 void XclExpChChart::WriteBody( XclExpStream
& rStrm
)
3437 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot
& rRoot
,
3438 const Reference
< XModel
>& rxModel
, const Size
& rChartSize
) :
3441 if( (rChartSize
.Width() > 0) && (rChartSize
.Height() > 0) )
3443 ScfPropertySet
aPropSet( rxModel
);
3444 Reference
< XShapes
> xShapes
;
3445 if( aPropSet
.GetProperty( xShapes
, EXC_CHPROP_ADDITIONALSHAPES
) && xShapes
.is() && (xShapes
->getCount() > 0) )
3447 /* Create a new independent object manager with own DFF stream for the
3448 DGCONTAINER, pass global manager as parent for shared usage of
3449 global DFF data (picture container etc.). */
3450 mxObjMgr
.reset( new XclExpEmbeddedObjectManager( GetObjectManager(), rChartSize
, EXC_CHART_TOTALUNITS
, EXC_CHART_TOTALUNITS
) );
3451 // initialize the drawing object list
3452 mxObjMgr
->StartSheet();
3453 // process the draw page (convert all shapes)
3454 mxObjRecs
= mxObjMgr
->ProcessDrawing( xShapes
);
3455 // finalize the DFF stream
3456 mxObjMgr
->EndDocument();
3461 XclExpChartDrawing::~XclExpChartDrawing()
3465 void XclExpChartDrawing::Save( XclExpStream
& rStrm
)
3468 mxObjRecs
->Save( rStrm
);
3471 XclExpChart::XclExpChart( const XclExpRoot
& rRoot
, Reference
< XModel
> xModel
, const Rectangle
& rChartRect
) :
3472 XclExpSubStream( EXC_BOF_CHART
),
3475 AppendNewRecord( new XclExpChartPageSettings( rRoot
) );
3476 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT
, false ) );
3477 AppendNewRecord( new XclExpChartDrawing( rRoot
, xModel
, rChartRect
.GetSize() ) );
3478 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS
, EXC_CHUNITS_TWIPS
) );
3480 Reference
< XChartDocument
> xChartDoc( xModel
, UNO_QUERY
);
3481 AppendNewRecord( new XclExpChChart( rRoot
, xChartDoc
, rChartRect
) );
3484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */