xref: /trunk/main/sc/source/filter/excel/xechart.cxx (revision b77af630)
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_scfilt.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