1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "xechart.hxx"
28
29 #include <com/sun/star/i18n/XBreakIterator.hpp>
30 #include <com/sun/star/i18n/ScriptType.hpp>
31 #include <com/sun/star/drawing/FillStyle.hpp>
32 #include <com/sun/star/drawing/XShapes.hpp>
33 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
34 #include <com/sun/star/chart/ChartAxisPosition.hpp>
35 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
36 #include <com/sun/star/chart/DataLabelPlacement.hpp>
37 #include <com/sun/star/chart/ErrorBarStyle.hpp>
38 #include <com/sun/star/chart/MissingValueTreatment.hpp>
39 #include <com/sun/star/chart/TimeInterval.hpp>
40 #include <com/sun/star/chart/TimeUnit.hpp>
41 #include <com/sun/star/chart/XAxisSupplier.hpp>
42 #include <com/sun/star/chart/XChartDocument.hpp>
43 #include <com/sun/star/chart/XDiagramPositioning.hpp>
44 #include <com/sun/star/chart2/XChartDocument.hpp>
45 #include <com/sun/star/chart2/XDiagram.hpp>
46 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
47 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
48 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
49 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
50 #include <com/sun/star/chart2/XTitled.hpp>
51 #include <com/sun/star/chart2/XColorScheme.hpp>
52 #include <com/sun/star/chart2/data/XDataSource.hpp>
53 #include <com/sun/star/chart2/AxisType.hpp>
54 #include <com/sun/star/chart2/CurveStyle.hpp>
55 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
56 #include <com/sun/star/chart2/DataPointLabel.hpp>
57 #include <com/sun/star/chart2/LegendPosition.hpp>
58 #include <com/sun/star/chart2/RelativePosition.hpp>
59 #include <com/sun/star/chart2/RelativeSize.hpp>
60 #include <com/sun/star/chart2/StackingDirection.hpp>
61 #include <com/sun/star/chart2/TickmarkStyle.hpp>
62
63 #include <vcl/outdev.hxx>
64 #include <filter/msfilter/escherex.hxx>
65
66 #include "document.hxx"
67 #include "rangelst.hxx"
68 #include "rangeutl.hxx"
69 #include "compiler.hxx"
70 #include "tokenarray.hxx"
71 #include "token.hxx"
72 #include "xeescher.hxx"
73 #include "xeformula.hxx"
74 #include "xehelper.hxx"
75 #include "xepage.hxx"
76 #include "xestyle.hxx"
77
78 using ::rtl::OUString;
79 using ::com::sun::star::uno::Any;
80 using ::com::sun::star::uno::Reference;
81 using ::com::sun::star::uno::Sequence;
82 using ::com::sun::star::uno::UNO_QUERY;
83 using ::com::sun::star::uno::UNO_QUERY_THROW;
84 using ::com::sun::star::uno::UNO_SET_THROW;
85 using ::com::sun::star::uno::Exception;
86 using ::com::sun::star::beans::XPropertySet;
87 using ::com::sun::star::i18n::XBreakIterator;
88 using ::com::sun::star::frame::XModel;
89 using ::com::sun::star::drawing::XShape;
90 using ::com::sun::star::drawing::XShapes;
91
92 using ::com::sun::star::chart2::IncrementData;
93 using ::com::sun::star::chart2::RelativePosition;
94 using ::com::sun::star::chart2::RelativeSize;
95 using ::com::sun::star::chart2::ScaleData;
96 using ::com::sun::star::chart2::SubIncrement;
97 using ::com::sun::star::chart2::XAxis;
98 using ::com::sun::star::chart2::XChartDocument;
99 using ::com::sun::star::chart2::XChartTypeContainer;
100 using ::com::sun::star::chart2::XColorScheme;
101 using ::com::sun::star::chart2::XCoordinateSystem;
102 using ::com::sun::star::chart2::XCoordinateSystemContainer;
103 using ::com::sun::star::chart2::XChartType;
104 using ::com::sun::star::chart2::XDataSeries;
105 using ::com::sun::star::chart2::XDataSeriesContainer;
106 using ::com::sun::star::chart2::XDiagram;
107 using ::com::sun::star::chart2::XFormattedString;
108 using ::com::sun::star::chart2::XLegend;
109 using ::com::sun::star::chart2::XRegressionCurve;
110 using ::com::sun::star::chart2::XRegressionCurveContainer;
111 using ::com::sun::star::chart2::XScaling;
112 using ::com::sun::star::chart2::XTitle;
113 using ::com::sun::star::chart2::XTitled;
114
115 using ::com::sun::star::chart2::data::XDataSequence;
116 using ::com::sun::star::chart2::data::XDataSource;
117 using ::com::sun::star::chart2::data::XLabeledDataSequence;
118
119 using ::formula::FormulaGrammar;
120 using ::formula::FormulaToken;
121
122 namespace cssc = ::com::sun::star::chart;
123 namespace cssc2 = ::com::sun::star::chart2;
124
125 // Helpers ====================================================================
126
127 namespace {
128
operator <<(XclExpStream & rStrm,const XclChRectangle & rRect)129 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
130 {
131 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
132 }
133
lclSaveRecord(XclExpStream & rStrm,XclExpRecordRef xRec)134 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
135 {
136 if( xRec.is() )
137 xRec->Save( rStrm );
138 }
139
140 /** Saves the passed record (group) together with a leading value record. */
141 template< typename Type >
lclSaveRecord(XclExpStream & rStrm,XclExpRecordRef xRec,sal_uInt16 nRecId,Type nValue)142 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
143 {
144 if( xRec.is() )
145 {
146 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
147 xRec->Save( rStrm );
148 }
149 }
150
lclWriteChFrBlockRecord(XclExpStream & rStrm,const XclChFrBlock & rFrBlock,bool bBegin)151 void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
152 {
153 sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
154 rStrm.StartRecord( nRecId, 12 );
155 rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
156 rStrm.EndRecord();
157 }
158
159 template< typename Type >
lclIsAutoAnyOrGetValue(Type & rValue,const Any & rAny)160 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
161 {
162 return !rAny.hasValue() || !(rAny >>= rValue);
163 }
164
lclIsAutoAnyOrGetScaledValue(double & rfValue,const Any & rAny,bool bLogScale)165 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
166 {
167 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
168 if( !bIsAuto && bLogScale )
169 rfValue = log( rfValue ) / log( 10.0 );
170 return bIsAuto;
171 }
172
lclGetTimeValue(const XclExpRoot & rRoot,double fSerialDate,sal_uInt16 nTimeUnit)173 sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit )
174 {
175 DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate );
176 switch( nTimeUnit )
177 {
178 case EXC_CHDATERANGE_DAYS:
179 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
180 case EXC_CHDATERANGE_MONTHS:
181 return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16 );
182 case EXC_CHDATERANGE_YEARS:
183 return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16 );
184 default:
185 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
186 }
187 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
188 }
189
lclConvertTimeValue(const XclExpRoot & rRoot,sal_uInt16 & rnValue,const Any & rAny,sal_uInt16 nTimeUnit)190 bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit )
191 {
192 double fSerialDate = 0;
193 bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny );
194 if( !bAuto )
195 rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit );
196 return bAuto;
197 }
198
lclGetTimeUnit(sal_Int32 nApiTimeUnit)199 sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit )
200 {
201 switch( nApiTimeUnit )
202 {
203 case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS;
204 case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS;
205 case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS;
206 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
207 }
208 return EXC_CHDATERANGE_DAYS;
209 }
210
lclConvertTimeInterval(sal_uInt16 & rnValue,sal_uInt16 & rnTimeUnit,const Any & rAny)211 bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny )
212 {
213 cssc::TimeInterval aInterval;
214 bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny );
215 if( !bAuto )
216 {
217 rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16 );
218 rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit );
219 }
220 return bAuto;
221 }
222
223 } // namespace
224
225 // Common =====================================================================
226
227 /** Stores global data needed in various classes of the Chart export filter. */
228 struct XclExpChRootData : public XclChRootData
229 {
230 typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
231
232 XclExpChChart& mrChartData; /// The chart data object.
233 XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
234 XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
235
XclExpChRootDataXclExpChRootData236 inline explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {}
237
238 /** Registers a new future record level. */
239 void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
240 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
241 void InitializeFutureRecBlock( XclExpStream& rStrm );
242 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
243 void FinalizeFutureRecBlock( XclExpStream& rStrm );
244 };
245
246 // ----------------------------------------------------------------------------
247
RegisterFutureRecBlock(const XclChFrBlock & rFrBlock)248 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
249 {
250 maUnwrittenFrBlocks.push_back( rFrBlock );
251 }
252
InitializeFutureRecBlock(XclExpStream & rStrm)253 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
254 {
255 // first call from a future record writes all missing CHFRBLOCKBEGIN records
256 if( !maUnwrittenFrBlocks.empty() )
257 {
258 // write the leading CHFRINFO record
259 if( maWrittenFrBlocks.empty() )
260 {
261 rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
262 rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
263 rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
264 rStrm.EndRecord();
265 }
266 // write all unwritten CHFRBLOCKBEGIN records
267 for( XclChFrBlockVector::const_iterator aIt = maUnwrittenFrBlocks.begin(), aEnd = maUnwrittenFrBlocks.end(); aIt != aEnd; ++aIt )
268 {
269 DBG_ASSERT( aIt->mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
270 lclWriteChFrBlockRecord( rStrm, *aIt, true );
271 }
272 // move all record infos to vector of written blocks
273 maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
274 maUnwrittenFrBlocks.clear();
275 }
276 }
277
FinalizeFutureRecBlock(XclExpStream & rStrm)278 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
279 {
280 DBG_ASSERT( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
281 if( !maUnwrittenFrBlocks.empty() )
282 {
283 // no future record has been written, just forget the topmost level
284 maUnwrittenFrBlocks.pop_back();
285 }
286 else if( !maWrittenFrBlocks.empty() )
287 {
288 // write the CHFRBLOCKEND record for the topmost block and delete it
289 lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
290 maWrittenFrBlocks.pop_back();
291 }
292 }
293
294 // ----------------------------------------------------------------------------
295
XclExpChRoot(const XclExpRoot & rRoot,XclExpChChart & rChartData)296 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) :
297 XclExpRoot( rRoot ),
298 mxChData( new XclExpChRootData( rChartData ) )
299 {
300 }
301
~XclExpChRoot()302 XclExpChRoot::~XclExpChRoot()
303 {
304 }
305
GetChartDocument() const306 Reference< XChartDocument > XclExpChRoot::GetChartDocument() const
307 {
308 return mxChData->mxChartDoc;
309 }
310
GetChartData() const311 XclExpChChart& XclExpChRoot::GetChartData() const
312 {
313 return mxChData->mrChartData;
314 }
315
GetChartTypeInfo(XclChTypeId eType) const316 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
317 {
318 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
319 }
320
GetChartTypeInfo(const OUString & rServiceName) const321 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
322 {
323 return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName );
324 }
325
GetFormatInfo(XclChObjectType eObjType) const326 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
327 {
328 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
329 }
330
InitConversion(XChartDocRef xChartDoc,const Rectangle & rChartRect) const331 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc, const Rectangle& rChartRect ) const
332 {
333 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
334 }
335
FinishConversion() const336 void XclExpChRoot::FinishConversion() const
337 {
338 mxChData->FinishConversion();
339 }
340
IsSystemColor(const Color & rColor,sal_uInt16 nSysColorIdx) const341 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
342 {
343 XclExpPalette& rPal = GetPalette();
344 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
345 }
346
SetSystemColor(Color & rColor,sal_uInt32 & rnColorId,sal_uInt16 nSysColorIdx) const347 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
348 {
349 DBG_ASSERT( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
350 rColor = GetPalette().GetDefColor( nSysColorIdx );
351 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
352 }
353
CalcChartXFromHmm(sal_Int32 nPosX) const354 sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const
355 {
356 return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS );
357 }
358
CalcChartYFromHmm(sal_Int32 nPosY) const359 sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const
360 {
361 return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS );
362 }
363
CalcChartRectFromHmm(const::com::sun::star::awt::Rectangle & rRect) const364 XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const ::com::sun::star::awt::Rectangle& rRect ) const
365 {
366 XclChRectangle aRect;
367 aRect.mnX = CalcChartXFromHmm( rRect.X );
368 aRect.mnY = CalcChartYFromHmm( rRect.Y );
369 aRect.mnWidth = CalcChartXFromHmm( rRect.Width );
370 aRect.mnHeight = CalcChartYFromHmm( rRect.Height );
371 return aRect;
372 }
373
CalcChartXFromRelative(double fPosX) const374 sal_Int32 XclExpChRoot::CalcChartXFromRelative( double fPosX ) const
375 {
376 return CalcChartXFromHmm( static_cast< sal_Int32 >( fPosX * mxChData->maChartRect.GetWidth() + 0.5 ) );
377 }
378
CalcChartYFromRelative(double fPosY) const379 sal_Int32 XclExpChRoot::CalcChartYFromRelative( double fPosY ) const
380 {
381 return CalcChartYFromHmm( static_cast< sal_Int32 >( fPosY * mxChData->maChartRect.GetHeight() + 0.5 ) );
382 }
383
ConvertLineFormat(XclChLineFormat & rLineFmt,const ScfPropertySet & rPropSet,XclChPropertyMode ePropMode) const384 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
385 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
386 {
387 GetChartPropSetHelper().ReadLineProperties(
388 rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode );
389 }
390
ConvertAreaFormat(XclChAreaFormat & rAreaFmt,const ScfPropertySet & rPropSet,XclChPropertyMode ePropMode) const391 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
392 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
393 {
394 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
395 }
396
ConvertEscherFormat(XclChEscherFormat & rEscherFmt,XclChPicFormat & rPicFmt,const ScfPropertySet & rPropSet,XclChPropertyMode ePropMode) const397 void XclExpChRoot::ConvertEscherFormat(
398 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
399 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
400 {
401 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
402 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode );
403 }
404
ConvertFont(const ScfPropertySet & rPropSet,sal_Int16 nScript) const405 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
406 {
407 XclFontData aFontData;
408 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
409 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
410 }
411
ConvertPieRotation(const ScfPropertySet & rPropSet)412 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
413 {
414 sal_Int32 nApiRot = 0;
415 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
416 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
417 }
418
RegisterFutureRecBlock(const XclChFrBlock & rFrBlock)419 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
420 {
421 mxChData->RegisterFutureRecBlock( rFrBlock );
422 }
423
InitializeFutureRecBlock(XclExpStream & rStrm)424 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
425 {
426 mxChData->InitializeFutureRecBlock( rStrm );
427 }
428
FinalizeFutureRecBlock(XclExpStream & rStrm)429 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
430 {
431 mxChData->FinalizeFutureRecBlock( rStrm );
432 }
433
434 // ----------------------------------------------------------------------------
435
XclExpChGroupBase(const XclExpChRoot & rRoot,sal_uInt16 nFrType,sal_uInt16 nRecId,sal_Size nRecSize)436 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
437 sal_uInt16 nFrType, sal_uInt16 nRecId, sal_Size nRecSize ) :
438 XclExpRecord( nRecId, nRecSize ),
439 XclExpChRoot( rRoot ),
440 maFrBlock( nFrType )
441 {
442 }
443
~XclExpChGroupBase()444 XclExpChGroupBase::~XclExpChGroupBase()
445 {
446 }
447
Save(XclExpStream & rStrm)448 void XclExpChGroupBase::Save( XclExpStream& rStrm )
449 {
450 // header record
451 XclExpRecord::Save( rStrm );
452 // group records
453 if( HasSubRecords() )
454 {
455 // register the future record context corresponding to this record group
456 RegisterFutureRecBlock( maFrBlock );
457 // CHBEGIN record
458 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
459 // embedded records
460 WriteSubRecords( rStrm );
461 // finalize the future records, must be done before the closing CHEND
462 FinalizeFutureRecBlock( rStrm );
463 // CHEND record
464 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
465 }
466 }
467
HasSubRecords() const468 bool XclExpChGroupBase::HasSubRecords() const
469 {
470 return true;
471 }
472
SetFutureRecordContext(sal_uInt16 nFrContext,sal_uInt16 nFrValue1,sal_uInt16 nFrValue2)473 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
474 {
475 maFrBlock.mnContext = nFrContext;
476 maFrBlock.mnValue1 = nFrValue1;
477 maFrBlock.mnValue2 = nFrValue2;
478 }
479
480 // ----------------------------------------------------------------------------
481
XclExpChFutureRecordBase(const XclExpChRoot & rRoot,XclFutureRecType eRecType,sal_uInt16 nRecId,sal_Size nRecSize)482 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
483 XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
484 XclExpFutureRecord( eRecType, nRecId, nRecSize ),
485 XclExpChRoot( rRoot )
486 {
487 }
488
Save(XclExpStream & rStrm)489 void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
490 {
491 InitializeFutureRecBlock( rStrm );
492 XclExpFutureRecord::Save( rStrm );
493 }
494
495 // Frame formatting ===========================================================
496
XclExpChFramePos(sal_uInt16 nTLMode,sal_uInt16 nBRMode)497 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode, sal_uInt16 nBRMode ) :
498 XclExpRecord( EXC_ID_CHFRAMEPOS, 20 )
499 {
500 maData.mnTLMode = nTLMode;
501 maData.mnBRMode = nBRMode;
502 }
503
WriteBody(XclExpStream & rStrm)504 void XclExpChFramePos::WriteBody( XclExpStream& rStrm )
505 {
506 rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect;
507 }
508
509 // ----------------------------------------------------------------------------
510
XclExpChLineFormat(const XclExpChRoot & rRoot)511 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
512 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
513 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
514 {
515 }
516
SetDefault(XclChFrameType eDefFrameType)517 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
518 {
519 switch( eDefFrameType )
520 {
521 case EXC_CHFRAMETYPE_AUTO:
522 SetAuto( true );
523 break;
524 case EXC_CHFRAMETYPE_INVISIBLE:
525 SetAuto( false );
526 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
527 break;
528 default:
529 DBG_ERRORFILE( "XclExpChLineFormat::SetDefault - unknown frame type" );
530 }
531 }
532
Convert(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,XclChObjectType eObjType)533 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
534 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
535 {
536 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
537 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
538 if( HasLine() )
539 {
540 // detect system color, set color identifier (TODO: detect automatic series line)
541 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
542 {
543 // store color index from automatic format data
544 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
545 // try to set automatic mode
546 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
547 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
548 }
549 else
550 {
551 // user defined color - register in palette
552 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
553 }
554 }
555 else
556 {
557 // no line - set default system color
558 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
559 }
560 }
561
IsDefault(XclChFrameType eDefFrameType) const562 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
563 {
564 return
565 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
566 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
567 }
568
WriteBody(XclExpStream & rStrm)569 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
570 {
571 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
572 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
573 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
574 }
575
576 namespace {
577
578 /** Creates a CHLINEFORMAT record from the passed property set. */
lclCreateLineFormat(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,XclChObjectType eObjType)579 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
580 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
581 {
582 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
583 xLineFmt->Convert( rRoot, rPropSet, eObjType );
584 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
585 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
586 xLineFmt.reset();
587 return xLineFmt;
588 }
589
590 } // namespace
591
592 // ----------------------------------------------------------------------------
593
XclExpChAreaFormat(const XclExpChRoot & rRoot)594 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
595 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
596 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
597 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
598 {
599 }
600
Convert(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,XclChObjectType eObjType)601 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
602 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
603 {
604 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
605 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
606 if( HasArea() )
607 {
608 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
609 // detect system color, set color identifier (TODO: detect automatic series area)
610 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
611 {
612 // store color index from automatic format data
613 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
614 // set automatic mode
615 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
616 }
617 else
618 {
619 // user defined color - register color in palette
620 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
621 }
622 // background color (default system color for solid fills)
623 if( bSolid )
624 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
625 else
626 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
627 }
628 else
629 {
630 // no area - set default system colors
631 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
632 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
633 }
634 return bComplexFill;
635 }
636
SetDefault(XclChFrameType eDefFrameType)637 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
638 {
639 switch( eDefFrameType )
640 {
641 case EXC_CHFRAMETYPE_AUTO:
642 SetAuto( true );
643 break;
644 case EXC_CHFRAMETYPE_INVISIBLE:
645 SetAuto( false );
646 maData.mnPattern = EXC_PATT_NONE;
647 break;
648 default:
649 DBG_ERRORFILE( "XclExpChAreaFormat::SetDefault - unknown frame type" );
650 }
651 }
652
IsDefault(XclChFrameType eDefFrameType) const653 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
654 {
655 return
656 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
657 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
658 }
659
WriteBody(XclExpStream & rStrm)660 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
661 {
662 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
663 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
664 {
665 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
666 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
667 }
668 }
669
670 // ----------------------------------------------------------------------------
671
XclExpChEscherFormat(const XclExpChRoot & rRoot)672 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
673 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
674 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
675 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
676 {
677 DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
678 }
679
Convert(const ScfPropertySet & rPropSet,XclChObjectType eObjType)680 void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
681 {
682 const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
683 ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
684 // register colors in palette
685 mnColor1Id = RegisterColor( ESCHER_Prop_fillColor );
686 mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor );
687 }
688
IsValid() const689 bool XclExpChEscherFormat::IsValid() const
690 {
691 return maData.mxEscherSet.is();
692 }
693
Save(XclExpStream & rStrm)694 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
695 {
696 if( maData.mxEscherSet.is() )
697 {
698 // replace RGB colors with palette indexes in the Escher container
699 const XclExpPalette& rPal = GetPalette();
700 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
701 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
702
703 // save the record group
704 XclExpChGroupBase::Save( rStrm );
705 }
706 }
707
HasSubRecords() const708 bool XclExpChEscherFormat::HasSubRecords() const
709 {
710 // no subrecords for gradients
711 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
712 }
713
WriteSubRecords(XclExpStream & rStrm)714 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
715 {
716 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
717 rStrm << maPicFmt.mnBmpMode << sal_uInt16( 0 ) << maPicFmt.mnFlags << maPicFmt.mfScale;
718 rStrm.EndRecord();
719 }
720
RegisterColor(sal_uInt16 nPropId)721 sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
722 {
723 sal_uInt32 nBGRValue;
724 if( maData.mxEscherSet.is() && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
725 {
726 // swap red and blue
727 Color aColor( RGB_COLORDATA(
728 COLORDATA_BLUE( nBGRValue ),
729 COLORDATA_GREEN( nBGRValue ),
730 COLORDATA_RED( nBGRValue ) ) );
731 return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
732 }
733 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
734 }
735
WriteBody(XclExpStream & rStrm)736 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
737 {
738 DBG_ASSERT( maData.mxEscherSet.is(), "XclExpChEscherFormat::WriteBody - missing property container" );
739 // write Escher property container via temporary memory stream
740 SvMemoryStream aMemStrm;
741 maData.mxEscherSet->Commit( aMemStrm );
742 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
743 rStrm.CopyFromStream( aMemStrm );
744 }
745
746 // ----------------------------------------------------------------------------
747
XclExpChFrameBase()748 XclExpChFrameBase::XclExpChFrameBase()
749 {
750 }
751
~XclExpChFrameBase()752 XclExpChFrameBase::~XclExpChFrameBase()
753 {
754 }
755
ConvertFrameBase(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,XclChObjectType eObjType)756 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
757 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
758 {
759 // line format
760 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
761 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
762 // area format (only for frame objects)
763 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
764 {
765 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
766 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
767 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
768 {
769 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
770 mxEscherFmt->Convert( rPropSet, eObjType );
771 if( mxEscherFmt->IsValid() )
772 mxAreaFmt->SetAuto( false );
773 else
774 mxEscherFmt.reset();
775 }
776 }
777 }
778
SetDefaultFrameBase(const XclExpChRoot & rRoot,XclChFrameType eDefFrameType,bool bIsFrame)779 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
780 XclChFrameType eDefFrameType, bool bIsFrame )
781 {
782 // line format
783 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
784 mxLineFmt->SetDefault( eDefFrameType );
785 // area format (only for frame objects)
786 if( bIsFrame )
787 {
788 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
789 mxAreaFmt->SetDefault( eDefFrameType );
790 mxEscherFmt.reset();
791 }
792 }
793
IsDefaultFrameBase(XclChFrameType eDefFrameType) const794 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
795 {
796 return
797 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
798 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
799 }
800
WriteFrameRecords(XclExpStream & rStrm)801 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
802 {
803 lclSaveRecord( rStrm, mxLineFmt );
804 lclSaveRecord( rStrm, mxAreaFmt );
805 lclSaveRecord( rStrm, mxEscherFmt );
806 }
807
808 // ----------------------------------------------------------------------------
809
XclExpChFrame(const XclExpChRoot & rRoot,XclChObjectType eObjType)810 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
811 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
812 meObjType( eObjType )
813 {
814 }
815
Convert(const ScfPropertySet & rPropSet)816 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
817 {
818 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
819 }
820
SetAutoFlags(bool bAutoPos,bool bAutoSize)821 void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize )
822 {
823 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos );
824 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize );
825 }
826
IsDefault() const827 bool XclExpChFrame::IsDefault() const
828 {
829 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
830 }
831
IsDeleteable() const832 bool XclExpChFrame::IsDeleteable() const
833 {
834 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
835 }
836
Save(XclExpStream & rStrm)837 void XclExpChFrame::Save( XclExpStream& rStrm )
838 {
839 switch( meObjType )
840 {
841 // wall/floor frame without CHFRAME header record
842 case EXC_CHOBJTYPE_WALL3D:
843 case EXC_CHOBJTYPE_FLOOR3D:
844 WriteFrameRecords( rStrm );
845 break;
846 default:
847 XclExpChGroupBase::Save( rStrm );
848 }
849 }
850
WriteSubRecords(XclExpStream & rStrm)851 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
852 {
853 WriteFrameRecords( rStrm );
854 }
855
WriteBody(XclExpStream & rStrm)856 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
857 {
858 rStrm << maData.mnFormat << maData.mnFlags;
859 }
860
861 namespace {
862
863 /** Creates a CHFRAME record from the passed property set. */
lclCreateFrame(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,XclChObjectType eObjType)864 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
865 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
866 {
867 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
868 xFrame->Convert( rPropSet );
869 if( xFrame->IsDeleteable() )
870 xFrame.reset();
871 return xFrame;
872 }
873
874 } // namespace
875
876 // Source links ===============================================================
877
878 namespace {
879
lclAddDoubleRefData(ScTokenArray & orArray,const FormulaToken & rToken,SCsTAB nScTab1,SCsCOL nScCol1,SCsROW nScRow1,SCsTAB nScTab2,SCsCOL nScCol2,SCsROW nScRow2)880 void lclAddDoubleRefData(
881 ScTokenArray& orArray, const FormulaToken& rToken,
882 SCsTAB nScTab1, SCsCOL nScCol1, SCsROW nScRow1,
883 SCsTAB nScTab2, SCsCOL nScCol2, SCsROW nScRow2 )
884 {
885 ScComplexRefData aComplexRef;
886 aComplexRef.InitFlags();
887 aComplexRef.Ref1.SetFlag3D( true );
888 aComplexRef.Ref1.nTab = nScTab1;
889 aComplexRef.Ref1.nCol = nScCol1;
890 aComplexRef.Ref1.nRow = nScRow1;
891 aComplexRef.Ref2.nTab = nScTab2;
892 aComplexRef.Ref2.nCol = nScCol2;
893 aComplexRef.Ref2.nRow = nScRow2;
894
895 if( orArray.GetLen() > 0 )
896 orArray.AddOpCode( ocUnion );
897
898 DBG_ASSERT( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),
899 "lclAddDoubleRefData - double reference token expected");
900 if( rToken.GetType() == ::formula::svExternalDoubleRef )
901 orArray.AddExternalDoubleReference( rToken.GetIndex(), rToken.GetString(), aComplexRef );
902 else
903 orArray.AddDoubleReference( aComplexRef );
904 }
905
906 } // namespace
907
908 // ----------------------------------------------------------------------------
909
XclExpChSourceLink(const XclExpChRoot & rRoot,sal_uInt8 nDestType)910 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
911 XclExpRecord( EXC_ID_CHSOURCELINK ),
912 XclExpChRoot( rRoot )
913 {
914 maData.mnDestType = nDestType;
915 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
916 }
917
ConvertDataSequence(Reference<XDataSequence> xDataSeq,bool bSplitToColumns,sal_uInt16 nDefCount)918 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
919 {
920 mxLinkFmla.reset();
921 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
922
923 if( !xDataSeq.is() )
924 return nDefCount;
925
926 // Compile the range representation string into token array. Note that the
927 // source range text depends on the current grammar.
928 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
929 ScCompiler aComp( GetDocPtr(), ScAddress() );
930 aComp.SetGrammar( GetDocPtr()->GetGrammar() );
931 ScTokenArray* pArray = aComp.CompileString( aRangeRepr );
932 if( !pArray )
933 return nDefCount;
934
935 ScTokenArray aArray;
936 sal_uInt32 nValueCount = 0;
937 pArray->Reset();
938 for( const FormulaToken* pToken = pArray->First(); pToken; pToken = pArray->Next() )
939 {
940 switch( pToken->GetType() )
941 {
942 case ::formula::svSingleRef:
943 case ::formula::svExternalSingleRef:
944 // for a single ref token, just add it to the new token array as is
945 if( aArray.GetLen() > 0 )
946 aArray.AddOpCode( ocUnion );
947 aArray.AddToken( *pToken );
948 ++nValueCount;
949 break;
950
951 case ::formula::svDoubleRef:
952 case ::formula::svExternalDoubleRef:
953 {
954 // split 3-dimensional ranges into single sheets
955 const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
956 const ScSingleRefData& rRef1 = rComplexRef.Ref1;
957 const ScSingleRefData& rRef2 = rComplexRef.Ref2;
958 for( SCsTAB nScTab = rRef1.nTab; nScTab <= rRef2.nTab; ++nScTab )
959 {
960 // split 2-dimensional ranges into single columns
961 if( bSplitToColumns && (rRef1.nCol < rRef2.nCol) && (rRef1.nRow < rRef2.nRow) )
962 for( SCsCOL nScCol = rRef1.nCol; nScCol <= rRef2.nCol; ++nScCol )
963 lclAddDoubleRefData( aArray, *pToken, nScTab, nScCol, rRef1.nRow, nScTab, nScCol, rRef2.nRow );
964 else
965 lclAddDoubleRefData( aArray, *pToken, nScTab, rRef1.nCol, rRef1.nRow, nScTab, rRef2.nCol, rRef2.nRow );
966 }
967 sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
968 sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
969 sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
970 nValueCount += nCols * nRows * nTabs;
971 }
972 break;
973
974 default:;
975 }
976 }
977
978 const ScAddress aBaseCell;
979 mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
980 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
981 return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
982 }
983
ConvertStringSequence(const Sequence<Reference<XFormattedString>> & rStringSeq)984 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
985 {
986 mxString.reset();
987 sal_uInt16 nFontIdx = EXC_FONT_APP;
988 if( rStringSeq.hasElements() )
989 {
990 mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
991 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
992 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
993
994 // convert all formatted string entries from the sequence
995 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
996 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
997 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
998 {
999 if( pIt->is() )
1000 {
1001 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
1002 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
1003 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
1004 OUString aText = (*pIt)->getString();
1005 ScfPropertySet aStrProp( *pIt );
1006
1007 // #i63255# get script type for leading weak characters
1008 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
1009
1010 // process all script portions
1011 sal_Int32 nPortionPos = 0;
1012 sal_Int32 nTextLen = aText.getLength();
1013 while( nPortionPos < nTextLen )
1014 {
1015 // get script type and end position of next script portion
1016 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
1017 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
1018
1019 // reuse previous script for following weak portions
1020 if( nScript == ApiScriptType::WEAK )
1021 nScript = nLastScript;
1022
1023 // Excel start position of this portion
1024 sal_uInt16 nXclPortionStart = mxString->Len();
1025 // add portion text to Excel string
1026 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
1027 if( nXclPortionStart < mxString->Len() )
1028 {
1029 // find font index variable dependent on script type
1030 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
1031 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
1032
1033 // insert font into buffer (if not yet done)
1034 if( rnFontIdx == EXC_FONT_NOTFOUND )
1035 rnFontIdx = ConvertFont( aStrProp, nScript );
1036
1037 // insert font index into format run vector
1038 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
1039 }
1040
1041 // go to next script portion
1042 nLastScript = nScript;
1043 nPortionPos = nPortionEnd;
1044 }
1045 }
1046 }
1047 if( !mxString->IsEmpty() )
1048 {
1049 // get leading font index
1050 const XclFormatRunVec& rFormats = mxString->GetFormats();
1051 DBG_ASSERT( !rFormats.empty() && (rFormats.front().mnChar == 0),
1052 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1053 // remove leading format run, if entire string is equally formatted
1054 if( rFormats.size() == 1 )
1055 nFontIdx = mxString->RemoveLeadingFont();
1056 else if( !rFormats.empty() )
1057 nFontIdx = rFormats.front().mnFontIdx;
1058 // add trailing format run, if string is rich-formatted
1059 if( mxString->IsRich() )
1060 mxString->AppendTrailingFormat( EXC_FONT_APP );
1061 }
1062 }
1063 return nFontIdx;
1064 }
1065
ConvertNumFmt(const ScfPropertySet & rPropSet,bool bPercent)1066 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
1067 {
1068 sal_Int32 nApiNumFmt = 0;
1069 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
1070 {
1071 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
1072 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
1073 }
1074 }
1075
Save(XclExpStream & rStrm)1076 void XclExpChSourceLink::Save( XclExpStream& rStrm )
1077 {
1078 // CHFORMATRUNS record
1079 if( mxString.is() && mxString->IsRich() )
1080 {
1081 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
1082 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
1083 mxString->WriteFormats( rStrm, true );
1084 rStrm.EndRecord();
1085 }
1086 // CHSOURCELINK record
1087 XclExpRecord::Save( rStrm );
1088 // CHSTRING record
1089 if( mxString.is() && !mxString->IsEmpty() )
1090 {
1091 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
1092 rStrm << sal_uInt16( 0 ) << *mxString;
1093 rStrm.EndRecord();
1094 }
1095 }
1096
WriteBody(XclExpStream & rStrm)1097 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
1098 {
1099 rStrm << maData.mnDestType
1100 << maData.mnLinkType
1101 << maData.mnFlags
1102 << maData.mnNumFmtIdx
1103 << mxLinkFmla;
1104 }
1105
1106 // Text =======================================================================
1107
XclExpChFont(sal_uInt16 nFontIdx)1108 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
1109 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
1110 {
1111 }
1112
1113 // ----------------------------------------------------------------------------
1114
XclExpChObjectLink(sal_uInt16 nLinkTarget,const XclChDataPointPos & rPointPos)1115 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
1116 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
1117 {
1118 maData.mnTarget = nLinkTarget;
1119 maData.maPointPos = rPointPos;
1120 }
1121
WriteBody(XclExpStream & rStrm)1122 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
1123 {
1124 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
1125 }
1126
1127 // ----------------------------------------------------------------------------
1128
XclExpChFrLabelProps(const XclExpChRoot & rRoot)1129 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
1130 XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
1131 {
1132 }
1133
Convert(const ScfPropertySet & rPropSet,bool bShowSeries,bool bShowCateg,bool bShowValue,bool bShowPercent,bool bShowBubble)1134 void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, bool bShowSeries,
1135 bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
1136 {
1137 // label value flags
1138 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, bShowSeries );
1139 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
1140 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
1141 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
1142 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
1143
1144 // label value separator
1145 rPropSet.GetStringProperty( maData.maSeparator, EXC_CHPROP_LABELSEPARATOR );
1146 if( maData.maSeparator.Len() == 0 )
1147 maData.maSeparator = String( sal_Unicode( ' ' ) );
1148 }
1149
WriteBody(XclExpStream & rStrm)1150 void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
1151 {
1152 XclExpString aXclSep( maData.maSeparator, EXC_STR_FORCEUNICODE | EXC_STR_SMARTFLAGS );
1153 rStrm << maData.mnFlags << aXclSep;
1154 }
1155
1156 // ----------------------------------------------------------------------------
1157
~XclExpChFontBase()1158 XclExpChFontBase::~XclExpChFontBase()
1159 {
1160 }
1161
ConvertFontBase(const XclExpChRoot & rRoot,sal_uInt16 nFontIdx)1162 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
1163 {
1164 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
1165 {
1166 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
1167 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
1168 }
1169 }
1170
ConvertFontBase(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet)1171 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
1172 {
1173 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
1174 }
1175
ConvertRotationBase(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,bool bSupportsStacked)1176 void XclExpChFontBase::ConvertRotationBase(
1177 const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet, bool bSupportsStacked )
1178 {
1179 sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet, bSupportsStacked );
1180 SetRotation( nRotation );
1181 }
1182
1183 // ----------------------------------------------------------------------------
1184
XclExpChText(const XclExpChRoot & rRoot)1185 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
1186 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
1187 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
1188 {
1189 }
1190
SetFont(XclExpChFontRef xFont,const Color & rColor,sal_uInt32 nColorId)1191 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
1192 {
1193 mxFont = xFont;
1194 maData.maTextColor = rColor;
1195 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
1196 mnTextColorId = nColorId;
1197 }
1198
SetRotation(sal_uInt16 nRotation)1199 void XclExpChText::SetRotation( sal_uInt16 nRotation )
1200 {
1201 maData.mnRotation = nRotation;
1202 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
1203 }
1204
ConvertTitle(Reference<XTitle> xTitle,sal_uInt16 nTarget)1205 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget )
1206 {
1207 switch( nTarget )
1208 {
1209 case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
1210 case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
1211 case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 0 ); break;
1212 case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
1213 }
1214
1215 mxSrcLink.reset();
1216 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
1217
1218 if( xTitle.is() )
1219 {
1220 // title frame formatting
1221 ScfPropertySet aTitleProp( xTitle );
1222 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1223
1224 // string sequence
1225 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1226 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1227 ConvertFontBase( GetChRoot(), nFontIdx );
1228
1229 // rotation
1230 ConvertRotationBase( GetChRoot(), aTitleProp, true );
1231
1232 // manual text position - only for main title
1233 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
1234 if( nTarget == EXC_CHOBJLINK_TITLE )
1235 {
1236 Any aRelPos;
1237 if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION ) && aRelPos.has< RelativePosition >() ) try
1238 {
1239 // calculate absolute position for CHTEXT record
1240 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
1241 Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW );
1242 ::com::sun::star::awt::Point aPos = xTitleShape->getPosition();
1243 ::com::sun::star::awt::Size aSize = xTitleShape->getSize();
1244 ::com::sun::star::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height );
1245 maData.maRect = CalcChartRectFromHmm( aRect );
1246 ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 );
1247 // manual title position implies manual plot area
1248 GetChartData().SetManualPlotArea();
1249 // calculate the default title position in chart units
1250 sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 );
1251 sal_Int32 nDefPosY = 85;
1252 // set the position relative to the standard position
1253 XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect;
1254 rFrameRect.mnX = maData.maRect.mnX - nDefPosX;
1255 rFrameRect.mnY = maData.maRect.mnY - nDefPosY;
1256 }
1257 catch( Exception& )
1258 {
1259 }
1260 }
1261 }
1262 else
1263 {
1264 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1265 }
1266 }
1267
ConvertLegend(const ScfPropertySet & rPropSet)1268 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1269 {
1270 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1271 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1272 ConvertFontBase( GetChRoot(), rPropSet );
1273 }
1274
ConvertDataLabel(const ScfPropertySet & rPropSet,const XclChTypeInfo & rTypeInfo,const XclChDataPointPos & rPointPos)1275 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1276 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1277 {
1278 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
1279
1280 cssc2::DataPointLabel aPointLabel;
1281 if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1282 return false;
1283
1284 // percentage only allowed in pie and donut charts
1285 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1286 // bubble sizes only allowed in bubble charts
1287 bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
1288 DBG_ASSERT( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1289
1290 // raw show flags
1291 bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1292 bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
1293 bool bShowCateg = aPointLabel.ShowCategoryName;
1294 bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1295 bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
1296
1297 // create the CHFRLABELPROPS record for extended settings in BIFF8
1298 if( bShowAny && (GetBiff() == EXC_BIFF8) )
1299 {
1300 mxLabelProps.reset( new XclExpChFrLabelProps( GetChRoot() ) );
1301 mxLabelProps->Convert( rPropSet, false, bShowCateg, bShowValue, bShowPercent, bShowBubble );
1302 }
1303
1304 // restrict to combinations allowed in CHTEXT
1305 if( bShowPercent ) bShowValue = false; // percent wins over value
1306 if( bShowValue ) bShowCateg = false; // value wins over category
1307 if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
1308
1309 // set all flags
1310 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1311 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1312 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1313 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1314 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1315 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
1316 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
1317 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1318
1319 if( bShowAny )
1320 {
1321 // font settings
1322 ConvertFontBase( GetChRoot(), rPropSet );
1323 ConvertRotationBase( GetChRoot(), rPropSet, false );
1324 // label placement
1325 sal_Int32 nPlacement = 0;
1326 sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO;
1327 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1328 {
1329 using namespace cssc::DataLabelPlacement;
1330 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1331 {
1332 nLabelPos = EXC_CHTEXT_POS_DEFAULT;
1333 }
1334 else switch( nPlacement )
1335 {
1336 case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break;
1337 case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break;
1338 case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break;
1339 case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1340 case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1341 case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1342 case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break;
1343 case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1344 case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1345 case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1346 case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break;
1347 case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break;
1348 case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break;
1349 default: DBG_ERRORFILE( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1350 }
1351 }
1352 ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 );
1353 // source link (contains number format)
1354 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1355 if( bShowValue || bShowPercent )
1356 // percentage format wins over value format
1357 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1358 // object link
1359 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1360 }
1361
1362 /* Return true to indicate valid label settings:
1363 - for existing labels at entire series
1364 - for any settings at single data point (to be able to delete a point label) */
1365 return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
1366 }
1367
ConvertTrendLineEquation(const ScfPropertySet & rPropSet,const XclChDataPointPos & rPointPos)1368 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1369 {
1370 // required flags
1371 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1372 if( GetBiff() == EXC_BIFF8 )
1373 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1374 // frame formatting
1375 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1376 // font settings
1377 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1378 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1379 ConvertFontBase( GetChRoot(), rPropSet );
1380 // source link (contains number format)
1381 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1382 mxSrcLink->ConvertNumFmt( rPropSet, false );
1383 // object link
1384 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1385 }
1386
GetAttLabelFlags() const1387 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1388 {
1389 sal_uInt16 nFlags = 0;
1390 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1391 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1392 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1393 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1394 return nFlags;
1395 }
1396
WriteSubRecords(XclExpStream & rStrm)1397 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1398 {
1399 // CHFRAMEPOS record
1400 lclSaveRecord( rStrm, mxFramePos );
1401 // CHFONT record
1402 lclSaveRecord( rStrm, mxFont );
1403 // CHSOURCELINK group
1404 lclSaveRecord( rStrm, mxSrcLink );
1405 // CHFRAME group
1406 lclSaveRecord( rStrm, mxFrame );
1407 // CHOBJECTLINK record
1408 lclSaveRecord( rStrm, mxObjLink );
1409 // CHFRLABELPROPS record
1410 lclSaveRecord( rStrm, mxLabelProps );
1411 }
1412
WriteBody(XclExpStream & rStrm)1413 void XclExpChText::WriteBody( XclExpStream& rStrm )
1414 {
1415 rStrm << maData.mnHAlign
1416 << maData.mnVAlign
1417 << maData.mnBackMode
1418 << maData.maTextColor
1419 << maData.maRect
1420 << maData.mnFlags;
1421
1422 if( GetBiff() == EXC_BIFF8 )
1423 {
1424 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1425 << maData.mnFlags2
1426 << maData.mnRotation;
1427 }
1428 }
1429
1430 // ----------------------------------------------------------------------------
1431
1432 namespace {
1433
1434 /** Creates and returns an Excel text object from the passed title. */
lclCreateTitle(const XclExpChRoot & rRoot,Reference<XTitled> xTitled,sal_uInt16 nTarget)1435 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget )
1436 {
1437 Reference< XTitle > xTitle;
1438 if( xTitled.is() )
1439 xTitle = xTitled->getTitleObject();
1440
1441 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1442 xText->ConvertTitle( xTitle, nTarget );
1443 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1444 will be interpreted as auto-generated title showing the series title in
1445 charts that contain exactly one data series. */
1446 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1447 xText.reset();
1448
1449 return xText;
1450 }
1451
1452 }
1453
1454 // Data series ================================================================
1455
XclExpChMarkerFormat(const XclExpChRoot & rRoot)1456 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1457 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1458 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1459 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1460 {
1461 }
1462
Convert(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,sal_uInt16 nFormatIdx)1463 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1464 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1465 {
1466 rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1467 /* Set marker line/fill color to series line color.
1468 TODO: remove this if OOChart supports own colors in markers. */
1469 Color aLineColor;
1470 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1471 maData.maLineColor = maData.maFillColor = aLineColor;
1472 // register colors in palette
1473 RegisterColors( rRoot );
1474 }
1475
ConvertStockSymbol(const XclExpChRoot & rRoot,const ScfPropertySet & rPropSet,bool bCloseSymbol)1476 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1477 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1478 {
1479 // clear the automatic flag
1480 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1481 // symbol type and color
1482 if( bCloseSymbol )
1483 {
1484 // set symbol type for the 'close' data series
1485 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1486 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1487 // set symbol line/fill color to series line color
1488 Color aLineColor;
1489 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1490 {
1491 maData.maLineColor = maData.maFillColor = aLineColor;
1492 RegisterColors( rRoot );
1493 }
1494 }
1495 else
1496 {
1497 // set invisible symbol
1498 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1499 }
1500 }
1501
RegisterColors(const XclExpChRoot & rRoot)1502 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1503 {
1504 if( HasMarker() )
1505 {
1506 if( HasLineColor() )
1507 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1508 if( HasFillColor() )
1509 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1510 }
1511 }
1512
WriteBody(XclExpStream & rStrm)1513 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1514 {
1515 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1516 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1517 {
1518 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1519 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1520 }
1521 }
1522
1523 // ----------------------------------------------------------------------------
1524
XclExpChPieFormat()1525 XclExpChPieFormat::XclExpChPieFormat() :
1526 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1527 {
1528 }
1529
Convert(const ScfPropertySet & rPropSet)1530 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1531 {
1532 double fApiDist(0.0);
1533 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1534 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1535 }
1536
1537 // ----------------------------------------------------------------------------
1538
XclExpCh3dDataFormat()1539 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1540 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1541 {
1542 }
1543
Convert(const ScfPropertySet & rPropSet)1544 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1545 {
1546 sal_Int32 nApiType(0);
1547 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1548 {
1549 using namespace cssc2::DataPointGeometry3D;
1550 switch( nApiType )
1551 {
1552 case CUBOID:
1553 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1554 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1555 break;
1556 case PYRAMID:
1557 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1558 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1559 break;
1560 case CYLINDER:
1561 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1562 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1563 break;
1564 case CONE:
1565 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1566 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1567 break;
1568 default:
1569 DBG_ERRORFILE( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1570 }
1571 }
1572 }
1573
WriteBody(XclExpStream & rStrm)1574 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1575 {
1576 rStrm << maData.mnBase << maData.mnTop;
1577 }
1578
1579 // ----------------------------------------------------------------------------
1580
XclExpChAttachedLabel(sal_uInt16 nFlags)1581 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1582 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1583 {
1584 }
1585
1586 // ----------------------------------------------------------------------------
1587
XclExpChDataFormat(const XclExpChRoot & rRoot,const XclChDataPointPos & rPointPos,sal_uInt16 nFormatIdx)1588 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1589 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1590 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
1591 {
1592 maData.maPointPos = rPointPos;
1593 maData.mnFormatIdx = nFormatIdx;
1594 }
1595
ConvertDataSeries(const ScfPropertySet & rPropSet,const XclChExtTypeInfo & rTypeInfo)1596 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1597 {
1598 // line and area formatting
1599 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1600
1601 // data point symbols
1602 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1603 if( !bIsFrame )
1604 {
1605 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1606 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1607 }
1608
1609 // pie segments
1610 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1611 {
1612 mxPieFmt.reset( new XclExpChPieFormat );
1613 mxPieFmt->Convert( rPropSet );
1614 }
1615
1616 // 3D bars (only allowed for entire series in BIFF8)
1617 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1618 {
1619 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1620 mx3dDataFmt->Convert( rPropSet );
1621 }
1622
1623 // spline
1624 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1625 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1626
1627 // data point labels
1628 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1629 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1630 {
1631 // CHTEXT groups for data labels are stored in global CHCHART group
1632 GetChartData().SetDataLabel( xLabel );
1633 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1634 }
1635 }
1636
ConvertStockSeries(const ScfPropertySet & rPropSet,bool bCloseSymbol)1637 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1638 {
1639 // set line format to invisible
1640 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1641 // set symbols to invisible or to 'close' series symbol
1642 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1643 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1644 }
1645
ConvertLine(const ScfPropertySet & rPropSet,XclChObjectType eObjType)1646 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1647 {
1648 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1649 }
1650
WriteSubRecords(XclExpStream & rStrm)1651 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1652 {
1653 lclSaveRecord( rStrm, mx3dDataFmt );
1654 WriteFrameRecords( rStrm );
1655 lclSaveRecord( rStrm, mxPieFmt );
1656 lclSaveRecord( rStrm, mxMarkerFmt );
1657 lclSaveRecord( rStrm, mxSeriesFmt );
1658 lclSaveRecord( rStrm, mxAttLabel );
1659 }
1660
WriteBody(XclExpStream & rStrm)1661 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1662 {
1663 rStrm << maData.maPointPos.mnPointIdx
1664 << maData.maPointPos.mnSeriesIdx
1665 << maData.mnFormatIdx
1666 << maData.mnFlags;
1667 }
1668
1669 // ----------------------------------------------------------------------------
1670
XclExpChSerTrendLine(const XclExpChRoot & rRoot)1671 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1672 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1673 XclExpChRoot( rRoot )
1674 {
1675 }
1676
Convert(Reference<XRegressionCurve> xRegCurve,sal_uInt16 nSeriesIdx)1677 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1678 {
1679 if( !xRegCurve.is() )
1680 return false;
1681
1682 // trend line type
1683 ScfPropertySet aCurveProp( xRegCurve );
1684 OUString aService = aCurveProp.GetServiceName();
1685 if( aService == SERVICE_CHART2_LINEARREGCURVE )
1686 {
1687 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1688 maData.mnOrder = 1;
1689 }
1690 else if( aService == SERVICE_CHART2_EXPREGCURVE )
1691 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1692 else if( aService == SERVICE_CHART2_LOGREGCURVE )
1693 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1694 else if( aService == SERVICE_CHART2_POTREGCURVE )
1695 maData.mnLineType = EXC_CHSERTREND_POWER;
1696 else
1697 return false;
1698
1699 // line formatting
1700 XclChDataPointPos aPointPos( nSeriesIdx );
1701 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1702 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1703
1704 // #i83100# show equation and correlation coefficient
1705 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1706 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1707 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1708
1709 // #i83100# formatting of the equation text box
1710 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1711 {
1712 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1713 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1714 }
1715
1716 // missing features
1717 // #i20819# polynomial trend lines
1718 // #i66819# moving average trend lines
1719 // #i5085# manual trend line size
1720 // #i34093# manual crossing point
1721 return true;
1722 }
1723
WriteBody(XclExpStream & rStrm)1724 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1725 {
1726 rStrm << maData.mnLineType
1727 << maData.mnOrder
1728 << maData.mfIntercept
1729 << maData.mnShowEquation
1730 << maData.mnShowRSquared
1731 << maData.mfForecastFor
1732 << maData.mfForecastBack;
1733 }
1734
1735 // ----------------------------------------------------------------------------
1736
XclExpChSerErrorBar(const XclExpChRoot & rRoot,sal_uInt8 nBarType)1737 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1738 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1739 XclExpChRoot( rRoot )
1740 {
1741 maData.mnBarType = nBarType;
1742 }
1743
Convert(XclExpChSourceLink & rValueLink,sal_uInt16 & rnValueCount,const ScfPropertySet & rPropSet)1744 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1745 {
1746 sal_Int32 nBarStyle = 0;
1747 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1748 if( bOk )
1749 {
1750 switch( nBarStyle )
1751 {
1752 case cssc::ErrorBarStyle::ABSOLUTE:
1753 maData.mnSourceType = EXC_CHSERERR_FIXED;
1754 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1755 break;
1756 case cssc::ErrorBarStyle::RELATIVE:
1757 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1758 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1759 break;
1760 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1761 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1762 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1763 break;
1764 case cssc::ErrorBarStyle::STANDARD_ERROR:
1765 maData.mnSourceType = EXC_CHSERERR_STDERR;
1766 break;
1767 case cssc::ErrorBarStyle::FROM_DATA:
1768 {
1769 bOk = false;
1770 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1771 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1772 if( xDataSource.is() )
1773 {
1774 // find first sequence with current role
1775 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1776 Reference< XDataSequence > xValueSeq;
1777
1778 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1779 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1780 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1781 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1782 {
1783 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1784 ScfPropertySet aValueProp( xTmpValueSeq );
1785 OUString aCurrRole;
1786 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1787 xValueSeq = xTmpValueSeq;
1788 }
1789 if( xValueSeq.is() )
1790 {
1791 // #i86465# pass value count back to series
1792 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1793 bOk = maData.mnValueCount > 0;
1794 }
1795 }
1796 }
1797 break;
1798 default:
1799 bOk = false;
1800 }
1801 }
1802 return bOk;
1803 }
1804
WriteBody(XclExpStream & rStrm)1805 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1806 {
1807 rStrm << maData.mnBarType
1808 << maData.mnSourceType
1809 << maData.mnLineEnd
1810 << sal_uInt8( 1 ) // must be 1 to make line visible
1811 << maData.mfValue
1812 << maData.mnValueCount;
1813 }
1814
1815 // ----------------------------------------------------------------------------
1816
1817 namespace {
1818
1819 /** Returns the property set of the specified data point. */
lclGetPointPropSet(Reference<XDataSeries> xDataSeries,sal_Int32 nPointIdx)1820 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1821 {
1822 ScfPropertySet aPropSet;
1823 try
1824 {
1825 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1826 }
1827 catch( Exception& )
1828 {
1829 DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1830 }
1831 return aPropSet;
1832 }
1833
1834 } // namespace
1835
XclExpChSeries(const XclExpChRoot & rRoot,sal_uInt16 nSeriesIdx)1836 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1837 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1838 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1839 mnSeriesIdx( nSeriesIdx ),
1840 mnParentIdx( EXC_CHSERIES_INVALID )
1841 {
1842 // CHSOURCELINK records are always required, even if unused
1843 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1844 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1845 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1846 if( GetBiff() == EXC_BIFF8 )
1847 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1848 }
1849
ConvertDataSeries(Reference<XDiagram> xDiagram,Reference<XDataSeries> xDataSeries,const XclChExtTypeInfo & rTypeInfo,sal_uInt16 nGroupIdx,sal_uInt16 nFormatIdx)1850 bool XclExpChSeries::ConvertDataSeries(
1851 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1852 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1853 {
1854 bool bOk = false;
1855 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1856 if( xDataSource.is() )
1857 {
1858 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
1859
1860 // find first sequence with role 'values-y'
1861 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1862 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1863 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1864 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1865 {
1866 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1867 ScfPropertySet aValueProp( xTmpValueSeq );
1868 OUString aRole;
1869 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1870 {
1871 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1872 {
1873 xYValueSeq = xTmpValueSeq;
1874 if( !xTitleSeq.is() )
1875 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1876 }
1877 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1878 {
1879 xXValueSeq = xTmpValueSeq;
1880 }
1881 else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES) )
1882 {
1883 xBubbleSeq = xTmpValueSeq;
1884 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1885 }
1886 }
1887 }
1888
1889 bOk = xYValueSeq.is();
1890 if( bOk )
1891 {
1892 // chart type group index
1893 mnGroupIdx = nGroupIdx;
1894
1895 // convert source links
1896 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1897 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1898
1899 // X values of XY charts
1900 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1901
1902 // size values of bubble charts
1903 if( mxBubbleLink.is() )
1904 mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
1905
1906 // series formatting
1907 XclChDataPointPos aPointPos( mnSeriesIdx );
1908 ScfPropertySet aSeriesProp( xDataSeries );
1909 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1910 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1911
1912 // trend lines
1913 CreateTrendLines( xDataSeries );
1914
1915 // error bars
1916 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1917 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1918
1919 if( maData.mnValueCount > 0 )
1920 {
1921 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1922
1923 /* #i91063# Create missing fill properties in pie/doughnut charts.
1924 If freshly created (never saved to ODF), these charts show
1925 varying point colors but do not return these points via API. */
1926 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1927 {
1928 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1929 if( xColorScheme.is() )
1930 {
1931 const OUString aFillStyleName = CREATE_OUSTRING( "FillStyle" );
1932 const OUString aColorName = CREATE_OUSTRING( "Color" );
1933 namespace cssd = ::com::sun::star::drawing;
1934 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1935 {
1936 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1937 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1938 // test that the point fill style is solid, but no color is set
1939 cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
1940 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1941 (eFillStyle == cssd::FillStyle_SOLID) &&
1942 !aPointProp.HasProperty( aColorName ) )
1943 {
1944 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1945 }
1946 }
1947 }
1948 }
1949
1950 // data point formatting
1951 Sequence< sal_Int32 > aPointIndexes;
1952 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1953 {
1954 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1955 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1956 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1957 {
1958 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1959 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1960 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1961 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1962 maPointFmts.AppendRecord( xPointFmt );
1963 }
1964 }
1965 }
1966 }
1967 }
1968 return bOk;
1969 }
1970
ConvertStockSeries(XDataSeriesRef xDataSeries,const OUString & rValueRole,sal_uInt16 nGroupIdx,sal_uInt16 nFormatIdx,bool bCloseSymbol)1971 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1972 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1973 {
1974 bool bOk = false;
1975 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1976 if( xDataSource.is() )
1977 {
1978 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1979
1980 // find first sequence with passed role
1981 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1982 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1983 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1984 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1985 {
1986 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1987 ScfPropertySet aValueProp( xTmpValueSeq );
1988 OUString aRole;
1989 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
1990 {
1991 xYValueSeq = xTmpValueSeq;
1992 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1993 }
1994 }
1995
1996 bOk = xYValueSeq.is();
1997 if( bOk )
1998 {
1999 // chart type group index
2000 mnGroupIdx = nGroupIdx;
2001 // convert source links
2002 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
2003 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
2004 // series formatting
2005 ScfPropertySet aSeriesProp( xDataSeries );
2006 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
2007 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
2008 }
2009 }
2010 return bOk;
2011 }
2012
ConvertTrendLine(const XclExpChSeries & rParent,Reference<XRegressionCurve> xRegCurve)2013 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
2014 {
2015 InitFromParent( rParent );
2016 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
2017 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
2018 if( bOk )
2019 {
2020 mxSeriesFmt = mxTrendLine->GetDataFormat();
2021 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
2022 }
2023 return bOk;
2024 }
2025
ConvertErrorBar(const XclExpChSeries & rParent,const ScfPropertySet & rPropSet,sal_uInt8 nBarId)2026 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
2027 {
2028 InitFromParent( rParent );
2029 // error bar settings
2030 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
2031 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
2032 if( bOk )
2033 {
2034 // error bar formatting
2035 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
2036 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
2037 }
2038 return bOk;
2039 }
2040
ConvertCategSequence(Reference<XLabeledDataSequence> xCategSeq)2041 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2042 {
2043 if( xCategSeq.is() )
2044 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
2045 }
2046
WriteSubRecords(XclExpStream & rStrm)2047 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
2048 {
2049 lclSaveRecord( rStrm, mxTitleLink );
2050 lclSaveRecord( rStrm, mxValueLink );
2051 lclSaveRecord( rStrm, mxCategLink );
2052 lclSaveRecord( rStrm, mxBubbleLink );
2053 lclSaveRecord( rStrm, mxSeriesFmt );
2054 maPointFmts.Save( rStrm );
2055 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
2056 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
2057 if( mnParentIdx != EXC_CHSERIES_INVALID )
2058 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
2059 lclSaveRecord( rStrm, mxTrendLine );
2060 lclSaveRecord( rStrm, mxErrorBar );
2061 }
2062
InitFromParent(const XclExpChSeries & rParent)2063 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
2064 {
2065 // index to parent series is stored 1-based
2066 mnParentIdx = rParent.mnSeriesIdx + 1;
2067 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2068 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2069 maData.mnCategCount = rParent.maData.mnCategCount;
2070 maData.mnValueCount = rParent.maData.mnValueCount;
2071 }
2072
CreateTrendLines(XDataSeriesRef xDataSeries)2073 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
2074 {
2075 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2076 if( xRegCurveCont.is() )
2077 {
2078 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
2079 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
2080 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
2081 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
2082 {
2083 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2084 if( xSeries.is() && !xSeries->ConvertTrendLine( *this, *pIt ) )
2085 GetChartData().RemoveLastSeries();
2086 }
2087 }
2088 }
2089
CreateErrorBars(const ScfPropertySet & rPropSet,const OUString & rBarPropName,sal_uInt8 nPosBarId,sal_uInt8 nNegBarId)2090 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
2091 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
2092 {
2093 Reference< XPropertySet > xErrorBar;
2094 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
2095 {
2096 ScfPropertySet aErrorProp( xErrorBar );
2097 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
2098 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
2099 }
2100 }
2101
CreateErrorBar(const ScfPropertySet & rPropSet,const OUString & rShowPropName,sal_uInt8 nBarId)2102 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
2103 const OUString& rShowPropName, sal_uInt8 nBarId )
2104 {
2105 if( rPropSet.GetBoolProperty( rShowPropName ) )
2106 {
2107 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2108 if( xSeries.is() && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
2109 GetChartData().RemoveLastSeries();
2110 }
2111 }
2112
WriteBody(XclExpStream & rStrm)2113 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
2114 {
2115 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
2116 if( GetBiff() == EXC_BIFF8 )
2117 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
2118 }
2119
2120 // Chart type groups ==========================================================
2121
XclExpChType(const XclExpChRoot & rRoot)2122 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
2123 XclExpRecord( EXC_ID_CHUNKNOWN ),
2124 XclExpChRoot( rRoot ),
2125 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2126 {
2127 }
2128
Convert(Reference<XDiagram> xDiagram,Reference<XChartType> xChartType,sal_Int32 nApiAxesSetIdx,bool bSwappedAxesSet,bool bHasXLabels)2129 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2130 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
2131 {
2132 if( xChartType.is() )
2133 {
2134 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
2135 // special handling for some chart types
2136 switch( maTypeInfo.meTypeCateg )
2137 {
2138 case EXC_CHTYPECATEG_BAR:
2139 {
2140 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
2141 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
2142 ScfPropertySet aTypeProp( xChartType );
2143 Sequence< sal_Int32 > aInt32Seq;
2144 maData.mnOverlap = 0;
2145 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2146 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
2147 maData.mnGap = 150;
2148 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2149 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
2150 }
2151 break;
2152 case EXC_CHTYPECATEG_RADAR:
2153 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
2154 break;
2155 case EXC_CHTYPECATEG_PIE:
2156 {
2157 ScfPropertySet aTypeProp( xChartType );
2158 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
2159 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2160 maData.mnPieHole = bDonut ? 50 : 0;
2161 // #i85166# starting angle of first pie slice
2162 ScfPropertySet aDiaProp( xDiagram );
2163 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
2164 }
2165 break;
2166 case EXC_CHTYPECATEG_SCATTER:
2167 if( GetBiff() == EXC_BIFF8 )
2168 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
2169 break;
2170 default:;
2171 }
2172 SetRecId( maTypeInfo.mnRecId );
2173 }
2174 }
2175
SetStacked(bool bPercent)2176 void XclExpChType::SetStacked( bool bPercent )
2177 {
2178 switch( maTypeInfo.meTypeCateg )
2179 {
2180 case EXC_CHTYPECATEG_LINE:
2181 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
2182 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
2183 break;
2184 case EXC_CHTYPECATEG_BAR:
2185 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
2186 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
2187 maData.mnOverlap = -100;
2188 break;
2189 default:;
2190 }
2191 }
2192
WriteBody(XclExpStream & rStrm)2193 void XclExpChType::WriteBody( XclExpStream& rStrm )
2194 {
2195 switch( GetRecId() )
2196 {
2197 case EXC_ID_CHBAR:
2198 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
2199 break;
2200
2201 case EXC_ID_CHLINE:
2202 case EXC_ID_CHAREA:
2203 case EXC_ID_CHRADARLINE:
2204 case EXC_ID_CHRADARAREA:
2205 rStrm << maData.mnFlags;
2206 break;
2207
2208 case EXC_ID_CHPIE:
2209 rStrm << maData.mnRotation << maData.mnPieHole;
2210 if( GetBiff() == EXC_BIFF8 )
2211 rStrm << maData.mnFlags;
2212 break;
2213
2214 case EXC_ID_CHSCATTER:
2215 if( GetBiff() == EXC_BIFF8 )
2216 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
2217 break;
2218
2219 default:
2220 DBG_ERRORFILE( "XclExpChType::WriteBody - unknown chart type" );
2221 }
2222 }
2223
2224 // ----------------------------------------------------------------------------
2225
XclExpChChart3d()2226 XclExpChChart3d::XclExpChChart3d() :
2227 XclExpRecord( EXC_ID_CHCHART3D, 14 )
2228 {
2229 }
2230
Convert(const ScfPropertySet & rPropSet,bool b3dWallChart)2231 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
2232 {
2233 sal_Int32 nRotationY = 0;
2234 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
2235 sal_Int32 nRotationX = 0;
2236 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
2237 sal_Int32 nPerspective = 15;
2238 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
2239
2240 if( b3dWallChart )
2241 {
2242 // Y rotation (Excel [0..359], Chart2 [-179,180])
2243 if( nRotationY < 0 ) nRotationY += 360;
2244 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
2245 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2246 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
2247 // perspective (Excel and Chart2 [0,100])
2248 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2249 // flags
2250 maData.mnFlags = 0;
2251 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
2252 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
2253 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
2254 }
2255 else
2256 {
2257 // Y rotation not used in pie charts, but 'first pie slice angle'
2258 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
2259 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2260 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
2261 // perspective (Excel and Chart2 [0,100])
2262 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2263 // flags
2264 maData.mnFlags = 0;
2265 }
2266 }
2267
WriteBody(XclExpStream & rStrm)2268 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
2269 {
2270 rStrm << maData.mnRotation
2271 << maData.mnElevation
2272 << maData.mnEyeDist
2273 << maData.mnRelHeight
2274 << maData.mnRelDepth
2275 << maData.mnDepthGap
2276 << maData.mnFlags;
2277 }
2278
2279 // ----------------------------------------------------------------------------
2280
XclExpChLegend(const XclExpChRoot & rRoot)2281 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2282 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
2283 {
2284 }
2285
Convert(const ScfPropertySet & rPropSet)2286 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2287 {
2288 // frame properties
2289 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2290 // text properties
2291 mxText.reset( new XclExpChText( GetChRoot() ) );
2292 mxText->ConvertLegend( rPropSet );
2293
2294 // legend position and size
2295 Any aRelPosAny, aRelSizeAny;
2296 rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION );
2297 rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE );
2298 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2299 rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION );
2300 if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) )
2301 {
2302 try
2303 {
2304 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2305 indicator of manually changed legend position/size, but due to
2306 the different anchor modes used by this property (in the
2307 RelativePosition.Anchor member) it cannot be used to calculate
2308 the position easily. For this, the Chart1 API will be used
2309 instead. */
2310 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
2311 Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW );
2312 // coordinates in CHLEGEND record written but not used by Excel
2313 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE, EXC_CHFRAMEPOS_PARENT ) );
2314 XclChFramePos& rFramePos = mxFramePos->GetFramePosData();
2315 rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE;
2316 ::com::sun::star::awt::Point aLegendPos = xChart1Legend->getPosition();
2317 rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X );
2318 rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y );
2319 // legend size, Excel expects points in CHFRAMEPOS record
2320 rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS;
2321 ::com::sun::star::awt::Size aLegendSize = xChart1Legend->getSize();
2322 rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 );
2323 rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 );
2324 maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width );
2325 maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height );
2326 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2327 // manual legend position implies manual plot area
2328 GetChartData().SetManualPlotArea();
2329 maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED;
2330 // a CHFRAME record with cleared auto flags is needed
2331 if( !mxFrame )
2332 mxFrame.reset( new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2333 mxFrame->SetAutoFlags( false, false );
2334 }
2335 catch( Exception& )
2336 {
2337 OSL_ENSURE( false, "XclExpChLegend::Convert - cannot get legend shape" );
2338 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2339 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2340 }
2341 }
2342 else
2343 {
2344 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2345 rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION );
2346 switch( eApiPos )
2347 {
2348 case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break;
2349 case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break;
2350 case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break;
2351 case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break;
2352 default:
2353 OSL_ENSURE( false, "XclExpChLegend::Convert - unrecognized legend position" );
2354 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2355 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2356 }
2357 }
2358 ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH );
2359
2360 // other flags
2361 ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES );
2362 const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY;
2363 ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED );
2364 }
2365
WriteSubRecords(XclExpStream & rStrm)2366 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2367 {
2368 lclSaveRecord( rStrm, mxFramePos );
2369 lclSaveRecord( rStrm, mxText );
2370 lclSaveRecord( rStrm, mxFrame );
2371 }
2372
WriteBody(XclExpStream & rStrm)2373 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2374 {
2375 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2376 }
2377
2378 // ----------------------------------------------------------------------------
2379
XclExpChDropBar(const XclExpChRoot & rRoot,XclChObjectType eObjType)2380 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
2381 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
2382 meObjType( eObjType ),
2383 mnBarDist( 100 )
2384 {
2385 }
2386
Convert(const ScfPropertySet & rPropSet)2387 void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
2388 {
2389 if( rPropSet.Is() )
2390 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
2391 else
2392 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
2393 }
2394
WriteSubRecords(XclExpStream & rStrm)2395 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2396 {
2397 WriteFrameRecords( rStrm );
2398 }
2399
WriteBody(XclExpStream & rStrm)2400 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2401 {
2402 rStrm << mnBarDist;
2403 }
2404
2405 // ----------------------------------------------------------------------------
2406
XclExpChTypeGroup(const XclExpChRoot & rRoot,sal_uInt16 nGroupIdx)2407 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2408 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
2409 maType( rRoot ),
2410 maTypeInfo( maType.GetTypeInfo() )
2411 {
2412 maData.mnGroupIdx = nGroupIdx;
2413 }
2414
ConvertType(Reference<XDiagram> xDiagram,Reference<XChartType> xChartType,sal_Int32 nApiAxesSetIdx,bool b3dChart,bool bSwappedAxesSet,bool bHasXLabels)2415 void XclExpChTypeGroup::ConvertType(
2416 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2417 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2418 {
2419 // chart type settings
2420 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2421
2422 // spline - TODO: get from single series (#i66858#)
2423 ScfPropertySet aTypeProp( xChartType );
2424 cssc2::CurveStyle eCurveStyle;
2425 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2426 (eCurveStyle != cssc2::CurveStyle_LINES);
2427
2428 // extended type info
2429 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2430
2431 // 3d chart settings
2432 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2433 {
2434 mxChart3d.reset( new XclExpChChart3d );
2435 ScfPropertySet aDiaProp( xDiagram );
2436 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2437 }
2438 }
2439
ConvertSeries(Reference<XDiagram> xDiagram,Reference<XChartType> xChartType,sal_Int32 nGroupAxesSetIdx,bool bPercent,bool bConnectBars)2440 void XclExpChTypeGroup::ConvertSeries(
2441 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2442 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2443 {
2444 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2445 if( xSeriesCont.is() )
2446 {
2447 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2448 XDataSeriesVec aSeriesVec;
2449
2450 // copy data series attached to the current axes set to the vector
2451 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2452 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2453 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2454 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2455 {
2456 ScfPropertySet aSeriesProp( *pIt );
2457 sal_Int32 nSeriesAxesSetIdx(0);
2458 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2459 aSeriesVec.push_back( *pIt );
2460 }
2461
2462 // Are there any series in the current axes set?
2463 if( !aSeriesVec.empty() )
2464 {
2465 // stacking direction (stacked/percent/deep 3d) from first series
2466 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2467 cssc2::StackingDirection eStacking;
2468 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2469 eStacking = cssc2::StackingDirection_NO_STACKING;
2470
2471 // stacked or percent chart
2472 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) )
2473 {
2474 // percent overrides simple stacking
2475 maType.SetStacked( bPercent );
2476
2477 // connected data points (only in stacked bar charts)
2478 if( bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
2479 maChartLines[ EXC_CHCHARTLINE_CONNECT ].reset( new XclExpChLineFormat( GetChRoot() ) );
2480 }
2481 else
2482 {
2483 // reverse series order for some unstacked 2D chart types
2484 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2485 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2486 }
2487
2488 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2489 if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() )
2490 mxChart3d->SetClustered();
2491
2492 // varied point colors
2493 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2494
2495 // process all series
2496 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2497 {
2498 // create Excel series object, stock charts need special processing
2499 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2500 CreateAllStockSeries( xChartType, *aIt );
2501 else
2502 CreateDataSeries( xDiagram, *aIt );
2503 }
2504 }
2505 }
2506 }
2507
ConvertCategSequence(Reference<XLabeledDataSequence> xCategSeq)2508 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2509 {
2510 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2511 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2512 }
2513
ConvertLegend(const ScfPropertySet & rPropSet)2514 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2515 {
2516 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2517 {
2518 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2519 mxLegend->Convert( rPropSet );
2520 }
2521 }
2522
WriteSubRecords(XclExpStream & rStrm)2523 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2524 {
2525 maType.Save( rStrm );
2526 lclSaveRecord( rStrm, mxChart3d );
2527 lclSaveRecord( rStrm, mxLegend );
2528 lclSaveRecord( rStrm, mxUpBar );
2529 lclSaveRecord( rStrm, mxDownBar );
2530 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2531 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2532 }
2533
GetFreeFormatIdx() const2534 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2535 {
2536 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2537 }
2538
CreateDataSeries(Reference<XDiagram> xDiagram,Reference<XDataSeries> xDataSeries)2539 void XclExpChTypeGroup::CreateDataSeries(
2540 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2541 {
2542 // let chart create series object with correct series index
2543 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2544 if( xSeries.is() )
2545 {
2546 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2547 maSeries.AppendRecord( xSeries );
2548 else
2549 GetChartData().RemoveLastSeries();
2550 }
2551 }
2552
CreateAllStockSeries(Reference<XChartType> xChartType,Reference<XDataSeries> xDataSeries)2553 void XclExpChTypeGroup::CreateAllStockSeries(
2554 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2555 {
2556 // create existing series objects
2557 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2558 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2559 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2560 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2561
2562 // formatting of special stock chart elements
2563 ScfPropertySet aTypeProp( xChartType );
2564 // hi-lo lines
2565 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2566 {
2567 ScfPropertySet aSeriesProp( xDataSeries );
2568 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2569 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2570 maChartLines[ EXC_CHCHARTLINE_HILO ] = xLineFmt;
2571 }
2572 // dropbars
2573 if( bHasOpen && bHasClose )
2574 {
2575 // dropbar type is dependent on position in the file - always create both
2576 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2577 // white dropbar format
2578 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2579 ScfPropertySet aWhiteProp( xWhitePropSet );
2580 mxUpBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ) );
2581 mxUpBar->Convert( aWhiteProp );
2582 // black dropbar format
2583 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2584 ScfPropertySet aBlackProp( xBlackPropSet );
2585 mxDownBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ) );
2586 mxDownBar->Convert( aBlackProp );
2587 }
2588 }
2589
CreateStockSeries(Reference<XDataSeries> xDataSeries,const OUString & rValueRole,bool bCloseSymbol)2590 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2591 const OUString& rValueRole, bool bCloseSymbol )
2592 {
2593 bool bOk = false;
2594 // let chart create series object with correct series index
2595 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2596 if( xSeries.is() )
2597 {
2598 bOk = xSeries->ConvertStockSeries( xDataSeries,
2599 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2600 if( bOk )
2601 maSeries.AppendRecord( xSeries );
2602 else
2603 GetChartData().RemoveLastSeries();
2604 }
2605 return bOk;
2606 }
2607
WriteBody(XclExpStream & rStrm)2608 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2609 {
2610 rStrm.WriteZeroBytes( 16 );
2611 rStrm << maData.mnFlags << maData.mnGroupIdx;
2612 }
2613
2614 // Axes =======================================================================
2615
XclExpChLabelRange(const XclExpChRoot & rRoot)2616 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2617 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2618 XclExpChRoot( rRoot )
2619 {
2620 }
2621
Convert(const ScaleData & rScaleData,const ScfPropertySet & rChart1Axis,bool bMirrorOrient)2622 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient )
2623 {
2624 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2625 chart API allows to detect axis type (date axis, if property exists),
2626 and to receive the base time unit currently used in case the base time
2627 unit is set to 'automatic'. */
2628 cssc::TimeIncrement aTimeIncrement;
2629 if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT ) )
2630 {
2631 // property exists -> this is a date axis currently
2632 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2633
2634 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2635 bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >();
2636 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase );
2637
2638 // ...but get the current base time unit from the property of the old chart API
2639 sal_Int32 nApiTimeUnit = 0;
2640 bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit;
2641 DBG_ASSERT( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot ghet base time unit" );
2642 maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS;
2643
2644 /* Min/max values depend on base time unit, they specify the number of
2645 days, months, or years starting from null date. */
2646 bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit );
2647 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin );
2648 bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit );
2649 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax );
2650 }
2651
2652 // automatic axis type detection
2653 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis );
2654
2655 // increment
2656 bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval );
2657 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor );
2658 bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval );
2659 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor );
2660
2661 // origin
2662 double fOrigin = 0.0;
2663 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
2664 maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
2665
2666 // reverse order
2667 if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient )
2668 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2669 }
2670
ConvertAxisPosition(const ScfPropertySet & rPropSet)2671 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2672 {
2673 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2674 rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION );
2675 double fCrossingPos = 1.0;
2676 rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE );
2677
2678 bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2679 switch( eAxisPos )
2680 {
2681 case cssc::ChartAxisPosition_ZERO:
2682 case cssc::ChartAxisPosition_START:
2683 maLabelData.mnCross = 1;
2684 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2685 break;
2686 case cssc::ChartAxisPosition_END:
2687 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS );
2688 break;
2689 case cssc::ChartAxisPosition_VALUE:
2690 maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 );
2691 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false );
2692 if( bDateAxis )
2693 maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit );
2694 break;
2695 default:
2696 maLabelData.mnCross = 1;
2697 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2698 }
2699 }
2700
Save(XclExpStream & rStrm)2701 void XclExpChLabelRange::Save( XclExpStream& rStrm )
2702 {
2703 // the CHLABELRANGE record
2704 XclExpRecord::Save( rStrm );
2705
2706 // the CHDATERANGE record with date axis settings (BIFF8 only)
2707 if( GetBiff() == EXC_BIFF8 )
2708 {
2709 rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 );
2710 rStrm << maDateData.mnMinDate
2711 << maDateData.mnMaxDate
2712 << maDateData.mnMajorStep
2713 << maDateData.mnMajorUnit
2714 << maDateData.mnMinorStep
2715 << maDateData.mnMinorUnit
2716 << maDateData.mnBaseUnit
2717 << maDateData.mnCross
2718 << maDateData.mnFlags;
2719 rStrm.EndRecord();
2720 }
2721 }
2722
WriteBody(XclExpStream & rStrm)2723 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2724 {
2725 rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags;
2726 }
2727
2728 // ----------------------------------------------------------------------------
2729
XclExpChValueRange(const XclExpChRoot & rRoot)2730 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2731 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2732 XclExpChRoot( rRoot )
2733 {
2734 }
2735
Convert(const ScaleData & rScaleData)2736 void XclExpChValueRange::Convert( const ScaleData& rScaleData )
2737 {
2738 // scaling algorithm
2739 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == SERVICE_CHART2_LOGSCALING;
2740 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2741
2742 // min/max
2743 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
2744 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2745 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
2746 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2747
2748 // origin
2749 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
2750 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2751
2752 // major increment
2753 const IncrementData& rIncrementData = rScaleData.IncrementData;
2754 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
2755 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2756 // minor increment
2757 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2758 sal_Int32 nCount = 0;
2759 bool bAutoMinor = bLogScale || bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2760 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1);
2761 if( !bAutoMinor )
2762 maData.mfMinorStep = maData.mfMajorStep / nCount;
2763 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2764
2765 // reverse order
2766 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE );
2767 }
2768
ConvertAxisPosition(const ScfPropertySet & rPropSet)2769 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2770 {
2771 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2772 double fCrossingPos = 0.0;
2773 if( rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE ) )
2774 {
2775 switch( eAxisPos )
2776 {
2777 case cssc::ChartAxisPosition_ZERO:
2778 case cssc::ChartAxisPosition_START:
2779 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2780 break;
2781 case cssc::ChartAxisPosition_END:
2782 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2783 break;
2784 case cssc::ChartAxisPosition_VALUE:
2785 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
2786 maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
2787 break;
2788 default:
2789 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2790 }
2791 }
2792 }
2793
WriteBody(XclExpStream & rStrm)2794 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2795 {
2796 rStrm << maData.mfMin
2797 << maData.mfMax
2798 << maData.mfMajorStep
2799 << maData.mfMinorStep
2800 << maData.mfCross
2801 << maData.mnFlags;
2802 }
2803
2804 // ----------------------------------------------------------------------------
2805
2806 namespace {
2807
lclGetXclTickPos(sal_Int32 nApiTickmarks)2808 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2809 {
2810 using namespace cssc2::TickmarkStyle;
2811 sal_uInt8 nXclTickPos = 0;
2812 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2813 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2814 return nXclTickPos;
2815 }
2816
2817 } // namespace
2818
XclExpChTick(const XclExpChRoot & rRoot)2819 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2820 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2821 XclExpChRoot( rRoot ),
2822 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2823 {
2824 }
2825
Convert(const ScfPropertySet & rPropSet,const XclChExtTypeInfo & rTypeInfo,sal_uInt16 nAxisType)2826 void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
2827 {
2828 // tick mark style
2829 sal_Int32 nApiTickmarks = 0;
2830 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2831 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2832 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2833 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2834
2835 // axis labels
2836 if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
2837 {
2838 /* Radar charts disable their category labels via chart type, not via
2839 axis, and axis labels are always 'near axis'. */
2840 maData.mnLabelPos = EXC_CHTICK_NEXT;
2841 }
2842 else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2843 {
2844 // no labels
2845 maData.mnLabelPos = EXC_CHTICK_NOLABEL;
2846 }
2847 else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
2848 {
2849 // Excel expects 'near axis' at Y axes in 3D charts
2850 maData.mnLabelPos = EXC_CHTICK_NEXT;
2851 }
2852 else
2853 {
2854 cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
2855 rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION );
2856 switch( eApiLabelPos )
2857 {
2858 case cssc::ChartAxisLabelPosition_NEAR_AXIS:
2859 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
2860 case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
2861 case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
2862 default: maData.mnLabelPos = EXC_CHTICK_NEXT;
2863 }
2864 }
2865 }
2866
SetFontColor(const Color & rColor,sal_uInt32 nColorId)2867 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2868 {
2869 maData.maTextColor = rColor;
2870 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2871 mnTextColorId = nColorId;
2872 }
2873
SetRotation(sal_uInt16 nRotation)2874 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2875 {
2876 maData.mnRotation = nRotation;
2877 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2878 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2879 }
2880
WriteBody(XclExpStream & rStrm)2881 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2882 {
2883 rStrm << maData.mnMajor
2884 << maData.mnMinor
2885 << maData.mnLabelPos
2886 << maData.mnBackMode;
2887 rStrm.WriteZeroBytes( 16 );
2888 rStrm << maData.maTextColor
2889 << maData.mnFlags;
2890 if( GetBiff() == EXC_BIFF8 )
2891 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2892 }
2893
2894 // ----------------------------------------------------------------------------
2895
2896 namespace {
2897
2898 /** Returns an API axis object from the passed coordinate system. */
lclGetApiAxis(Reference<XCoordinateSystem> xCoordSystem,sal_Int32 nApiAxisDim,sal_Int32 nApiAxesSetIdx)2899 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2900 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2901 {
2902 Reference< XAxis > xAxis;
2903 if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
2904 {
2905 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2906 }
2907 catch( Exception& )
2908 {
2909 }
2910 return xAxis;
2911 }
2912
lclGetApiChart1Axis(Reference<XChartDocument> xChartDoc,sal_Int32 nApiAxisDim,sal_Int32 nApiAxesSetIdx)2913 Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > xChartDoc,
2914 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2915 {
2916 Reference< cssc::XAxis > xChart1Axis;
2917 try
2918 {
2919 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW );
2920 Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
2921 switch( nApiAxesSetIdx )
2922 {
2923 case EXC_CHART_AXESSET_PRIMARY:
2924 xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim );
2925 break;
2926 case EXC_CHART_AXESSET_SECONDARY:
2927 xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim );
2928 break;
2929 }
2930 }
2931 catch( Exception& )
2932 {
2933 }
2934 return xChart1Axis;
2935 }
2936
2937 } // namespace
2938
XclExpChAxis(const XclExpChRoot & rRoot,sal_uInt16 nAxisType)2939 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2940 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
2941 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2942 {
2943 maData.mnType = nAxisType;
2944 }
2945
SetFont(XclExpChFontRef xFont,const Color & rColor,sal_uInt32 nColorId)2946 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2947 {
2948 mxFont = xFont;
2949 if( mxTick.is() )
2950 mxTick->SetFontColor( rColor, nColorId );
2951 }
2952
SetRotation(sal_uInt16 nRotation)2953 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2954 {
2955 if( mxTick.is() )
2956 mxTick->SetRotation( nRotation );
2957 }
2958
Convert(Reference<XAxis> xAxis,Reference<XAxis> xCrossingAxis,Reference<cssc::XAxis> xChart1Axis,const XclChExtTypeInfo & rTypeInfo)2959 void XclExpChAxis::Convert( Reference< XAxis > xAxis, Reference< XAxis > xCrossingAxis,
2960 Reference< cssc::XAxis > xChart1Axis, const XclChExtTypeInfo& rTypeInfo )
2961 {
2962 ScfPropertySet aAxisProp( xAxis );
2963 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2964
2965 // axis line format -------------------------------------------------------
2966
2967 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2968 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2969 // #i58688# axis enabled
2970 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2971
2972 // axis scaling and increment ---------------------------------------------
2973
2974 ScfPropertySet aCrossingProp( xCrossingAxis );
2975 if( bCategoryAxis )
2976 {
2977 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2978 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2979 if( xAxis.is() )
2980 {
2981 ScfPropertySet aChart1AxisProp( xChart1Axis );
2982 // #i71684# radar charts have reversed rotation direction
2983 mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2984 }
2985 // get position of crossing axis on this axis from passed axis object
2986 if( aCrossingProp.Is() )
2987 mxLabelRange->ConvertAxisPosition( aCrossingProp );
2988 }
2989 else
2990 {
2991 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
2992 if( xAxis.is() )
2993 mxValueRange->Convert( xAxis->getScaleData() );
2994 // get position of crossing axis on this axis from passed axis object
2995 if( aCrossingProp.Is() )
2996 mxValueRange->ConvertAxisPosition( aCrossingProp );
2997 }
2998
2999 // axis caption text ------------------------------------------------------
3000
3001 // axis ticks properties
3002 mxTick.reset( new XclExpChTick( GetChRoot() ) );
3003 mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
3004
3005 // axis label formatting and rotation
3006 ConvertFontBase( GetChRoot(), aAxisProp );
3007 ConvertRotationBase( GetChRoot(), aAxisProp, true );
3008
3009 // axis number format
3010 sal_Int32 nApiNumFmt = 0;
3011 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
3012 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
3013
3014 // grid -------------------------------------------------------------------
3015
3016 if( xAxis.is() )
3017 {
3018 // main grid
3019 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3020 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3021 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3022 // sub grid
3023 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3024 if( aSubGridPropSeq.hasElements() )
3025 {
3026 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3027 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3028 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3029 }
3030 }
3031 }
3032
ConvertWall(XDiagramRef xDiagram)3033 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
3034 {
3035 if( xDiagram.is() ) switch( GetAxisType() )
3036 {
3037 case EXC_CHAXIS_X:
3038 {
3039 ScfPropertySet aWallProp( xDiagram->getWall() );
3040 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
3041 }
3042 break;
3043 case EXC_CHAXIS_Y:
3044 {
3045 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3046 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
3047 }
3048 break;
3049 default:
3050 mxWallFrame.reset();
3051 }
3052 }
3053
WriteSubRecords(XclExpStream & rStrm)3054 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
3055 {
3056 lclSaveRecord( rStrm, mxLabelRange );
3057 lclSaveRecord( rStrm, mxValueRange );
3058 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
3059 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
3060 lclSaveRecord( rStrm, mxTick );
3061 lclSaveRecord( rStrm, mxFont );
3062 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
3063 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
3064 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
3065 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
3066 }
3067
WriteBody(XclExpStream & rStrm)3068 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
3069 {
3070 rStrm << maData.mnType;
3071 rStrm.WriteZeroBytes( 16 );
3072 }
3073
3074 // ----------------------------------------------------------------------------
3075
XclExpChAxesSet(const XclExpChRoot & rRoot,sal_uInt16 nAxesSetId)3076 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3077 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
3078 {
3079 maData.mnAxesSetId = nAxesSetId;
3080 SetFutureRecordContext( 0, nAxesSetId );
3081
3082 /* Need to set a reasonable size for the plot area, otherwise Excel will
3083 move away embedded shapes while auto-sizing the plot area. This is just
3084 a wild guess, but will be fixed with implementing manual positioning of
3085 chart elements. */
3086 maData.maRect.mnX = 262;
3087 maData.maRect.mnY = 626;
3088 maData.maRect.mnWidth = 3187;
3089 maData.maRect.mnHeight = 2633;
3090 }
3091
Convert(Reference<XDiagram> xDiagram,sal_uInt16 nFirstGroupIdx)3092 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
3093 {
3094 /* First unused chart type group index is passed to be able to continue
3095 counting of chart type groups for secondary axes set. */
3096 sal_uInt16 nGroupIdx = nFirstGroupIdx;
3097 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
3098 if( xCoordSysCont.is() )
3099 {
3100 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
3101 if( aCoordSysSeq.getLength() > 0 )
3102 {
3103 /* Process first coordinate system only. Import filter puts all
3104 chart types into one coordinate system. */
3105 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
3106 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3107
3108 // 3d mode
3109 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
3110
3111 // percent charts
3112 namespace ApiAxisType = cssc2::AxisType;
3113 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
3114 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
3115
3116 // connector lines in bar charts
3117 ScfPropertySet aDiaProp( xDiagram );
3118 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
3119
3120 // swapped axes sets
3121 ScfPropertySet aCoordSysProp( xCoordSystem );
3122 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
3123
3124 // X axis for later use
3125 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
3126 // X axis labels
3127 ScfPropertySet aXAxisProp( xApiXAxis );
3128 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
3129
3130 // process chart types
3131 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3132 if( xChartTypeCont.is() )
3133 {
3134 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
3135 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
3136 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
3137 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
3138 {
3139 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
3140 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
3141 /* If new chart type group cannot be inserted into a combination
3142 chart with existing type groups, insert all series into last
3143 contained chart type group instead of creating a new group. */
3144 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
3145 if( xLastGroup.is() && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
3146 {
3147 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3148 }
3149 else
3150 {
3151 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3152 if( xTypeGroup->IsValidGroup() )
3153 {
3154 maTypeGroups.AppendRecord( xTypeGroup );
3155 ++nGroupIdx;
3156 }
3157 }
3158 }
3159 }
3160
3161 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
3162 {
3163 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
3164
3165 // create axes according to chart type (no axes for pie and donut charts)
3166 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
3167 {
3168 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
3169 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
3170 if( pGroup->Is3dDeepChart() )
3171 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
3172 }
3173
3174 // X axis category ranges
3175 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
3176 {
3177 const ScaleData aScaleData = xApiXAxis->getScaleData();
3178 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
3179 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
3180 }
3181
3182 // legend
3183 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3184 {
3185 Reference< XLegend > xLegend = xDiagram->getLegend();
3186 if( xLegend.is() )
3187 {
3188 ScfPropertySet aLegendProp( xLegend );
3189 pGroup->ConvertLegend( aLegendProp );
3190 }
3191 }
3192 }
3193 }
3194 }
3195
3196 // wall/floor/diagram frame formatting
3197 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3198 {
3199 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3200 if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
3201 {
3202 // wall/floor formatting (3D charts)
3203 if( mxXAxis.is() )
3204 mxXAxis->ConvertWall( xDiagram );
3205 if( mxYAxis.is() )
3206 mxYAxis->ConvertWall( xDiagram );
3207 }
3208 else
3209 {
3210 // diagram background formatting
3211 ScfPropertySet aWallProp( xDiagram->getWall() );
3212 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
3213 }
3214 }
3215
3216 // inner and outer plot area position and size
3217 try
3218 {
3219 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
3220 Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
3221 // set manual flag in chart data
3222 if( !xPositioning->isAutomaticDiagramPositioning() )
3223 GetChartData().SetManualPlotArea();
3224 // the CHAXESSET record contains the inner plot area
3225 maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() );
3226 // the embedded CHFRAMEPOS record contains the outer plot area
3227 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
3228 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3229 const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get();
3230 bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE);
3231 mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect :
3232 CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() );
3233 }
3234 catch( Exception& )
3235 {
3236 }
3237
3238 // return first unused chart type group index for next axes set
3239 return nGroupIdx;
3240 }
3241
Is3dChart() const3242 bool XclExpChAxesSet::Is3dChart() const
3243 {
3244 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3245 return xTypeGroup.is() && xTypeGroup->Is3dChart();
3246 }
3247
WriteSubRecords(XclExpStream & rStrm)3248 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
3249 {
3250 lclSaveRecord( rStrm, mxFramePos );
3251 lclSaveRecord( rStrm, mxXAxis );
3252 lclSaveRecord( rStrm, mxYAxis );
3253 lclSaveRecord( rStrm, mxZAxis );
3254 lclSaveRecord( rStrm, mxXAxisTitle );
3255 lclSaveRecord( rStrm, mxYAxisTitle );
3256 lclSaveRecord( rStrm, mxZAxisTitle );
3257 if( mxPlotFrame.is() )
3258 {
3259 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
3260 mxPlotFrame->Save( rStrm );
3261 }
3262 maTypeGroups.Save( rStrm );
3263 }
3264
GetFirstTypeGroup() const3265 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
3266 {
3267 return maTypeGroups.GetFirstRecord();
3268 }
3269
GetLastTypeGroup() const3270 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
3271 {
3272 return maTypeGroups.GetLastRecord();
3273 }
3274
ConvertAxis(XclExpChAxisRef & rxChAxis,sal_uInt16 nAxisType,XclExpChTextRef & rxChAxisTitle,sal_uInt16 nTitleTarget,Reference<XCoordinateSystem> xCoordSystem,const XclChExtTypeInfo & rTypeInfo,sal_Int32 nCrossingAxisDim)3275 void XclExpChAxesSet::ConvertAxis(
3276 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
3277 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
3278 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
3279 sal_Int32 nCrossingAxisDim )
3280 {
3281 // create and convert axis object
3282 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
3283 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
3284 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3285 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
3286 Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
3287 Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx );
3288 rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo );
3289
3290 // create and convert axis title
3291 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
3292 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
3293 }
3294
WriteBody(XclExpStream & rStrm)3295 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
3296 {
3297 rStrm << maData.mnAxesSetId << maData.maRect;
3298 }
3299
3300 // The chart object ===========================================================
3301
XclExpChChart(const XclExpRoot & rRoot,Reference<XChartDocument> xChartDoc,const Rectangle & rChartRect)3302 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
3303 Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) :
3304 XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
3305 {
3306 Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
3307 // rectangle is stored in 16.16 fixed-point format
3308 maRect.mnX = maRect.mnY = 0;
3309 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
3310 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
3311
3312 // global chart properties (default values)
3313 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
3314 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA );
3315 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
3316
3317 // always create both axes set objects
3318 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3319 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3320
3321 if( xChartDoc.is() )
3322 {
3323 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
3324
3325 // global chart properties (only 'include hidden cells' attribute for now)
3326 ScfPropertySet aDiagramProp( xDiagram );
3327 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
3328 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
3329
3330 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3331 InitConversion( xChartDoc, rChartRect );
3332
3333 // chart frame
3334 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3335 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
3336
3337 // chart title
3338 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3339 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE );
3340
3341 // diagrams (axes sets)
3342 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
3343 if( !mxPrimAxesSet->Is3dChart() )
3344 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
3345
3346 // treatment of missing values
3347 ScfPropertySet aDiaProp( xDiagram );
3348 sal_Int32 nMissingValues = 0;
3349 if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT ) )
3350 {
3351 using namespace cssc::MissingValueTreatment;
3352 switch( nMissingValues )
3353 {
3354 case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
3355 case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
3356 case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
3357 }
3358 }
3359
3360 // finish API conversion
3361 FinishConversion();
3362 }
3363 }
3364
CreateSeries()3365 XclExpChSeriesRef XclExpChChart::CreateSeries()
3366 {
3367 XclExpChSeriesRef xSeries;
3368 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
3369 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3370 {
3371 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
3372 maSeries.AppendRecord( xSeries );
3373 }
3374 return xSeries;
3375 }
3376
RemoveLastSeries()3377 void XclExpChChart::RemoveLastSeries()
3378 {
3379 if( !maSeries.IsEmpty() )
3380 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
3381 }
3382
SetDataLabel(XclExpChTextRef xText)3383 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
3384 {
3385 if( xText.is() )
3386 maLabels.AppendRecord( xText );
3387 }
3388
SetManualPlotArea()3389 void XclExpChChart::SetManualPlotArea()
3390 {
3391 // this flag does not exist in BIFF5
3392 if( GetBiff() == EXC_BIFF8 )
3393 ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3394 }
3395
WriteSubRecords(XclExpStream & rStrm)3396 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
3397 {
3398 // background format
3399 lclSaveRecord( rStrm, mxFrame );
3400
3401 // data series
3402 maSeries.Save( rStrm );
3403
3404 // CHPROPERTIES record
3405 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
3406 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
3407 rStrm.EndRecord();
3408
3409 // axes sets (always save primary axes set)
3410 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
3411 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
3412 mxPrimAxesSet->Save( rStrm );
3413 if( mxSecnAxesSet->IsValidAxesSet() )
3414 mxSecnAxesSet->Save( rStrm );
3415
3416 // chart title and data labels
3417 lclSaveRecord( rStrm, mxTitle );
3418 maLabels.Save( rStrm );
3419 }
3420
WriteBody(XclExpStream & rStrm)3421 void XclExpChChart::WriteBody( XclExpStream& rStrm )
3422 {
3423 rStrm << maRect;
3424 }
3425
3426 // ----------------------------------------------------------------------------
3427
XclExpChartDrawing(const XclExpRoot & rRoot,const Reference<XModel> & rxModel,const Size & rChartSize)3428 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot,
3429 const Reference< XModel >& rxModel, const Size& rChartSize ) :
3430 XclExpRoot( rRoot )
3431 {
3432 if( (rChartSize.Width() > 0) && (rChartSize.Height() > 0) )
3433 {
3434 ScfPropertySet aPropSet( rxModel );
3435 Reference< XShapes > xShapes;
3436 if( aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES ) && xShapes.is() && (xShapes->getCount() > 0) )
3437 {
3438 /* Create a new independent object manager with own DFF stream for the
3439 DGCONTAINER, pass global manager as parent for shared usage of
3440 global DFF data (picture container etc.). */
3441 mxObjMgr.reset( new XclExpEmbeddedObjectManager( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS ) );
3442 // initialize the drawing object list
3443 mxObjMgr->StartSheet();
3444 // process the draw page (convert all shapes)
3445 mxObjRecs = mxObjMgr->ProcessDrawing( xShapes );
3446 // finalize the DFF stream
3447 mxObjMgr->EndDocument();
3448 }
3449 }
3450 }
3451
~XclExpChartDrawing()3452 XclExpChartDrawing::~XclExpChartDrawing()
3453 {
3454 }
3455
Save(XclExpStream & rStrm)3456 void XclExpChartDrawing::Save( XclExpStream& rStrm )
3457 {
3458 if( mxObjRecs.is() )
3459 mxObjRecs->Save( rStrm );
3460 }
3461
3462 // ----------------------------------------------------------------------------
3463
XclExpChart(const XclExpRoot & rRoot,Reference<XModel> xModel,const Rectangle & rChartRect)3464 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Rectangle& rChartRect ) :
3465 XclExpSubStream( EXC_BOF_CHART ),
3466 XclExpRoot( rRoot )
3467 {
3468 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
3469 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
3470 AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) );
3471 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
3472
3473 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3474 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) );
3475 }
3476
3477 // ============================================================================
3478
3479