xref: /trunk/main/sc/source/filter/excel/xichart.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 "xichart.hxx"
28 
29 #include <algorithm>
30 #include <memory>
31 
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/drawing/Direction3D.hpp>
34 #include <com/sun/star/drawing/ProjectionMode.hpp>
35 #include <com/sun/star/drawing/ShadeMode.hpp>
36 #include <com/sun/star/drawing/XShape.hpp>
37 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
38 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
39 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
40 #include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
41 #include <com/sun/star/chart/ChartAxisPosition.hpp>
42 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
43 #include <com/sun/star/chart/TimeInterval.hpp>
44 #include <com/sun/star/chart/TimeUnit.hpp>
45 #include <com/sun/star/chart/XChartDocument.hpp>
46 #include <com/sun/star/chart/XDiagramPositioning.hpp>
47 #include <com/sun/star/chart2/XChartDocument.hpp>
48 #include <com/sun/star/chart2/XDiagram.hpp>
49 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
50 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
51 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
52 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
53 #include <com/sun/star/chart2/XTitled.hpp>
54 #include <com/sun/star/chart2/data/XDataProvider.hpp>
55 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
56 #include <com/sun/star/chart2/data/XDataSink.hpp>
57 #include <com/sun/star/chart2/AxisType.hpp>
58 #include <com/sun/star/chart2/CurveStyle.hpp>
59 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
60 #include <com/sun/star/chart2/DataPointLabel.hpp>
61 #include <com/sun/star/chart2/LegendPosition.hpp>
62 #include <com/sun/star/chart2/StackingDirection.hpp>
63 #include <com/sun/star/chart2/TickmarkStyle.hpp>
64 #include <com/sun/star/chart2/RelativePosition.hpp>
65 #include <com/sun/star/chart2/RelativeSize.hpp>
66 #include <com/sun/star/chart/DataLabelPlacement.hpp>
67 #include <com/sun/star/chart/ErrorBarStyle.hpp>
68 #include <com/sun/star/chart/MissingValueTreatment.hpp>
69 
70 #include <sfx2/objsh.hxx>
71 #include <svx/svdpage.hxx>
72 #include <svx/unoapi.hxx>
73 
74 #include "document.hxx"
75 #include "drwlayer.hxx"
76 #include "rangeutl.hxx"
77 #include "tokenarray.hxx"
78 #include "token.hxx"
79 #include "compiler.hxx"
80 #include "reftokenhelper.hxx"
81 #include "chartlis.hxx"
82 #include "fprogressbar.hxx"
83 #include "xltracer.hxx"
84 #include "xistream.hxx"
85 #include "xiformula.hxx"
86 #include "xistyle.hxx"
87 #include "xipage.hxx"
88 #include "xiview.hxx"
89 
90 using ::rtl::OUString;
91 using ::rtl::OUStringBuffer;
92 using ::com::sun::star::uno::Any;
93 using ::com::sun::star::uno::Reference;
94 using ::com::sun::star::uno::Sequence;
95 using ::com::sun::star::uno::UNO_QUERY;
96 using ::com::sun::star::uno::UNO_QUERY_THROW;
97 using ::com::sun::star::uno::UNO_SET_THROW;
98 using ::com::sun::star::uno::Exception;
99 using ::com::sun::star::beans::XPropertySet;
100 using ::com::sun::star::lang::XMultiServiceFactory;
101 using ::com::sun::star::frame::XModel;
102 using ::com::sun::star::util::XNumberFormatsSupplier;
103 using ::com::sun::star::drawing::XDrawPage;
104 using ::com::sun::star::drawing::XDrawPageSupplier;
105 using ::com::sun::star::drawing::XShape;
106 
107 using ::com::sun::star::chart2::IncrementData;
108 using ::com::sun::star::chart2::RelativePosition;
109 using ::com::sun::star::chart2::RelativeSize;
110 using ::com::sun::star::chart2::ScaleData;
111 using ::com::sun::star::chart2::SubIncrement;
112 using ::com::sun::star::chart2::XAxis;
113 using ::com::sun::star::chart2::XChartDocument;
114 using ::com::sun::star::chart2::XChartType;
115 using ::com::sun::star::chart2::XChartTypeContainer;
116 using ::com::sun::star::chart2::XCoordinateSystem;
117 using ::com::sun::star::chart2::XCoordinateSystemContainer;
118 using ::com::sun::star::chart2::XDataSeries;
119 using ::com::sun::star::chart2::XDataSeriesContainer;
120 using ::com::sun::star::chart2::XDiagram;
121 using ::com::sun::star::chart2::XFormattedString;
122 using ::com::sun::star::chart2::XLegend;
123 using ::com::sun::star::chart2::XRegressionCurve;
124 using ::com::sun::star::chart2::XRegressionCurveContainer;
125 using ::com::sun::star::chart2::XScaling;
126 using ::com::sun::star::chart2::XTitle;
127 using ::com::sun::star::chart2::XTitled;
128 
129 using ::com::sun::star::chart2::data::XDataProvider;
130 using ::com::sun::star::chart2::data::XDataReceiver;
131 using ::com::sun::star::chart2::data::XDataSequence;
132 using ::com::sun::star::chart2::data::XDataSink;
133 using ::com::sun::star::chart2::data::XLabeledDataSequence;
134 
135 using ::formula::FormulaToken;
136 using ::formula::StackVar;
137 
138 namespace cssc = ::com::sun::star::chart;
139 namespace cssc2 = ::com::sun::star::chart2;
140 
141 // Helpers ====================================================================
142 
143 namespace {
144 
operator >>(XclImpStream & rStrm,XclChRectangle & rRect)145 XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect )
146 {
147     return rStrm >> rRect.mnX >> rRect.mnY >> rRect.mnWidth >> rRect.mnHeight;
148 }
149 
lclSetValueOrClearAny(Any & rAny,double fValue,bool bClear)150 inline void lclSetValueOrClearAny( Any& rAny, double fValue, bool bClear )
151 {
152     if( bClear )
153         rAny.clear();
154     else
155         rAny <<= fValue;
156 }
157 
lclSetExpValueOrClearAny(Any & rAny,double fValue,bool bLogScale,bool bClear)158 void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear )
159 {
160     if( !bClear && bLogScale )
161         fValue = pow( 10.0, fValue );
162     lclSetValueOrClearAny( rAny, fValue, bClear );
163 }
164 
lclGetSerialDay(const XclImpRoot & rRoot,sal_uInt16 nValue,sal_uInt16 nTimeUnit)165 double lclGetSerialDay( const XclImpRoot& rRoot, sal_uInt16 nValue, sal_uInt16 nTimeUnit )
166 {
167     switch( nTimeUnit )
168     {
169         case EXC_CHDATERANGE_DAYS:
170             return nValue;
171         case EXC_CHDATERANGE_MONTHS:
172             return rRoot.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16 >( 1 + nValue % 12 ), static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue / 12 ) ) );
173         case EXC_CHDATERANGE_YEARS:
174             return rRoot.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue ) ) );
175         default:
176             OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
177     }
178     return nValue;
179 }
180 
lclConvertTimeValue(const XclImpRoot & rRoot,Any & rAny,sal_uInt16 nValue,bool bAuto,sal_uInt16 nTimeUnit)181 void lclConvertTimeValue( const XclImpRoot& rRoot, Any& rAny, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
182 {
183     if( bAuto )
184         rAny.clear();
185     else
186         rAny <<= lclGetSerialDay( rRoot, nValue, nTimeUnit );
187 }
188 
lclGetApiTimeUnit(sal_uInt16 nTimeUnit)189 sal_Int32 lclGetApiTimeUnit( sal_uInt16 nTimeUnit )
190 {
191     switch( nTimeUnit )
192     {
193         case EXC_CHDATERANGE_DAYS:      return cssc::TimeUnit::DAY;
194         case EXC_CHDATERANGE_MONTHS:    return cssc::TimeUnit::MONTH;
195         case EXC_CHDATERANGE_YEARS:     return cssc::TimeUnit::YEAR;
196         default:                        OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
197     }
198     return cssc::TimeUnit::DAY;
199 }
200 
lclConvertTimeInterval(Any & rInterval,sal_uInt16 nValue,bool bAuto,sal_uInt16 nTimeUnit)201 void lclConvertTimeInterval( Any& rInterval, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
202 {
203     if( bAuto || (nValue == 0) )
204         rInterval.clear();
205     else
206         rInterval <<= cssc::TimeInterval( nValue, lclGetApiTimeUnit( nTimeUnit ) );
207 }
208 
209 } // namespace
210 
211 // Common =====================================================================
212 
213 /** Stores global data needed in various classes of the Chart import filter. */
214 struct XclImpChRootData : public XclChRootData
215 {
216     XclImpChChart&      mrChartData;            /// The chart data object.
217 
XclImpChRootDataXclImpChRootData218     inline explicit     XclImpChRootData( XclImpChChart& rChartData ) : mrChartData( rChartData ) {}
219 };
220 
221 // ----------------------------------------------------------------------------
222 
XclImpChRoot(const XclImpRoot & rRoot,XclImpChChart & rChartData)223 XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart& rChartData ) :
224     XclImpRoot( rRoot ),
225     mxChData( new XclImpChRootData( rChartData ) )
226 {
227 }
228 
~XclImpChRoot()229 XclImpChRoot::~XclImpChRoot()
230 {
231 }
232 
GetChartData() const233 XclImpChChart& XclImpChRoot::GetChartData() const
234 {
235     return mxChData->mrChartData;
236 }
237 
GetChartTypeInfo(XclChTypeId eType) const238 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
239 {
240     return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
241 }
242 
GetChartTypeInfo(sal_uInt16 nRecId) const243 const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const
244 {
245     return mxChData->mxTypeInfoProv->GetTypeInfoFromRecId( nRecId );
246 }
247 
GetFormatInfo(XclChObjectType eObjType) const248 const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
249 {
250     return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
251 }
252 
GetFontAutoColor() const253 Color XclImpChRoot::GetFontAutoColor() const
254 {
255     return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT );
256 }
257 
GetSeriesLineAutoColor(sal_uInt16 nFormatIdx) const258 Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const
259 {
260     return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) );
261 }
262 
GetSeriesFillAutoColor(sal_uInt16 nFormatIdx) const263 Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const
264 {
265     const XclImpPalette& rPal = GetPalette();
266     Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) );
267     sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx );
268     return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans );
269 }
270 
InitConversion(Reference<XChartDocument> xChartDoc,const Rectangle & rChartRect) const271 void XclImpChRoot::InitConversion( Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) const
272 {
273     // create formatting object tables
274     mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
275 
276     // lock the model to suppress any internal updates
277     Reference< XModel > xModel( xChartDoc, UNO_QUERY );
278     if( xModel.is() )
279         xModel->lockControllers();
280 
281     SfxObjectShell* pDocShell = GetDocShell();
282     Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
283     if( pDocShell && xDataRec.is() )
284     {
285         // create and register a data provider
286         Reference< XDataProvider > xDataProv(
287             ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY );
288         if( xDataProv.is() )
289             xDataRec->attachDataProvider( xDataProv );
290         // attach the number formatter
291         Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY );
292         if( xNumFmtSupp.is() )
293             xDataRec->attachNumberFormatsSupplier( xNumFmtSupp );
294     }
295 }
296 
FinishConversion(XclImpDffConverter & rDffConv) const297 void XclImpChRoot::FinishConversion( XclImpDffConverter& rDffConv ) const
298 {
299     rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
300     // unlock the model
301     Reference< XModel > xModel( mxChData->mxChartDoc, UNO_QUERY );
302     if( xModel.is() )
303         xModel->unlockControllers();
304     rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
305 
306     mxChData->FinishConversion();
307 }
308 
GetDataProvider() const309 Reference< XDataProvider > XclImpChRoot::GetDataProvider() const
310 {
311     return mxChData->mxChartDoc->getDataProvider();
312 }
313 
GetTitleShape(const XclChTextKey & rTitleKey) const314 Reference< XShape > XclImpChRoot::GetTitleShape( const XclChTextKey& rTitleKey ) const
315 {
316     return mxChData->GetTitleShape( rTitleKey );
317 }
318 
CalcHmmFromChartX(sal_Int32 nPosX) const319 sal_Int32 XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX ) const
320 {
321     return static_cast< sal_Int32 >( mxChData->mfUnitSizeX * nPosX + mxChData->mnBorderGapX + 0.5 );
322 }
323 
CalcHmmFromChartY(sal_Int32 nPosY) const324 sal_Int32 XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY ) const
325 {
326     return static_cast< sal_Int32 >( mxChData->mfUnitSizeY * nPosY + mxChData->mnBorderGapY + 0.5 );
327 }
328 
CalcHmmFromChartRect(const XclChRectangle & rRect) const329 ::com::sun::star::awt::Rectangle XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle& rRect ) const
330 {
331     return ::com::sun::star::awt::Rectangle(
332         CalcHmmFromChartX( rRect.mnX ),
333         CalcHmmFromChartY( rRect.mnY ),
334         CalcHmmFromChartX( rRect.mnWidth ),
335         CalcHmmFromChartY( rRect.mnHeight ) );
336 }
337 
CalcRelativeFromHmmX(sal_Int32 nPosX) const338 double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX ) const
339 {
340     return static_cast< double >( nPosX ) / mxChData->maChartRect.GetWidth();
341 }
342 
CalcRelativeFromHmmY(sal_Int32 nPosY) const343 double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY ) const
344 {
345     return static_cast< double >( nPosY ) / mxChData->maChartRect.GetHeight();
346 }
347 
CalcRelativeFromChartX(sal_Int32 nPosX) const348 double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX ) const
349 {
350     return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX ) );
351 }
352 
CalcRelativeFromChartY(sal_Int32 nPosY) const353 double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY ) const
354 {
355     return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY ) );
356 }
357 
ConvertLineFormat(ScfPropertySet & rPropSet,const XclChLineFormat & rLineFmt,XclChPropertyMode ePropMode) const358 void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet,
359         const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const
360 {
361     GetChartPropSetHelper().WriteLineProperties(
362         rPropSet, *mxChData->mxLineDashTable, rLineFmt, ePropMode );
363 }
364 
ConvertAreaFormat(ScfPropertySet & rPropSet,const XclChAreaFormat & rAreaFmt,XclChPropertyMode ePropMode) const365 void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet,
366         const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const
367 {
368     GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode );
369 }
370 
ConvertEscherFormat(ScfPropertySet & rPropSet,const XclChEscherFormat & rEscherFmt,const XclChPicFormat * pPicFmt,sal_uInt32 nDffFillType,XclChPropertyMode ePropMode) const371 void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet,
372         const XclChEscherFormat& rEscherFmt, const XclChPicFormat* pPicFmt,
373         sal_uInt32 nDffFillType, XclChPropertyMode ePropMode ) const
374 {
375     GetChartPropSetHelper().WriteEscherProperties( rPropSet,
376         *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable,
377         rEscherFmt, pPicFmt, nDffFillType, ePropMode );
378 }
379 
ConvertFont(ScfPropertySet & rPropSet,sal_uInt16 nFontIdx,const Color * pFontColor) const380 void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet,
381         sal_uInt16 nFontIdx, const Color* pFontColor ) const
382 {
383     GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor );
384 }
385 
ConvertPieRotation(ScfPropertySet & rPropSet,sal_uInt16 nAngle)386 void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle )
387 {
388     sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360;
389     rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot );
390 }
391 
392 // ----------------------------------------------------------------------------
393 
~XclImpChGroupBase()394 XclImpChGroupBase::~XclImpChGroupBase()
395 {
396 }
397 
ReadRecordGroup(XclImpStream & rStrm)398 void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm )
399 {
400     // read contents of the header record
401     ReadHeaderRecord( rStrm );
402 
403     // only read sub records, if the next record is a CHBEGIN
404     if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN )
405     {
406         // read the CHBEGIN record, may be used for special initial processing
407         rStrm.StartNextRecord();
408         ReadSubRecord( rStrm );
409 
410         // read the nested records
411         bool bLoop = true;
412         while( bLoop && rStrm.StartNextRecord() )
413         {
414             sal_uInt16 nRecId = rStrm.GetRecId();
415             bLoop = nRecId != EXC_ID_CHEND;
416             // skip unsupported nested blocks
417             if( nRecId == EXC_ID_CHBEGIN )
418                 SkipBlock( rStrm );
419             else
420                 ReadSubRecord( rStrm );
421         }
422     }
423     /*  Returns with current CHEND record or unchanged stream, if no record
424         group present. In every case another call to StartNextRecord() will go
425         to next record of interest. */
426 }
427 
SkipBlock(XclImpStream & rStrm)428 void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm )
429 {
430     DBG_ASSERT( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
431     // do nothing if current record is not CHBEGIN
432     bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN;
433     while( bLoop && rStrm.StartNextRecord() )
434     {
435         sal_uInt16 nRecId = rStrm.GetRecId();
436         bLoop = nRecId != EXC_ID_CHEND;
437         // skip nested record groups
438         if( nRecId == EXC_ID_CHBEGIN )
439             SkipBlock( rStrm );
440     }
441 }
442 
443 // Frame formatting ===========================================================
444 
ReadChFramePos(XclImpStream & rStrm)445 void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm )
446 {
447     rStrm >> maData.mnTLMode >> maData.mnBRMode;
448     /*  According to the spec, the upper 16 bits of all members in the
449         rectangle are unused and may contain garbage. */
450     maData.maRect.mnX = rStrm.ReadInt16(); rStrm.Ignore( 2 );
451     maData.maRect.mnY = rStrm.ReadInt16(); rStrm.Ignore( 2 );
452     maData.maRect.mnWidth = rStrm.ReadInt16(); rStrm.Ignore( 2 );
453     maData.maRect.mnHeight = rStrm.ReadInt16(); rStrm.Ignore( 2 );
454 }
455 
456 // ----------------------------------------------------------------------------
457 
ReadChLineFormat(XclImpStream & rStrm)458 void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm )
459 {
460     rStrm >> maData.maColor >> maData.mnPattern >> maData.mnWeight >> maData.mnFlags;
461 
462     const XclImpRoot& rRoot = rStrm.GetRoot();
463     if( rRoot.GetBiff() == EXC_BIFF8 )
464         // #116397# BIFF8: index into palette used instead of RGB data
465         maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() );
466 }
467 
Convert(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,sal_uInt16 nFormatIdx) const468 void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot,
469         ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
470 {
471     const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
472     if( IsAuto() )
473     {
474         XclChLineFormat aLineFmt;
475         aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ?
476             rRoot.GetSeriesLineAutoColor( nFormatIdx ) :
477             rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx );
478         aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
479         aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight;
480         rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode );
481     }
482     else
483     {
484         rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode );
485     }
486 }
487 
488 // ----------------------------------------------------------------------------
489 
ReadChAreaFormat(XclImpStream & rStrm)490 void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm )
491 {
492     rStrm >> maData.maPattColor >> maData.maBackColor >> maData.mnPattern >> maData.mnFlags;
493 
494     const XclImpRoot& rRoot = rStrm.GetRoot();
495     if( rRoot.GetBiff() == EXC_BIFF8 )
496     {
497         // #116397# BIFF8: index into palette used instead of RGB data
498         const XclImpPalette& rPal = rRoot.GetPalette();
499         maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() );
500         maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16());
501     }
502 }
503 
Convert(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,sal_uInt16 nFormatIdx) const504 void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot,
505         ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
506 {
507     const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
508     if( IsAuto() )
509     {
510         XclChAreaFormat aAreaFmt;
511         aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ?
512             rRoot.GetSeriesFillAutoColor( nFormatIdx ) :
513             rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx );
514         aAreaFmt.mnPattern = EXC_PATT_SOLID;
515         rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode );
516     }
517     else
518     {
519         rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode );
520     }
521 }
522 
523 // ----------------------------------------------------------------------------
524 
XclImpChEscherFormat(const XclImpRoot & rRoot)525 XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot ) :
526     mnDffFillType( mso_fillSolid )
527 {
528     maData.mxItemSet.reset(
529         new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) );
530 }
531 
ReadHeaderRecord(XclImpStream & rStrm)532 void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm )
533 {
534     // read from stream - CHESCHERFORMAT uses own ID for record continuation
535     XclImpDffPropSet aPropSet( rStrm.GetRoot() );
536     rStrm.ResetRecord( true, rStrm.GetRecId() );
537     rStrm >> aPropSet;
538     // get the data
539     aPropSet.FillToItemSet( *maData.mxItemSet );
540     // get fill type from DFF property set
541     mnDffFillType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid );
542 }
543 
ReadSubRecord(XclImpStream & rStrm)544 void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm )
545 {
546     switch( rStrm.GetRecId() )
547     {
548         case EXC_ID_CHPICFORMAT:
549             rStrm >> maPicFmt.mnBmpMode;
550             rStrm.Ignore( 2 );
551             rStrm >> maPicFmt.mnFlags >> maPicFmt.mfScale;
552         break;
553     }
554 }
555 
Convert(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,bool bUsePicFmt) const556 void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot,
557         ScfPropertySet& rPropSet, XclChObjectType eObjType, bool bUsePicFmt ) const
558 {
559     const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
560     rRoot.ConvertEscherFormat( rPropSet, maData, bUsePicFmt ? &maPicFmt : 0, mnDffFillType, rFmtInfo.mePropMode );
561 }
562 
563 // ----------------------------------------------------------------------------
564 
XclImpChFrameBase(const XclChFormatInfo & rFmtInfo)565 XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo )
566 {
567     if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType )
568     {
569         case EXC_CHFRAMETYPE_AUTO:
570             mxLineFmt.reset( new XclImpChLineFormat );
571             if( rFmtInfo.mbIsFrame )
572                 mxAreaFmt.reset( new XclImpChAreaFormat );
573         break;
574         case EXC_CHFRAMETYPE_INVISIBLE:
575         {
576             XclChLineFormat aLineFmt;
577             ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
578             aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
579             mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
580             if( rFmtInfo.mbIsFrame )
581             {
582                 XclChAreaFormat aAreaFmt;
583                 ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
584                 aAreaFmt.mnPattern = EXC_PATT_NONE;
585                 mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
586             }
587         }
588         break;
589         default:
590             DBG_ERRORFILE( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
591     }
592 }
593 
ReadSubRecord(XclImpStream & rStrm)594 void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm )
595 {
596     switch( rStrm.GetRecId() )
597     {
598         case EXC_ID_CHLINEFORMAT:
599             mxLineFmt.reset( new XclImpChLineFormat );
600             mxLineFmt->ReadChLineFormat( rStrm );
601         break;
602         case EXC_ID_CHAREAFORMAT:
603             mxAreaFmt.reset( new XclImpChAreaFormat );
604             mxAreaFmt->ReadChAreaFormat( rStrm );
605         break;
606         case EXC_ID_CHESCHERFORMAT:
607             mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) );
608             mxEscherFmt->ReadRecordGroup( rStrm );
609         break;
610     }
611 }
612 
ConvertLineBase(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,sal_uInt16 nFormatIdx) const613 void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot,
614         ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
615 {
616     if( mxLineFmt.is() )
617         mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
618 }
619 
ConvertAreaBase(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,sal_uInt16 nFormatIdx,bool bUsePicFmt) const620 void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot,
621         ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
622 {
623     if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
624     {
625         // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
626         if( mxEscherFmt.is() )
627             mxEscherFmt->Convert( rRoot, rPropSet, eObjType, bUsePicFmt );
628         else if( mxAreaFmt.is() )
629             mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
630     }
631 }
632 
ConvertFrameBase(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,XclChObjectType eObjType,sal_uInt16 nFormatIdx,bool bUsePicFmt) const633 void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot,
634         ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
635 {
636     ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx );
637     ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx, bUsePicFmt );
638 }
639 
640 // ----------------------------------------------------------------------------
641 
XclImpChFrame(const XclImpChRoot & rRoot,XclChObjectType eObjType)642 XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) :
643     XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ),
644     XclImpChRoot( rRoot ),
645     meObjType( eObjType )
646 {
647 }
648 
ReadHeaderRecord(XclImpStream & rStrm)649 void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm )
650 {
651     rStrm >> maData.mnFormat >> maData.mnFlags;
652 }
653 
UpdateObjFrame(const XclObjLineData & rLineData,const XclObjFillData & rFillData)654 void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
655 {
656     const XclImpPalette& rPal = GetPalette();
657 
658     if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) )
659     {
660         // line formatting
661         XclChLineFormat aLineFmt;
662         aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx );
663         switch( rLineData.mnStyle )
664         {
665             case EXC_OBJ_LINE_SOLID:        aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;        break;
666             case EXC_OBJ_LINE_DASH:         aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH;         break;
667             case EXC_OBJ_LINE_DOT:          aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT;          break;
668             case EXC_OBJ_LINE_DASHDOT:      aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT;      break;
669             case EXC_OBJ_LINE_DASHDOTDOT:   aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT;   break;
670             case EXC_OBJ_LINE_MEDTRANS:     aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS;     break;
671             case EXC_OBJ_LINE_DARKTRANS:    aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS;    break;
672             case EXC_OBJ_LINE_LIGHTTRANS:   aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS;   break;
673             case EXC_OBJ_LINE_NONE:         aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;         break;
674             default:                        aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
675         }
676         switch( rLineData.mnWidth )
677         {
678             case EXC_OBJ_LINE_HAIR:     aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;      break;
679             case EXC_OBJ_LINE_THIN:     aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE;    break;
680             case EXC_OBJ_LINE_MEDIUM:   aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE;    break;
681             case EXC_OBJ_LINE_THICK:    aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE;    break;
682             default:                    aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
683         }
684         ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() );
685         mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
686     }
687 
688     if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt )
689     {
690         // area formatting
691         XclChAreaFormat aAreaFmt;
692         aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx );
693         aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx );
694         aAreaFmt.mnPattern = rFillData.mnPattern;
695         ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() );
696         mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
697     }
698 }
699 
Convert(ScfPropertySet & rPropSet,bool bUsePicFmt) const700 void XclImpChFrame::Convert( ScfPropertySet& rPropSet, bool bUsePicFmt ) const
701 {
702     ConvertFrameBase( GetChRoot(), rPropSet, meObjType, EXC_CHDATAFORMAT_UNKNOWN, bUsePicFmt );
703 }
704 
705 // Source links ===============================================================
706 
707 namespace {
708 
709 /** Creates a labeled data sequence object, adds link for series title if present. */
lclCreateLabeledDataSequence(XclImpChSourceLinkRef xValueLink,const OUString & rValueRole,const XclImpChSourceLink * pTitleLink=0)710 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
711         XclImpChSourceLinkRef xValueLink, const OUString& rValueRole,
712         const XclImpChSourceLink* pTitleLink = 0 )
713 {
714     // create data sequence for values and title
715     Reference< XDataSequence > xValueSeq;
716     if( xValueLink.is() )
717         xValueSeq = xValueLink->CreateDataSequence( rValueRole );
718     Reference< XDataSequence > xTitleSeq;
719     if( pTitleLink )
720         xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL );
721 
722     // create the labeled data sequence, if values or title are present
723     Reference< XLabeledDataSequence > xLabeledSeq;
724     if( xValueSeq.is() || xTitleSeq.is() )
725         xLabeledSeq.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LABELEDDATASEQ ), UNO_QUERY );
726     if( xLabeledSeq.is() )
727     {
728         if( xValueSeq.is() )
729             xLabeledSeq->setValues( xValueSeq );
730         if( xTitleSeq.is() )
731             xLabeledSeq->setLabel( xTitleSeq );
732     }
733     return xLabeledSeq;
734 }
735 
736 } // namespace
737 
738 // ----------------------------------------------------------------------------
739 
XclImpChSourceLink(const XclImpChRoot & rRoot)740 XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
741     XclImpChRoot( rRoot )
742 {
743 }
744 
~XclImpChSourceLink()745 XclImpChSourceLink::~XclImpChSourceLink()
746 {
747 }
748 
ReadChSourceLink(XclImpStream & rStrm)749 void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
750 {
751     rStrm   >> maData.mnDestType
752             >> maData.mnLinkType
753             >> maData.mnFlags
754             >> maData.mnNumFmtIdx;
755 
756     mxTokenArray.reset();
757     if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
758     {
759         // read token array
760         XclTokenArray aXclTokArr;
761         rStrm >> aXclTokArr;
762 
763         // convert BIFF formula tokens to Calc token array
764         if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) )
765             mxTokenArray.reset( pTokens->Clone() );
766     }
767 
768     // try to read a following CHSTRING record
769     if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() )
770     {
771         mxString.reset( new XclImpString );
772         rStrm.Ignore( 2 );
773         mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
774     }
775 }
776 
SetString(const String & rString)777 void XclImpChSourceLink::SetString( const String& rString )
778 {
779     if( !mxString )
780         mxString.reset( new XclImpString );
781     mxString->SetText( rString );
782 }
783 
SetTextFormats(const XclFormatRunVec & rFormats)784 void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
785 {
786     if( mxString.is() )
787         mxString->SetFormats( rFormats );
788 }
789 
GetCellCount() const790 sal_uInt16 XclImpChSourceLink::GetCellCount() const
791 {
792     sal_uInt32 nCellCount = 0;
793     if( mxTokenArray.is() )
794     {
795         mxTokenArray->Reset();
796         for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() )
797         {
798             switch( pToken->GetType() )
799             {
800                 case ::formula::svSingleRef:
801                 case ::formula::svExternalSingleRef:
802                     // single cell
803                     ++nCellCount;
804                 break;
805                 case ::formula::svDoubleRef:
806                 case ::formula::svExternalDoubleRef:
807                 {
808                     // cell range
809                     const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
810                     const ScSingleRefData& rRef1 = rComplexRef.Ref1;
811                     const ScSingleRefData& rRef2 = rComplexRef.Ref2;
812                     sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
813                     sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
814                     sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
815                     nCellCount += nCols * nRows * nTabs;
816                 }
817                 break;
818                 default: ;
819             }
820         }
821     }
822     return limit_cast< sal_uInt16 >( nCellCount );
823 }
824 
ConvertNumFmt(ScfPropertySet & rPropSet,bool bPercent) const825 void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
826 {
827     bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
828     sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND;
829     OUString aPropName = bPercent ? EXC_CHPROP_PERCENTAGENUMFMT : EXC_CHPROP_NUMBERFORMAT;
830     if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
831         rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) );
832     else
833         // restore 'link to source' at data point (series may contain manual number format)
834         rPropSet.SetAnyProperty( aPropName, Any() );
835 }
836 
CreateDataSequence(const OUString & rRole) const837 Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const
838 {
839     Reference< XDataSequence > xDataSeq;
840     Reference< XDataProvider > xDataProv = GetDataProvider();
841     if( xDataProv.is() && mxTokenArray.is() )
842     {
843         ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray );
844         aComp.SetGrammar( ::formula::FormulaGrammar::GRAM_ENGLISH );
845         OUStringBuffer aRangeRep;
846         aComp.CreateStringFromTokenArray( aRangeRep );
847         try
848         {
849             xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() );
850             // set sequence role
851             ScfPropertySet aSeqProp( xDataSeq );
852             aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
853         }
854         catch( Exception& )
855         {
856 //            DBG_ERRORFILE( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
857         }
858     }
859     return xDataSeq;
860 }
861 
CreateStringSequence(const XclImpChRoot & rRoot,sal_uInt16 nLeadFontIdx,const Color & rLeadFontColor) const862 Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence(
863         const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const
864 {
865     ::std::vector< Reference< XFormattedString > > aStringVec;
866     if( mxString.is() )
867     {
868         for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt )
869         {
870             Reference< XFormattedString > xFmtStr(
871                 ScfApiHelper::CreateInstance( SERVICE_CHART2_FORMATTEDSTRING ), UNO_QUERY );
872             if( xFmtStr.is() )
873             {
874                 // set text data
875                 xFmtStr->setString( aIt.GetPortionText() );
876 
877                 // set font formatting and font color
878                 ScfPropertySet aStringProp( xFmtStr );
879                 sal_uInt16 nFontIdx = aIt.GetPortionFont();
880                 if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) )
881                     // leading unformatted portion - use passed font settings
882                     rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor );
883                 else
884                     rRoot.ConvertFont( aStringProp, nFontIdx );
885 
886                 // add string to vector of strings
887                 aStringVec.push_back( xFmtStr );
888             }
889         }
890     }
891     return ScfApiHelper::VectorToSequence( aStringVec );
892 }
893 
FillSourceLink(::std::vector<ScSharedTokenRef> & rTokens) const894 void XclImpChSourceLink::FillSourceLink( ::std::vector< ScSharedTokenRef >& rTokens ) const
895 {
896     if( !mxTokenArray.is() )
897         // no links to fill.
898         return;
899 
900     mxTokenArray->Reset();
901     for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next())
902     {
903         ScSharedTokenRef pToken(static_cast<ScToken*>(p->Clone()));
904         if (ScRefTokenHelper::isRef(pToken))
905             // This is a reference token.  Store it.
906             ScRefTokenHelper::join(rTokens, pToken);
907     }
908 }
909 
910 // Text =======================================================================
911 
~XclImpChFontBase()912 XclImpChFontBase::~XclImpChFontBase()
913 {
914 }
915 
ConvertFontBase(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet) const916 void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
917 {
918     Color aFontColor = GetFontColor();
919     rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor );
920 }
921 
ConvertRotationBase(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,bool bSupportsStacked) const922 void XclImpChFontBase::ConvertRotationBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet, bool bSupportsStacked ) const
923 {
924     rRoot.GetChartPropSetHelper().WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked );
925 }
926 
927 // ----------------------------------------------------------------------------
928 
XclImpChFont()929 XclImpChFont::XclImpChFont() :
930     mnFontIdx( EXC_FONT_NOTFOUND )
931 {
932 }
933 
ReadChFont(XclImpStream & rStrm)934 void XclImpChFont::ReadChFont( XclImpStream& rStrm )
935 {
936     rStrm >> mnFontIdx;
937 }
938 
939 // ----------------------------------------------------------------------------
940 
XclImpChText(const XclImpChRoot & rRoot)941 XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) :
942     XclImpChRoot( rRoot )
943 {
944 }
945 
ReadHeaderRecord(XclImpStream & rStrm)946 void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm )
947 {
948     rStrm   >> maData.mnHAlign
949             >> maData.mnVAlign
950             >> maData.mnBackMode
951             >> maData.maTextColor
952             >> maData.maRect
953             >> maData.mnFlags;
954 
955     if( GetBiff() == EXC_BIFF8 )
956     {
957         // #116397# BIFF8: index into palette used instead of RGB data
958         maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
959         // placement and rotation
960         rStrm >> maData.mnFlags2 >> maData.mnRotation;
961     }
962     else
963     {
964         // BIFF2-BIFF7: get rotation from text orientation
965         sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 );
966         maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
967     }
968 }
969 
ReadSubRecord(XclImpStream & rStrm)970 void XclImpChText::ReadSubRecord( XclImpStream& rStrm )
971 {
972     switch( rStrm.GetRecId() )
973     {
974         case EXC_ID_CHFRAMEPOS:
975             mxFramePos.reset( new XclImpChFramePos );
976             mxFramePos->ReadChFramePos( rStrm );
977         break;
978         case EXC_ID_CHFONT:
979             mxFont.reset( new XclImpChFont );
980             mxFont->ReadChFont( rStrm );
981         break;
982         case EXC_ID_CHFORMATRUNS:
983             if( GetBiff() == EXC_BIFF8 )
984                 XclImpString::ReadFormats( rStrm, maFormats );
985         break;
986         case EXC_ID_CHSOURCELINK:
987             mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
988             mxSrcLink->ReadChSourceLink( rStrm );
989         break;
990         case EXC_ID_CHFRAME:
991             mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) );
992             mxFrame->ReadRecordGroup( rStrm );
993         break;
994         case EXC_ID_CHOBJECTLINK:
995             rStrm >> maObjLink.mnTarget >> maObjLink.maPointPos.mnSeriesIdx >> maObjLink.maPointPos.mnPointIdx;
996         break;
997         case EXC_ID_CHFRLABELPROPS:
998             ReadChFrLabelProps( rStrm );
999         break;
1000         case EXC_ID_CHEND:
1001             if( mxSrcLink.is() && !maFormats.empty() )
1002                 mxSrcLink->SetTextFormats( maFormats );
1003         break;
1004     }
1005 }
1006 
GetFontIndex() const1007 sal_uInt16 XclImpChText::GetFontIndex() const
1008 {
1009     return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
1010 }
1011 
GetFontColor() const1012 Color XclImpChText::GetFontColor() const
1013 {
1014     return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
1015 }
1016 
GetRotation() const1017 sal_uInt16 XclImpChText::GetRotation() const
1018 {
1019     return maData.mnRotation;
1020 }
1021 
SetString(const String & rString)1022 void XclImpChText::SetString( const String& rString )
1023 {
1024     if( !mxSrcLink )
1025         mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
1026     mxSrcLink->SetString( rString );
1027 }
1028 
UpdateText(const XclImpChText * pParentText)1029 void XclImpChText::UpdateText( const XclImpChText* pParentText )
1030 {
1031     if( pParentText )
1032     {
1033         // update missing members
1034         if( !mxFrame )
1035             mxFrame = pParentText->mxFrame;
1036         if( !mxFont )
1037         {
1038             mxFont = pParentText->mxFont;
1039             // text color is taken from CHTEXT record, not from font in CHFONT
1040             ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) );
1041             maData.maTextColor = pParentText->maData.maTextColor;
1042         }
1043     }
1044 }
1045 
UpdateDataLabel(bool bCateg,bool bValue,bool bPercent)1046 void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent )
1047 {
1048     ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG,     bCateg );
1049     ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE,     bValue );
1050     ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT,   bPercent );
1051     ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent );
1052     ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED,       !bCateg && !bValue && !bPercent );
1053 }
1054 
ConvertFont(ScfPropertySet & rPropSet) const1055 void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const
1056 {
1057     ConvertFontBase( GetChRoot(), rPropSet );
1058 }
1059 
ConvertRotation(ScfPropertySet & rPropSet,bool bSupportsStacked) const1060 void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
1061 {
1062     ConvertRotationBase( GetChRoot(), rPropSet, bSupportsStacked );
1063 }
1064 
ConvertFrame(ScfPropertySet & rPropSet) const1065 void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const
1066 {
1067     if( mxFrame.is() )
1068         mxFrame->Convert( rPropSet );
1069 }
1070 
ConvertNumFmt(ScfPropertySet & rPropSet,bool bPercent) const1071 void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
1072 {
1073     if( mxSrcLink.is() )
1074         mxSrcLink->ConvertNumFmt( rPropSet, bPercent );
1075 }
1076 
ConvertDataLabel(ScfPropertySet & rPropSet,const XclChTypeInfo & rTypeInfo) const1077 void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const
1078 {
1079     // existing CHFRLABELPROPS record wins over flags from CHTEXT
1080     sal_uInt16 nShowFlags = mxLabelProps.is() ? mxLabelProps->mnFlags : maData.mnFlags;
1081     sal_uInt16 SHOWANYCATEG   = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG);
1082     sal_uInt16 SHOWANYVALUE   = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE;
1083     sal_uInt16 SHOWANYPERCENT = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC);
1084     sal_uInt16 SHOWANYBUBBLE  = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE;
1085 
1086     // get raw flags for label values
1087     bool bShowNone    = IsDeleted();
1088     bool bShowCateg   = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG );
1089     bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT );
1090     bool bShowValue   = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE );
1091     bool bShowBubble  = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE );
1092 
1093     // adjust to Chart2 behaviour
1094     if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
1095          bShowValue = bShowBubble;  // Chart2 bubble charts show bubble size if 'ShowValue' is set
1096 
1097     // other flags
1098     bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1099     bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL );
1100 
1101     // create API struct for label values, set API label separator
1102     cssc2::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
1103     rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel );
1104     String aSep = mxLabelProps.is() ? mxLabelProps->maSeparator : String( sal_Unicode( '\n' ) );
1105     if( aSep.Len() == 0 )
1106         aSep = CREATE_STRING( "; " );
1107     rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep );
1108 
1109     // text properties of attached label
1110     if( bShowAny )
1111     {
1112         ConvertFont( rPropSet );
1113         ConvertRotation( rPropSet, false );
1114         // label placement
1115         using namespace cssc::DataLabelPlacement;
1116         sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos;
1117         switch( ::extract_value< sal_uInt16 >( maData.mnFlags2, 0, 4 ) )
1118         {
1119             case EXC_CHTEXT_POS_DEFAULT:    nPlacement = rTypeInfo.mnDefaultLabelPos;   break;
1120             case EXC_CHTEXT_POS_OUTSIDE:    nPlacement = OUTSIDE;                       break;
1121             case EXC_CHTEXT_POS_INSIDE:     nPlacement = INSIDE;                        break;
1122             case EXC_CHTEXT_POS_CENTER:     nPlacement = CENTER;                        break;
1123             case EXC_CHTEXT_POS_AXIS:       nPlacement = NEAR_ORIGIN;                   break;
1124             case EXC_CHTEXT_POS_ABOVE:      nPlacement = TOP;                           break;
1125             case EXC_CHTEXT_POS_BELOW:      nPlacement = BOTTOM;                        break;
1126             case EXC_CHTEXT_POS_LEFT:       nPlacement = LEFT;                          break;
1127             case EXC_CHTEXT_POS_RIGHT:      nPlacement = RIGHT;                         break;
1128             case EXC_CHTEXT_POS_AUTO:       nPlacement = AVOID_OVERLAP;                 break;
1129         }
1130         rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement );
1131         // label number format (percentage format wins over value format)
1132         if( bShowPercent || bShowValue )
1133             ConvertNumFmt( rPropSet, bShowPercent );
1134     }
1135 }
1136 
CreateTitle() const1137 Reference< XTitle > XclImpChText::CreateTitle() const
1138 {
1139     Reference< XTitle > xTitle;
1140     if( mxSrcLink.is() && mxSrcLink->HasString() )
1141     {
1142         // create the formatted strings
1143         Sequence< Reference< XFormattedString > > aStringSeq(
1144             mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
1145         if( aStringSeq.hasElements() )
1146         {
1147             // create the title object
1148             xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY );
1149             if( xTitle.is() )
1150             {
1151                 // set the formatted strings
1152                 xTitle->setText( aStringSeq );
1153                 // more title formatting properties
1154                 ScfPropertySet aTitleProp( xTitle );
1155                 ConvertFrame( aTitleProp );
1156                 ConvertRotation( aTitleProp, true );
1157             }
1158         }
1159     }
1160     return xTitle;
1161 }
1162 
ConvertTitlePosition(const XclChTextKey & rTitleKey) const1163 void XclImpChText::ConvertTitlePosition( const XclChTextKey& rTitleKey ) const
1164 {
1165     if( !mxFramePos ) return;
1166 
1167     const XclChFramePos& rPosData = mxFramePos->GetFramePosData();
1168     OSL_ENSURE( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rPosData.mnBRMode == EXC_CHFRAMEPOS_PARENT),
1169         "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
1170 
1171     /*  Check if title is moved manually. To get the actual position of the
1172         title, we do some kind of hack and use the values from the CHTEXT
1173         record, effectively ignoring the contents of the CHFRAMEPOS record
1174         which contains the position relative to the default title position
1175         (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
1176         Especially when it comes to axis titles, things would become very
1177         complicated here, because the relative title position is stored in a
1178         measurement unit that is dependent on the size of the inner plot area,
1179         the interpretation of the X and Y coordinate is dependent on the
1180         direction of the axis, and in 3D charts, and the title default
1181         positions are dependent on the 3D view settings (rotation, elevation,
1182         and perspective). Thus, it is easier to assume that the creator has
1183         written out the correct absolute position and size of the title in the
1184         CHTEXT record. This is assured by checking that the shape size stored
1185         in the CHTEXT record is non-zero. */
1186     if( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) &&
1187         ((rPosData.maRect.mnX != 0) || (rPosData.maRect.mnY != 0)) &&
1188         (maData.maRect.mnWidth > 0) && (maData.maRect.mnHeight > 0) ) try
1189     {
1190         Reference< XShape > xTitleShape( GetTitleShape( rTitleKey ), UNO_SET_THROW );
1191         // the call to XShape.getSize() may recalc the chart view
1192         ::com::sun::star::awt::Size aTitleSize = xTitleShape->getSize();
1193         // rotated titles need special handling...
1194         sal_Int32 nScRot = XclTools::GetScRotation( GetRotation(), 0 );
1195         double fRad = nScRot * F_PI18000;
1196         double fSin = fabs( sin( fRad ) );
1197         double fCos = fabs( cos( fRad ) );
1198         ::com::sun::star::awt::Size aBoundSize(
1199             static_cast< sal_Int32 >( fCos * aTitleSize.Width + fSin * aTitleSize.Height + 0.5 ),
1200             static_cast< sal_Int32 >( fSin * aTitleSize.Width + fCos * aTitleSize.Height + 0.5 ) );
1201         // calculate the title position from the values in the CHTEXT record
1202         ::com::sun::star::awt::Point aTitlePos(
1203             CalcHmmFromChartX( maData.maRect.mnX ),
1204             CalcHmmFromChartY( maData.maRect.mnY ) );
1205         // add part of height to X direction, if title is rotated down (clockwise)
1206         if( nScRot > 18000 )
1207             aTitlePos.X += static_cast< sal_Int32 >( fSin * aTitleSize.Height + 0.5 );
1208         // add part of width to Y direction, if title is rotated up (counterclockwise)
1209         else if( nScRot > 0 )
1210             aTitlePos.Y += static_cast< sal_Int32 >( fSin * aTitleSize.Width + 0.5 );
1211         // set the resulting position at the title shape
1212         xTitleShape->setPosition( aTitlePos );
1213     }
1214     catch( Exception& )
1215     {
1216     }
1217 }
1218 
ReadChFrLabelProps(XclImpStream & rStrm)1219 void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm )
1220 {
1221     if( GetBiff() == EXC_BIFF8 )
1222     {
1223         mxLabelProps.reset( new XclChFrLabelProps );
1224         sal_uInt16 nSepLen;
1225         rStrm.Ignore( 12 );
1226         rStrm >> mxLabelProps->mnFlags >> nSepLen;
1227         if( nSepLen > 0 )
1228             mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen );
1229     }
1230 }
1231 
1232 namespace {
1233 
lclUpdateText(XclImpChTextRef & rxText,XclImpChTextRef xDefText)1234 void lclUpdateText( XclImpChTextRef& rxText, XclImpChTextRef xDefText )
1235 {
1236     if( rxText.is() )
1237         rxText->UpdateText( xDefText.get() );
1238     else
1239         rxText = xDefText;
1240 }
1241 
lclFinalizeTitle(XclImpChTextRef & rxTitle,XclImpChTextRef xDefText,const String & rAutoTitle)1242 void lclFinalizeTitle( XclImpChTextRef& rxTitle, XclImpChTextRef xDefText, const String& rAutoTitle )
1243 {
1244     /*  Do not update a title, if it is not visible (if rxTitle is null).
1245         Existing reference indicates enabled title. */
1246     if( rxTitle.is() )
1247     {
1248         if( !rxTitle->HasString() )
1249             rxTitle->SetString( rAutoTitle );
1250         if( rxTitle->HasString() )
1251             rxTitle->UpdateText( xDefText.get() );
1252         else
1253             rxTitle.reset();
1254     }
1255 }
1256 
1257 } // namespace
1258 
1259 // Data series ================================================================
1260 
ReadChMarkerFormat(XclImpStream & rStrm)1261 void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm )
1262 {
1263     rStrm >> maData.maLineColor >> maData.maFillColor >> maData.mnMarkerType >> maData.mnFlags;
1264 
1265     const XclImpRoot& rRoot = rStrm.GetRoot();
1266     if( rRoot.GetBiff() == EXC_BIFF8 )
1267     {
1268         // #116397# BIFF8: index into palette used instead of RGB data
1269         const XclImpPalette& rPal = rRoot.GetPalette();
1270         maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() );
1271         maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() );
1272         // marker size
1273         rStrm >> maData.mnMarkerSize;
1274     }
1275 }
1276 
Convert(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,sal_uInt16 nFormatIdx,sal_Int16 nLineWeight) const1277 void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot,
1278         ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const
1279 {
1280     if( IsAuto() )
1281     {
1282         XclChMarkerFormat aMarkerFmt;
1283         // line and fill color of the symbol are equal to series line color
1284         //! TODO: Excel sets no fill color for specific symbols (e.g. cross)
1285         aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx );
1286         switch( nLineWeight )
1287         {
1288             case EXC_CHLINEFORMAT_HAIR:     aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE;      break;
1289             case EXC_CHLINEFORMAT_SINGLE:   aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;    break;
1290             case EXC_CHLINEFORMAT_DOUBLE:   aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;    break;
1291             case EXC_CHLINEFORMAT_TRIPLE:   aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE;    break;
1292             default:                        aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;
1293         }
1294         aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
1295         rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, aMarkerFmt );
1296     }
1297     else
1298     {
1299         rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, maData );
1300     }
1301 }
1302 
ConvertColor(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet,sal_uInt16 nFormatIdx) const1303 void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot,
1304         ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
1305 {
1306     Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor;
1307     rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor );
1308 }
1309 
1310 // ----------------------------------------------------------------------------
1311 
XclImpChPieFormat()1312 XclImpChPieFormat::XclImpChPieFormat() :
1313     mnPieDist( 0 )
1314 {
1315 }
1316 
ReadChPieFormat(XclImpStream & rStrm)1317 void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm )
1318 {
1319     rStrm >> mnPieDist;
1320 }
1321 
Convert(ScfPropertySet & rPropSet) const1322 void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const
1323 {
1324     double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 );
1325     rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist );
1326 }
1327 
1328 // ----------------------------------------------------------------------------
1329 
XclImpChSeriesFormat()1330 XclImpChSeriesFormat::XclImpChSeriesFormat() :
1331     mnFlags( 0 )
1332 {
1333 }
1334 
ReadChSeriesFormat(XclImpStream & rStrm)1335 void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm )
1336 {
1337     rStrm >> mnFlags;
1338 }
1339 
1340 // ----------------------------------------------------------------------------
1341 
ReadCh3dDataFormat(XclImpStream & rStrm)1342 void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm )
1343 {
1344     rStrm >> maData.mnBase >> maData.mnTop;
1345 }
1346 
Convert(ScfPropertySet & rPropSet) const1347 void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const
1348 {
1349     using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1350     sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ?
1351         ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) :
1352         ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE);
1353     rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType );
1354 }
1355 
1356 // ----------------------------------------------------------------------------
1357 
XclImpChAttachedLabel(const XclImpChRoot & rRoot)1358 XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) :
1359     XclImpChRoot( rRoot ),
1360     mnFlags( 0 )
1361 {
1362 }
1363 
ReadChAttachedLabel(XclImpStream & rStrm)1364 void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm )
1365 {
1366     rStrm >> mnFlags;
1367 }
1368 
CreateDataLabel(XclImpChTextRef xParent) const1369 XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( XclImpChTextRef xParent ) const
1370 {
1371     const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE;
1372     const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC;
1373     const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC;
1374 
1375     XclImpChTextRef xLabel( xParent.is() ? new XclImpChText( *xParent ) : new XclImpChText( GetChRoot() ) );
1376     xLabel->UpdateDataLabel(
1377         ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ),
1378         ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ),
1379         ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) );
1380     return xLabel;
1381 }
1382 
1383 // ----------------------------------------------------------------------------
1384 
XclImpChDataFormat(const XclImpChRoot & rRoot)1385 XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) :
1386     XclImpChRoot( rRoot )
1387 {
1388 }
1389 
ReadHeaderRecord(XclImpStream & rStrm)1390 void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm )
1391 {
1392     rStrm   >> maData.maPointPos.mnPointIdx
1393             >> maData.maPointPos.mnSeriesIdx
1394             >> maData.mnFormatIdx
1395             >> maData.mnFlags;
1396 }
1397 
ReadSubRecord(XclImpStream & rStrm)1398 void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm )
1399 {
1400     switch( rStrm.GetRecId() )
1401     {
1402         case EXC_ID_CHMARKERFORMAT:
1403             mxMarkerFmt.reset( new XclImpChMarkerFormat );
1404             mxMarkerFmt->ReadChMarkerFormat( rStrm );
1405         break;
1406         case EXC_ID_CHPIEFORMAT:
1407             mxPieFmt.reset( new XclImpChPieFormat );
1408             mxPieFmt->ReadChPieFormat( rStrm );
1409         break;
1410         case EXC_ID_CHSERIESFORMAT:
1411             mxSeriesFmt.reset( new XclImpChSeriesFormat );
1412             mxSeriesFmt->ReadChSeriesFormat( rStrm );
1413         break;
1414         case EXC_ID_CH3DDATAFORMAT:
1415             mx3dDataFmt.reset( new XclImpCh3dDataFormat );
1416             mx3dDataFmt->ReadCh3dDataFormat( rStrm );
1417         break;
1418         case EXC_ID_CHATTACHEDLABEL:
1419             mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) );
1420             mxAttLabel->ReadChAttachedLabel( rStrm );
1421         break;
1422         default:
1423             XclImpChFrameBase::ReadSubRecord( rStrm );
1424     }
1425 }
1426 
SetPointPos(const XclChDataPointPos & rPointPos,sal_uInt16 nFormatIdx)1427 void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx )
1428 {
1429     maData.maPointPos = rPointPos;
1430     maData.mnFormatIdx = nFormatIdx;
1431 }
1432 
UpdateGroupFormat(const XclChExtTypeInfo & rTypeInfo)1433 void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo )
1434 {
1435     // remove formats not used for the current chart type
1436     RemoveUnusedFormats( rTypeInfo );
1437 }
1438 
UpdateSeriesFormat(const XclChExtTypeInfo & rTypeInfo,const XclImpChDataFormat * pGroupFmt)1439 void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt )
1440 {
1441     // update missing formats from passed chart type group format
1442     if( pGroupFmt )
1443     {
1444         if( !mxLineFmt )
1445             mxLineFmt = pGroupFmt->mxLineFmt;
1446         if( !mxAreaFmt && !mxEscherFmt )
1447         {
1448             mxAreaFmt = pGroupFmt->mxAreaFmt;
1449             mxEscherFmt = pGroupFmt->mxEscherFmt;
1450         }
1451         if( !mxMarkerFmt )
1452             mxMarkerFmt = pGroupFmt->mxMarkerFmt;
1453         if( !mxPieFmt )
1454             mxPieFmt = pGroupFmt->mxPieFmt;
1455         if( !mxSeriesFmt )
1456             mxSeriesFmt = pGroupFmt->mxSeriesFmt;
1457         if( !mx3dDataFmt )
1458             mx3dDataFmt = pGroupFmt->mx3dDataFmt;
1459         if( !mxAttLabel )
1460             mxAttLabel = pGroupFmt->mxAttLabel;
1461     }
1462 
1463     /*  Create missing but required formats. Existing line, area, and marker
1464         format objects are needed to create automatic series formatting. */
1465     if( !mxLineFmt )
1466         mxLineFmt.reset( new XclImpChLineFormat );
1467     if( !mxAreaFmt && !mxEscherFmt )
1468         mxAreaFmt.reset( new XclImpChAreaFormat );
1469     if( !mxMarkerFmt )
1470         mxMarkerFmt.reset( new XclImpChMarkerFormat );
1471 
1472     // remove formats not used for the current chart type
1473     RemoveUnusedFormats( rTypeInfo );
1474     // update data label
1475     UpdateDataLabel( pGroupFmt );
1476 }
1477 
UpdatePointFormat(const XclChExtTypeInfo & rTypeInfo,const XclImpChDataFormat * pSeriesFmt)1478 void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt )
1479 {
1480     // remove formats if they are automatic in this and in the passed series format
1481     if( pSeriesFmt )
1482     {
1483         if( IsAutoLine() && pSeriesFmt->IsAutoLine() )
1484             mxLineFmt.reset();
1485         if( IsAutoArea() && pSeriesFmt->IsAutoArea() )
1486             mxAreaFmt.reset();
1487         if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() )
1488             mxMarkerFmt.reset();
1489         mxSeriesFmt.reset();
1490     }
1491 
1492     // Excel ignores 3D bar format for single data points
1493     mx3dDataFmt.reset();
1494     // remove point line formats for linear chart types, TODO: implement in OOChart
1495     if( !rTypeInfo.IsSeriesFrameFormat() )
1496         mxLineFmt.reset();
1497 
1498     // remove formats not used for the current chart type
1499     RemoveUnusedFormats( rTypeInfo );
1500     // update data label
1501     UpdateDataLabel( pSeriesFmt );
1502 }
1503 
UpdateTrendLineFormat()1504 void XclImpChDataFormat::UpdateTrendLineFormat()
1505 {
1506     if( !mxLineFmt )
1507         mxLineFmt.reset( new XclImpChLineFormat );
1508     mxAreaFmt.reset();
1509     mxEscherFmt.reset();
1510     mxMarkerFmt.reset();
1511     mxPieFmt.reset();
1512     mxSeriesFmt.reset();
1513     mx3dDataFmt.reset();
1514     mxAttLabel.reset();
1515     // update data label
1516     UpdateDataLabel( 0 );
1517 }
1518 
Convert(ScfPropertySet & rPropSet,const XclChExtTypeInfo & rTypeInfo) const1519 void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const
1520 {
1521     /*  Line and area format.
1522         #i71810# If the data points are filled with bitmaps, textures, or
1523         patterns, then only bar charts will use the CHPICFORMAT record to
1524         determine stacking/streching mode. All other chart types ignore this
1525         record and always use the property 'fill-type' from the DFF property
1526         set (streched for bitmaps, and stacked for textures and patterns). */
1527     bool bUsePicFmt = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR;
1528     ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx, bUsePicFmt );
1529 
1530 #if EXC_CHART2_3DBAR_HAIRLINES_ONLY
1531     // #i83151# only hair lines in 3D charts with filled data points
1532     if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt.is() && mxLineFmt->HasLine() )
1533         rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "BorderWidth" ), 0 );
1534 #endif
1535 
1536     // other formatting
1537     if( mxMarkerFmt.is() )
1538         mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() );
1539     if( mxPieFmt.is() )
1540         mxPieFmt->Convert( rPropSet );
1541     if( mx3dDataFmt.is() )
1542         mx3dDataFmt->Convert( rPropSet );
1543     if( mxLabel.is() )
1544         mxLabel->ConvertDataLabel( rPropSet, rTypeInfo );
1545 
1546     // 3D settings
1547     rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 );
1548 
1549     /*  Special case: set marker color as line color, if series line is not
1550         visible. This makes the color visible in the marker area.
1551         TODO: remove this if OOChart supports own colors in markers. */
1552     if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt.is() )
1553         mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx );
1554 }
1555 
ConvertLine(ScfPropertySet & rPropSet,XclChObjectType eObjType) const1556 void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
1557 {
1558     ConvertLineBase( GetChRoot(), rPropSet, eObjType );
1559 }
1560 
ConvertArea(ScfPropertySet & rPropSet,sal_uInt16 nFormatIdx,bool bUsePicFmt) const1561 void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const
1562 {
1563     ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx, bUsePicFmt );
1564 }
1565 
RemoveUnusedFormats(const XclChExtTypeInfo & rTypeInfo)1566 void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo )
1567 {
1568     // data point marker only in linear 2D charts
1569     if( rTypeInfo.IsSeriesFrameFormat() )
1570         mxMarkerFmt.reset();
1571     // pie format only in pie/donut charts
1572     if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
1573         mxPieFmt.reset();
1574     // 3D format only in 3D bar charts
1575     if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
1576         mx3dDataFmt.reset();
1577 }
1578 
UpdateDataLabel(const XclImpChDataFormat * pParentFmt)1579 void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt )
1580 {
1581     /*  CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
1582         records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
1583         group, the contents of the CHATTACHEDLABEL record are used. In this
1584         case a new CHTEXT group is created and filled with the settings from
1585         the CHATTACHEDLABEL record. */
1586     XclImpChTextRef xDefText;
1587     if( pParentFmt )
1588         xDefText = pParentFmt->GetDataLabel();
1589     if( !xDefText )
1590         xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL );
1591     if( mxLabel.is() )
1592         mxLabel->UpdateText( xDefText.get() );
1593     else if( mxAttLabel.is() )
1594         mxLabel = mxAttLabel->CreateDataLabel( xDefText );
1595 }
1596 
1597 // ----------------------------------------------------------------------------
1598 
XclImpChSerTrendLine(const XclImpChRoot & rRoot)1599 XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) :
1600     XclImpChRoot( rRoot )
1601 {
1602 }
1603 
ReadChSerTrendLine(XclImpStream & rStrm)1604 void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm )
1605 {
1606     rStrm   >> maData.mnLineType
1607             >> maData.mnOrder
1608             >> maData.mfIntercept
1609             >> maData.mnShowEquation
1610             >> maData.mnShowRSquared
1611             >> maData.mfForecastFor
1612             >> maData.mfForecastBack;
1613 }
1614 
CreateRegressionCurve() const1615 Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const
1616 {
1617     // trend line type
1618     OUString aService;
1619     switch( maData.mnLineType )
1620     {
1621         case EXC_CHSERTREND_POLYNOMIAL:
1622             // TODO: only linear trend lines are supported by OOChart (#i20819#)
1623             if( maData.mnOrder == 1 )
1624                 aService = SERVICE_CHART2_LINEARREGCURVE;
1625         break;
1626         case EXC_CHSERTREND_EXPONENTIAL:
1627             aService = SERVICE_CHART2_EXPREGCURVE;
1628         break;
1629         case EXC_CHSERTREND_LOGARITHMIC:
1630             aService = SERVICE_CHART2_LOGREGCURVE;
1631         break;
1632         case EXC_CHSERTREND_POWER:
1633             aService = SERVICE_CHART2_POTREGCURVE;
1634         break;
1635     }
1636     Reference< XRegressionCurve > xRegCurve;
1637     if( aService.getLength() > 0 )
1638         xRegCurve.set( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
1639 
1640     // trend line formatting
1641     if( xRegCurve.is() && mxDataFmt.is() )
1642     {
1643         ScfPropertySet aPropSet( xRegCurve );
1644         mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE );
1645 
1646         // #i83100# show equation and correlation coefficient
1647         ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() );
1648         aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 );
1649         aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 );
1650 
1651         // #i83100# formatting of the equation text box
1652         if( const XclImpChText* pLabel = mxDataFmt->GetDataLabel().get() )
1653         {
1654             pLabel->ConvertFont( aLabelProp );
1655             pLabel->ConvertFrame( aLabelProp );
1656             pLabel->ConvertNumFmt( aLabelProp, false );
1657         }
1658     }
1659 
1660     // missing features
1661     // #i20819# polynomial trend lines
1662     // #i66819# moving average trend lines
1663     // #i5085# manual trend line size
1664     // #i34093# manual crossing point
1665 
1666     return xRegCurve;
1667 }
1668 
1669 // ----------------------------------------------------------------------------
1670 
XclImpChSerErrorBar(const XclImpChRoot & rRoot)1671 XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) :
1672     XclImpChRoot( rRoot )
1673 {
1674 }
1675 
ReadChSerErrorBar(XclImpStream & rStrm)1676 void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm )
1677 {
1678     rStrm >> maData.mnBarType >> maData.mnSourceType >> maData.mnLineEnd;
1679     rStrm.Ignore( 1 );
1680     rStrm >> maData.mfValue >> maData.mnValueCount;
1681 }
1682 
SetSeriesData(XclImpChSourceLinkRef xValueLink,XclImpChDataFormatRef xDataFmt)1683 void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef xValueLink, XclImpChDataFormatRef xDataFmt )
1684 {
1685     mxValueLink = xValueLink;
1686     mxDataFmt = xDataFmt;
1687 }
1688 
CreateValueSequence() const1689 Reference< XLabeledDataSequence > XclImpChSerErrorBar::CreateValueSequence() const
1690 {
1691     return lclCreateLabeledDataSequence( mxValueLink, XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ) );
1692 }
1693 
CreateErrorBar(const XclImpChSerErrorBar * pPosBar,const XclImpChSerErrorBar * pNegBar)1694 Reference< XPropertySet > XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar* pPosBar, const XclImpChSerErrorBar* pNegBar )
1695 {
1696     Reference< XPropertySet > xErrorBar;
1697 
1698     if( const XclImpChSerErrorBar* pPrimaryBar = pPosBar ? pPosBar : pNegBar )
1699     {
1700         xErrorBar.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR ), UNO_QUERY );
1701         ScfPropertySet aBarProp( xErrorBar );
1702 
1703         // plus/minus bars visible?
1704         aBarProp.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR, pPosBar != 0 );
1705         aBarProp.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR, pNegBar != 0 );
1706 
1707         // type of displayed error
1708         switch( pPrimaryBar->maData.mnSourceType )
1709         {
1710             case EXC_CHSERERR_PERCENT:
1711                 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::RELATIVE );
1712                 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1713                 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1714             break;
1715             case EXC_CHSERERR_FIXED:
1716                 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::ABSOLUTE );
1717                 aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
1718                 aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
1719             break;
1720             case EXC_CHSERERR_STDDEV:
1721                 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_DEVIATION );
1722                 aBarProp.SetProperty( EXC_CHPROP_WEIGHT, pPrimaryBar->maData.mfValue );
1723             break;
1724             case EXC_CHSERERR_STDERR:
1725                 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_ERROR );
1726             break;
1727             case EXC_CHSERERR_CUSTOM:
1728             {
1729                 aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::FROM_DATA );
1730                 // attach data sequences to erorr bar
1731                 Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
1732                 if( xDataSink.is() )
1733                 {
1734                     // create vector of all value sequences
1735                     ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
1736                     // add positive values
1737                     if( pPosBar )
1738                     {
1739                         Reference< XLabeledDataSequence > xValueSeq = pPosBar->CreateValueSequence();
1740                         if( xValueSeq.is() )
1741                             aLabeledSeqVec.push_back( xValueSeq );
1742                     }
1743                     // add negative values
1744                     if( pNegBar )
1745                     {
1746                         Reference< XLabeledDataSequence > xValueSeq = pNegBar->CreateValueSequence();
1747                         if( xValueSeq.is() )
1748                             aLabeledSeqVec.push_back( xValueSeq );
1749                     }
1750                     // attach labeled data sequences to series
1751                     if( aLabeledSeqVec.empty() )
1752                         xErrorBar.clear();
1753                     else
1754                         xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
1755                 }
1756             }
1757             break;
1758             default:
1759                 xErrorBar.clear();
1760         }
1761 
1762         // error bar formatting
1763         if( pPrimaryBar->mxDataFmt.is() && xErrorBar.is() )
1764             pPrimaryBar->mxDataFmt->ConvertLine( aBarProp, EXC_CHOBJTYPE_ERRORBAR );
1765     }
1766 
1767     return xErrorBar;
1768 }
1769 
1770 // ----------------------------------------------------------------------------
1771 
XclImpChSeries(const XclImpChRoot & rRoot,sal_uInt16 nSeriesIdx)1772 XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1773     XclImpChRoot( rRoot ),
1774     mnGroupIdx( EXC_CHSERGROUP_NONE ),
1775     mnSeriesIdx( nSeriesIdx ),
1776     mnParentIdx( EXC_CHSERIES_INVALID )
1777 {
1778 }
1779 
ReadHeaderRecord(XclImpStream & rStrm)1780 void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm )
1781 {
1782     rStrm >> maData.mnCategType >> maData.mnValueType >> maData.mnCategCount >> maData.mnValueCount;
1783     if( GetBiff() == EXC_BIFF8 )
1784         rStrm >> maData.mnBubbleType >> maData.mnBubbleCount;
1785 }
1786 
ReadSubRecord(XclImpStream & rStrm)1787 void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm )
1788 {
1789     switch( rStrm.GetRecId() )
1790     {
1791         case EXC_ID_CHSOURCELINK:
1792             ReadChSourceLink( rStrm );
1793         break;
1794         case EXC_ID_CHDATAFORMAT:
1795             ReadChDataFormat( rStrm );
1796         break;
1797         case EXC_ID_CHSERGROUP:
1798             rStrm >> mnGroupIdx;
1799         break;
1800         case EXC_ID_CHSERPARENT:
1801             ReadChSerParent( rStrm );
1802         break;
1803         case EXC_ID_CHSERTRENDLINE:
1804             ReadChSerTrendLine( rStrm );
1805         break;
1806         case EXC_ID_CHSERERRORBAR:
1807             ReadChSerErrorBar( rStrm );
1808         break;
1809     }
1810 }
1811 
SetDataFormat(XclImpChDataFormatRef xDataFmt)1812 void XclImpChSeries::SetDataFormat( XclImpChDataFormatRef xDataFmt )
1813 {
1814     if( xDataFmt.is() )
1815     {
1816         XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( xDataFmt->GetPointPos().mnPointIdx );
1817         // do not overwrite existing data format
1818         if( pxDataFmt && !*pxDataFmt )
1819         {
1820             *pxDataFmt = xDataFmt;
1821             // #i51639# register series format index at chart type group
1822             if( (pxDataFmt == &mxSeriesFmt) && !HasParentSeries() )
1823                 if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1824                     pTypeGroup->SetUsedFormatIndex( xDataFmt->GetFormatIdx() );
1825         }
1826     }
1827 }
1828 
SetDataLabel(XclImpChTextRef xLabel)1829 void XclImpChSeries::SetDataLabel( XclImpChTextRef xLabel )
1830 {
1831     if( xLabel.is() )
1832     {
1833         XclImpChTextRef* pxLabel = GetDataLabelRef( xLabel->GetPointPos().mnPointIdx );
1834         if( pxLabel && !*pxLabel )
1835             *pxLabel = xLabel;
1836     }
1837 }
1838 
AddChildSeries(const XclImpChSeries & rSeries)1839 void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries )
1840 {
1841     DBG_ASSERT( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
1842 
1843     /*  In Excel, trend lines and error bars are stored as own series. In Calc,
1844         these are properties of the parent series. This function adds the
1845         settings of the passed series to this series. */
1846     maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() );
1847     maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() );
1848 }
1849 
FinalizeDataFormats()1850 void XclImpChSeries::FinalizeDataFormats()
1851 {
1852     if( HasParentSeries() )
1853     {
1854         // *** series is a child series, e.g. trend line or error bar ***
1855 
1856         // create missing series format
1857         if( !mxSeriesFmt )
1858             mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 );
1859 
1860         if( mxSeriesFmt.is() )
1861         {
1862             // #i83100# set text label format, e.g. for trend line equations
1863             mxSeriesFmt->SetDataLabel( maLabels.get( EXC_CHDATAFORMAT_ALLPOINTS ) );
1864             // create missing automatic formats
1865             mxSeriesFmt->UpdateTrendLineFormat();
1866         }
1867 
1868         // copy series formatting to child objects
1869         for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt )
1870             (*aLIt)->SetDataFormat( mxSeriesFmt );
1871         for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt )
1872             aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt );
1873     }
1874     else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1875     {
1876         // *** series is a regular data series ***
1877 
1878         // create missing series format
1879         if( !mxSeriesFmt )
1880         {
1881             // #i51639# use a new unused format index to create series default format
1882             sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex();
1883             mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx );
1884         }
1885 
1886         // set text labels to data formats
1887         for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt )
1888         {
1889             if( XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( aTIt->first ) )
1890             {
1891                 if( !*pxDataFmt )
1892                     *pxDataFmt = CreateDataFormat( aTIt->first, EXC_CHDATAFORMAT_DEFAULT );
1893                 (*pxDataFmt)->SetDataLabel( aTIt->second );
1894             }
1895         }
1896 
1897         // update series format (copy missing formatting from group default format)
1898         if( mxSeriesFmt.is() )
1899             mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() );
1900 
1901         // update data point formats (removes unchanged automatic formatting)
1902         for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt )
1903             aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() );
1904     }
1905 }
1906 
1907 namespace {
1908 
1909 /** Returns the property set of the specified data point. */
lclGetPointPropSet(Reference<XDataSeries> xDataSeries,sal_uInt16 nPointIdx)1910 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx )
1911 {
1912     ScfPropertySet aPropSet;
1913     try
1914     {
1915         aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) );
1916     }
1917     catch( Exception& )
1918     {
1919         DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1920     }
1921     return aPropSet;
1922 }
1923 
1924 } // namespace
1925 
CreateValueSequence(const OUString & rValueRole) const1926 Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const
1927 {
1928     return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() );
1929 }
1930 
CreateCategSequence(const OUString & rCategRole) const1931 Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const
1932 {
1933     return lclCreateLabeledDataSequence( mxCategLink, rCategRole );
1934 }
1935 
CreateDataSeries() const1936 Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const
1937 {
1938     Reference< XDataSeries > xDataSeries;
1939     if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
1940     {
1941         const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo();
1942 
1943         // create the data series object
1944         xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
1945 
1946         // attach data and title sequences to series
1947         Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
1948         if( xDataSink.is() )
1949         {
1950             // create vector of all value sequences
1951             ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
1952             // add Y values
1953             Reference< XLabeledDataSequence > xYValueSeq =
1954                 CreateValueSequence( EXC_CHPROP_ROLE_YVALUES );
1955             if( xYValueSeq.is() )
1956                 aLabeledSeqVec.push_back( xYValueSeq );
1957             // add X values
1958             if( !rTypeInfo.mbCategoryAxis )
1959             {
1960                 Reference< XLabeledDataSequence > xXValueSeq =
1961                     CreateCategSequence( EXC_CHPROP_ROLE_XVALUES );
1962                 if( xXValueSeq.is() )
1963                     aLabeledSeqVec.push_back( xXValueSeq );
1964                 // add size values of bubble charts
1965                 if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
1966                 {
1967                     Reference< XLabeledDataSequence > xSizeValueSeq =
1968                         lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() );
1969                     if( xSizeValueSeq.is() )
1970                         aLabeledSeqVec.push_back( xSizeValueSeq );
1971                 }
1972             }
1973             // attach labeled data sequences to series
1974             if( !aLabeledSeqVec.empty() )
1975                 xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
1976         }
1977 
1978         // series formatting
1979         ScfPropertySet aSeriesProp( xDataSeries );
1980         if( mxSeriesFmt.is() )
1981             mxSeriesFmt->Convert( aSeriesProp, rTypeInfo );
1982 
1983         // trend lines
1984         ConvertTrendLines( xDataSeries );
1985 
1986         // error bars
1987         Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1988         if( xErrorBarX.is() )
1989             aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX );
1990         Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1991         if( xErrorBarY.is() )
1992             aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY );
1993 
1994         // own area formatting for every data point (TODO: varying line color not supported)
1995         bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat();
1996 #if EXC_CHART2_VARYCOLORSBY_PROP
1997         aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt );
1998 #else
1999         aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
2000 #endif
2001         // #i91271# always set area formatting for every point in pie/doughnut charts
2002         if( mxSeriesFmt.is() && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)) )
2003         {
2004             for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx )
2005             {
2006                 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
2007                 mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx, false );
2008             }
2009         }
2010 
2011         // data point formatting
2012         for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt )
2013         {
2014             ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first );
2015             aIt->second->Convert( aPointProp, rTypeInfo );
2016         }
2017     }
2018     return xDataSeries;
2019 }
2020 
FillAllSourceLinks(::std::vector<ScSharedTokenRef> & rTokens) const2021 void XclImpChSeries::FillAllSourceLinks( ::std::vector< ScSharedTokenRef >& rTokens ) const
2022 {
2023     if( mxValueLink.is() )
2024         mxValueLink->FillSourceLink( rTokens );
2025     if( mxCategLink.is() )
2026         mxCategLink->FillSourceLink( rTokens );
2027     if( mxTitleLink.is() )
2028         mxTitleLink->FillSourceLink( rTokens );
2029     if( mxBubbleLink.is() )
2030         mxBubbleLink->FillSourceLink( rTokens );
2031 }
2032 
ReadChSourceLink(XclImpStream & rStrm)2033 void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm )
2034 {
2035     XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
2036     xSrcLink->ReadChSourceLink( rStrm );
2037     switch( xSrcLink->GetDestType() )
2038     {
2039         case EXC_CHSRCLINK_TITLE:       mxTitleLink = xSrcLink;     break;
2040         case EXC_CHSRCLINK_VALUES:      mxValueLink = xSrcLink;     break;
2041         case EXC_CHSRCLINK_CATEGORY:    mxCategLink = xSrcLink;     break;
2042         case EXC_CHSRCLINK_BUBBLES:     mxBubbleLink = xSrcLink;    break;
2043     }
2044 }
2045 
ReadChDataFormat(XclImpStream & rStrm)2046 void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm )
2047 {
2048     // #i51639# chart stores all data formats and assigns them later to the series
2049     GetChartData().ReadChDataFormat( rStrm );
2050 }
2051 
ReadChSerParent(XclImpStream & rStrm)2052 void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm )
2053 {
2054     rStrm >> mnParentIdx;
2055     // index to parent series is 1-based, convert it to 0-based
2056     if( mnParentIdx > 0 )
2057         --mnParentIdx;
2058     else
2059         mnParentIdx = EXC_CHSERIES_INVALID;
2060 }
2061 
ReadChSerTrendLine(XclImpStream & rStrm)2062 void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm )
2063 {
2064     XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
2065     xTrendLine->ReadChSerTrendLine( rStrm );
2066     maTrendLines.push_back( xTrendLine );
2067 }
2068 
ReadChSerErrorBar(XclImpStream & rStrm)2069 void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm )
2070 {
2071     XclImpChSerErrorBarRef xErrorBar( new XclImpChSerErrorBar( GetChRoot() ) );
2072     xErrorBar->ReadChSerErrorBar( rStrm );
2073     maErrorBars[ xErrorBar->GetBarType() ] = xErrorBar;
2074 }
2075 
CreateDataFormat(sal_uInt16 nPointIdx,sal_uInt16 nFormatIdx)2076 XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx )
2077 {
2078     XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2079     xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx );
2080     return xDataFmt;
2081 }
2082 
GetDataFormatRef(sal_uInt16 nPointIdx)2083 XclImpChDataFormatRef* XclImpChSeries::GetDataFormatRef( sal_uInt16 nPointIdx )
2084 {
2085     if( nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS )
2086         return &mxSeriesFmt;
2087     if( nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT )
2088         return &maPointFmts[ nPointIdx ];
2089     return 0;
2090 }
2091 
GetDataLabelRef(sal_uInt16 nPointIdx)2092 XclImpChTextRef* XclImpChSeries::GetDataLabelRef( sal_uInt16 nPointIdx )
2093 {
2094     if( (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS) || (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT) )
2095         return &maLabels[ nPointIdx ];
2096     return 0;
2097 }
2098 
ConvertTrendLines(Reference<XDataSeries> xDataSeries) const2099 void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const
2100 {
2101     Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2102     if( xRegCurveCont.is() )
2103     {
2104         for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt )
2105         {
2106             try
2107             {
2108                 Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve();
2109                 if( xRegCurve.is() )
2110                     xRegCurveCont->addRegressionCurve( xRegCurve );
2111             }
2112             catch( Exception& )
2113             {
2114                 DBG_ERRORFILE( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
2115             }
2116         }
2117     }
2118 }
2119 
CreateErrorBar(sal_uInt8 nPosBarId,sal_uInt8 nNegBarId) const2120 Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const
2121 {
2122     return XclImpChSerErrorBar::CreateErrorBar( maErrorBars.get( nPosBarId ).get(), maErrorBars.get( nNegBarId ).get() );
2123 }
2124 
2125 // Chart type groups ==========================================================
2126 
XclImpChType(const XclImpChRoot & rRoot)2127 XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) :
2128     XclImpChRoot( rRoot ),
2129     mnRecId( EXC_ID_CHUNKNOWN ),
2130     maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2131 {
2132 }
2133 
ReadChType(XclImpStream & rStrm)2134 void XclImpChType::ReadChType( XclImpStream& rStrm )
2135 {
2136     sal_uInt16 nRecId = rStrm.GetRecId();
2137     bool bKnownType = true;
2138 
2139     switch( nRecId )
2140     {
2141         case EXC_ID_CHBAR:
2142             rStrm >> maData.mnOverlap >> maData.mnGap >> maData.mnFlags;
2143         break;
2144 
2145         case EXC_ID_CHLINE:
2146         case EXC_ID_CHAREA:
2147         case EXC_ID_CHRADARLINE:
2148         case EXC_ID_CHRADARAREA:
2149             rStrm >> maData.mnFlags;
2150         break;
2151 
2152         case EXC_ID_CHPIE:
2153             rStrm >> maData.mnRotation >> maData.mnPieHole;
2154             if( GetBiff() == EXC_BIFF8 )
2155                 rStrm >> maData.mnFlags;
2156             else
2157                 maData.mnFlags = 0;
2158         break;
2159 
2160         case EXC_ID_CHPIEEXT:
2161             maData.mnRotation = 0;
2162             maData.mnPieHole = 0;
2163             maData.mnFlags = 0;
2164         break;
2165 
2166         case EXC_ID_CHSCATTER:
2167             if( GetBiff() == EXC_BIFF8 )
2168                 rStrm >> maData.mnBubbleSize >> maData.mnBubbleType >> maData.mnFlags;
2169             else
2170                 maData.mnFlags = 0;
2171         break;
2172 
2173         case EXC_ID_CHSURFACE:
2174             rStrm >> maData.mnFlags;
2175         break;
2176 
2177         default:
2178             bKnownType = false;
2179     }
2180 
2181     if( bKnownType )
2182         mnRecId = nRecId;
2183 }
2184 
Finalize(bool bStockChart)2185 void XclImpChType::Finalize( bool bStockChart )
2186 {
2187     switch( mnRecId )
2188     {
2189         case EXC_ID_CHLINE:
2190             maTypeInfo = GetChartTypeInfo( bStockChart ?
2191                 EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE );
2192         break;
2193         case EXC_ID_CHBAR:
2194             maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2195                 maData.mnFlags, EXC_CHBAR_HORIZONTAL,
2196                 EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) );
2197         break;
2198         case EXC_ID_CHPIE:
2199             maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ?
2200                 EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2201         break;
2202         case EXC_ID_CHSCATTER:
2203             maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
2204                 maData.mnFlags, EXC_CHSCATTER_BUBBLES,
2205                 EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) );
2206         break;
2207         default:
2208             maTypeInfo = GetChartTypeInfo( mnRecId );
2209     }
2210 
2211     switch( maTypeInfo.meTypeId )
2212     {
2213         case EXC_CHTYPEID_PIEEXT:
2214         case EXC_CHTYPEID_BUBBLES:
2215         case EXC_CHTYPEID_SURFACE:
2216         case EXC_CHTYPEID_UNKNOWN:
2217             GetTracer().TraceChartUnKnownType();
2218         break;
2219         default:;
2220     }
2221 }
2222 
IsStacked() const2223 bool XclImpChType::IsStacked() const
2224 {
2225     bool bStacked = false;
2226     if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2227     {
2228         case EXC_CHTYPECATEG_LINE:
2229             bStacked =
2230                 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2231                 !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2232         break;
2233         case EXC_CHTYPECATEG_BAR:
2234             bStacked =
2235                 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2236                 !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2237         break;
2238         default:;
2239     }
2240     return bStacked;
2241 }
2242 
IsPercent() const2243 bool XclImpChType::IsPercent() const
2244 {
2245     bool bPercent = false;
2246     if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
2247     {
2248         case EXC_CHTYPECATEG_LINE:
2249             bPercent =
2250                 ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
2251                 ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
2252         break;
2253         case EXC_CHTYPECATEG_BAR:
2254             bPercent =
2255                 ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
2256                 ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
2257         break;
2258         default:;
2259     }
2260     return bPercent;
2261 }
2262 
HasCategoryLabels() const2263 bool XclImpChType::HasCategoryLabels() const
2264 {
2265     // radar charts disable category labels in chart type, not in CHTICK of X axis
2266     return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS );
2267 }
2268 
CreateCoordSystem(bool b3dChart) const2269 Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const
2270 {
2271     // service name
2272     OUString aCoordSysService;
2273     if( maTypeInfo.mbPolarCoordSystem )
2274     {
2275         if( b3dChart )
2276             aCoordSysService = SERVICE_CHART2_POLARCOORDSYS3D;
2277         else
2278             aCoordSysService = SERVICE_CHART2_POLARCOORDSYS2D;
2279     }
2280     else
2281     {
2282         if( b3dChart )
2283             aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS3D;
2284         else
2285             aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS2D;
2286     }
2287 
2288     // create the coordinate system object
2289     Reference< XCoordinateSystem > xCoordSystem( ScfApiHelper::CreateInstance( aCoordSysService ), UNO_QUERY );
2290 
2291     // swap X and Y axis
2292     if( maTypeInfo.mbSwappedAxesSet )
2293     {
2294         ScfPropertySet aCoordSysProp( xCoordSystem );
2295         aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true );
2296     }
2297 
2298     return xCoordSystem;
2299 }
2300 
CreateChartType(Reference<XDiagram> xDiagram,bool b3dChart) const2301 Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const
2302 {
2303     OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
2304     Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
2305 
2306     // additional properties
2307     switch( maTypeInfo.meTypeCateg )
2308     {
2309         case EXC_CHTYPECATEG_BAR:
2310         {
2311             ScfPropertySet aTypeProp( xChartType );
2312             Sequence< sal_Int32 > aInt32Seq( 2 );
2313             aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap;
2314             aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq );
2315             aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap;
2316             aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq );
2317         }
2318         break;
2319         case EXC_CHTYPECATEG_PIE:
2320         {
2321             ScfPropertySet aTypeProp( xChartType );
2322             aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT );
2323             /*  #i85166# starting angle of first pie slice. 3D pie charts use Y
2324                 rotation setting in view3D element. Of-pie charts do not
2325                 support pie rotation. */
2326             if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) )
2327             {
2328                 ScfPropertySet aDiaProp( xDiagram );
2329                 XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation );
2330             }
2331         }
2332         break;
2333         default:;
2334     }
2335 
2336     return xChartType;
2337 }
2338 
2339 // ----------------------------------------------------------------------------
2340 
ReadChChart3d(XclImpStream & rStrm)2341 void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm )
2342 {
2343     rStrm   >> maData.mnRotation
2344             >> maData.mnElevation
2345             >> maData.mnEyeDist
2346             >> maData.mnRelHeight
2347             >> maData.mnRelDepth
2348             >> maData.mnDepthGap
2349             >> maData.mnFlags;
2350 }
2351 
Convert(ScfPropertySet & rPropSet,bool b3dWallChart) const2352 void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const
2353 {
2354     namespace cssd = ::com::sun::star::drawing;
2355 
2356 //    #i104057# do not assert this, written by broken external generators
2357 //    DBG_ASSERT( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
2358 
2359     sal_Int32 nRotationY = 0;
2360     sal_Int32 nRotationX = 0;
2361     sal_Int32 nPerspective = 15;
2362     bool bRightAngled = false;
2363     cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE;
2364     Color aAmbientColor, aLightColor;
2365 
2366     if( b3dWallChart )
2367     {
2368         // Y rotation (Excel [0..359], Chart2 [-179,180])
2369         nRotationY = maData.mnRotation % 360;
2370         if( nRotationY > 180 ) nRotationY -= 360;
2371         // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2372         nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 );
2373         // perspective (Excel and Chart2 [0,100])
2374         nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2375         // right-angled axes
2376         bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D );
2377         // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
2378         bool bParallel = bRightAngled || (nPerspective == 0);
2379         eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
2380         // ambient color (Gray 20%)
2381         aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) );
2382         // light color (Gray 60%)
2383         aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) );
2384     }
2385     else
2386     {
2387         // Y rotation not used in pie charts, but 'first pie slice angle'
2388         nRotationY = 0;
2389         XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation );
2390         // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
2391         nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90;
2392         // perspective (Excel and Chart2 [0,100])
2393         nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
2394         // no right-angled axes in pie charts, but parallel projection
2395         bRightAngled = false;
2396         eProjMode = cssd::ProjectionMode_PARALLEL;
2397         // ambient color (Gray 30%)
2398         aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) );
2399         // light color (Gray 70%)
2400         aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) );
2401     }
2402 
2403     // properties
2404     rPropSet.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT, (sal_Int32)(maData.mnRelHeight / 2)); // seems to be 200%, cange to 100%
2405     rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY );
2406     rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX );
2407     rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective );
2408     rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled );
2409     rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode );
2410 
2411     // light settings
2412     rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT );
2413     rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor );
2414     rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false );
2415     rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true );
2416     rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor );
2417     rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
2418 }
2419 
2420 // ----------------------------------------------------------------------------
2421 
XclImpChLegend(const XclImpChRoot & rRoot)2422 XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) :
2423     XclImpChRoot( rRoot )
2424 {
2425 }
2426 
ReadHeaderRecord(XclImpStream & rStrm)2427 void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm )
2428 {
2429     rStrm >> maData.maRect >> maData.mnDockMode >> maData.mnSpacing >> maData.mnFlags;
2430 
2431     // trace unsupported features
2432     if( GetTracer().IsEnabled() )
2433     {
2434         if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED )
2435             GetTracer().TraceChartLegendPosition();
2436         if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) )
2437             GetTracer().TraceChartDataTable();
2438     }
2439 }
2440 
ReadSubRecord(XclImpStream & rStrm)2441 void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm )
2442 {
2443     switch( rStrm.GetRecId() )
2444     {
2445         case EXC_ID_CHFRAMEPOS:
2446             mxFramePos.reset( new XclImpChFramePos );
2447             mxFramePos->ReadChFramePos( rStrm );
2448         break;
2449         case EXC_ID_CHTEXT:
2450             mxText.reset( new XclImpChText( GetChRoot() ) );
2451             mxText->ReadRecordGroup( rStrm );
2452         break;
2453         case EXC_ID_CHFRAME:
2454             mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2455             mxFrame->ReadRecordGroup( rStrm );
2456         break;
2457     }
2458 }
2459 
Finalize()2460 void XclImpChLegend::Finalize()
2461 {
2462     // legend default formatting differs in OOChart and Excel, missing frame means automatic
2463     if( !mxFrame )
2464         mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2465     // Update text formatting. If mxText is empty, the passed default text is used.
2466     lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) );
2467 }
2468 
CreateLegend() const2469 Reference< XLegend > XclImpChLegend::CreateLegend() const
2470 {
2471     Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY );
2472     if( xLegend.is() )
2473     {
2474         ScfPropertySet aLegendProp( xLegend );
2475         aLegendProp.SetBoolProperty( EXC_CHPROP_SHOW, true );
2476 
2477         // frame properties
2478         if( mxFrame.is() )
2479             mxFrame->Convert( aLegendProp );
2480         // text properties
2481         if( mxText.is() )
2482             mxText->ConvertFont( aLegendProp );
2483 
2484         /*  Legend position and size. Default positions are used only if the
2485             plot area is positioned automatically (Excel sets the plot area to
2486             manual mode, if the legend is moved or resized). With manual plot
2487             areas, Excel ignores the value in maData.mnDockMode completely. */
2488         cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2489         cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2490         if( !GetChartData().IsManualPlotArea() ) switch( maData.mnDockMode )
2491         {
2492             case EXC_CHLEGEND_LEFT:
2493                 eApiPos = cssc2::LegendPosition_LINE_START;
2494                 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2495             break;
2496             case EXC_CHLEGEND_RIGHT:
2497             // top-right not supported
2498             case EXC_CHLEGEND_CORNER:
2499                 eApiPos = cssc2::LegendPosition_LINE_END;
2500                 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2501             break;
2502             case EXC_CHLEGEND_TOP:
2503                 eApiPos = cssc2::LegendPosition_PAGE_START;
2504                 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2505             break;
2506             case EXC_CHLEGEND_BOTTOM:
2507                 eApiPos = cssc2::LegendPosition_PAGE_END;
2508                 eApiExpand = cssc::ChartLegendExpansion_WIDE;
2509             break;
2510         }
2511 
2512         // no automatic position/size: try to find the correct position and size
2513         if( eApiPos == cssc2::LegendPosition_CUSTOM )
2514         {
2515             const XclChFramePos* pFramePos = mxFramePos.is() ? &mxFramePos->GetFramePosData() : 0;
2516 
2517             /*  Legend position. Only the settings from the CHFRAMEPOS record
2518                 are used by Excel, the position in the CHLEGEND record will be
2519                 ignored. */
2520             if( pFramePos )
2521             {
2522                 RelativePosition aRelPos(
2523                     CalcRelativeFromChartX( pFramePos->maRect.mnX ),
2524                     CalcRelativeFromChartY( pFramePos->maRect.mnY ),
2525                     ::com::sun::star::drawing::Alignment_TOP_LEFT );
2526                 aLegendProp.SetProperty( EXC_CHPROP_RELATIVEPOSITION, aRelPos );
2527             }
2528             else
2529             {
2530                 // no manual position/size found, just go for the default
2531                 eApiPos = cssc2::LegendPosition_LINE_END;
2532             }
2533 
2534             /*  Legend size. The member mnBRMode specifies whether size is
2535                 automatic or changes manually. Manual size is given in points,
2536                 not in chart units. */
2537             if( pFramePos && (pFramePos->mnBRMode == EXC_CHFRAMEPOS_ABSSIZE_POINTS) &&
2538                 (pFramePos->maRect.mnWidth > 0) && (pFramePos->maRect.mnHeight > 0) )
2539             {
2540                 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2541                 sal_Int32 nWidthHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnWidth / EXC_POINTS_PER_HMM );
2542                 sal_Int32 nHeightHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnHeight / EXC_POINTS_PER_HMM );
2543                 RelativeSize aRelSize( CalcRelativeFromHmmX( nWidthHmm ), CalcRelativeFromHmmY( nHeightHmm ) );
2544                 aLegendProp.SetProperty( EXC_CHPROP_RELATIVESIZE, aRelSize );
2545             }
2546             else
2547             {
2548                 // automatic size: determine entry direction from flags
2549                 eApiExpand = ::get_flagvalue( maData.mnFlags, EXC_CHLEGEND_STACKED,
2550                     cssc::ChartLegendExpansion_HIGH, cssc::ChartLegendExpansion_WIDE );
2551             }
2552         }
2553         aLegendProp.SetProperty( EXC_CHPROP_ANCHORPOSITION, eApiPos );
2554         aLegendProp.SetProperty( EXC_CHPROP_EXPANSION, eApiExpand );
2555     }
2556     return xLegend;
2557 }
2558 
2559 // ----------------------------------------------------------------------------
2560 
XclImpChDropBar(sal_uInt16 nDropBar)2561 XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) :
2562     mnDropBar( nDropBar ),
2563     mnBarDist( 0 )
2564 {
2565 }
2566 
ReadHeaderRecord(XclImpStream & rStrm)2567 void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm )
2568 {
2569     rStrm >> mnBarDist;
2570 }
2571 
Convert(const XclImpChRoot & rRoot,ScfPropertySet & rPropSet) const2572 void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
2573 {
2574     XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND;
2575     switch( mnDropBar )
2576     {
2577         case EXC_CHDROPBAR_UP:      eObjType = EXC_CHOBJTYPE_WHITEDROPBAR;  break;
2578         case EXC_CHDROPBAR_DOWN:    eObjType = EXC_CHOBJTYPE_BLACKDROPBAR;  break;
2579     }
2580     ConvertFrameBase( rRoot, rPropSet, eObjType );
2581 }
2582 
2583 // ----------------------------------------------------------------------------
2584 
XclImpChTypeGroup(const XclImpChRoot & rRoot)2585 XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) :
2586     XclImpChRoot( rRoot ),
2587     maType( rRoot ),
2588     maTypeInfo( maType.GetTypeInfo() )
2589 {
2590     // Initialize unused format indexes set. At this time, all formats are unused.
2591     for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx )
2592         maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx );
2593 }
2594 
ReadHeaderRecord(XclImpStream & rStrm)2595 void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm )
2596 {
2597     rStrm.Ignore( 16 );
2598     rStrm >> maData.mnFlags >> maData.mnGroupIdx;
2599 }
2600 
ReadSubRecord(XclImpStream & rStrm)2601 void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm )
2602 {
2603     switch( rStrm.GetRecId() )
2604     {
2605         case EXC_ID_CHCHART3D:
2606             mxChart3d.reset( new XclImpChChart3d );
2607             mxChart3d->ReadChChart3d( rStrm );
2608         break;
2609         case EXC_ID_CHLEGEND:
2610             mxLegend.reset( new XclImpChLegend( GetChRoot() ) );
2611             mxLegend->ReadRecordGroup( rStrm );
2612         break;
2613         case EXC_ID_CHDEFAULTTEXT:
2614             GetChartData().ReadChDefaultText( rStrm );
2615         break;
2616         case EXC_ID_CHDROPBAR:
2617             ReadChDropBar( rStrm );
2618         break;
2619         case EXC_ID_CHCHARTLINE:
2620             ReadChChartLine( rStrm );
2621         break;
2622         case EXC_ID_CHDATAFORMAT:
2623             ReadChDataFormat( rStrm );
2624         break;
2625         default:
2626             maType.ReadChType( rStrm );
2627     }
2628 }
2629 
Finalize()2630 void XclImpChTypeGroup::Finalize()
2631 {
2632     // check and set valid chart type
2633     bool bStockChart =
2634         (maType.GetRecId() == EXC_ID_CHLINE) &&         // must be a line chart
2635         !mxChart3d &&                                   // must be a 2d chart
2636         HasHiLoLine() &&                                // must contain hi-lo lines
2637         (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3));   // correct series count
2638     maType.Finalize( bStockChart );
2639 
2640     // extended type info
2641     maTypeInfo.Set( maType.GetTypeInfo(), mxChart3d.is(), false );
2642 
2643     // reverse series order for some unstacked 2D chart types
2644     if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() )
2645         ::std::reverse( maSeries.begin(), maSeries.end() );
2646 
2647     // update chart type group format, may depend on chart type finalized above
2648     if( mxGroupFmt.is() )
2649         mxGroupFmt->UpdateGroupFormat( maTypeInfo );
2650 }
2651 
AddSeries(XclImpChSeriesRef xSeries)2652 void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries )
2653 {
2654     if( xSeries.is() )
2655         maSeries.push_back( xSeries );
2656     // store first inserted series separately, series order may be reversed later
2657     if( !mxFirstSeries )
2658         mxFirstSeries = xSeries;
2659 }
2660 
SetUsedFormatIndex(sal_uInt16 nFormatIdx)2661 void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx )
2662 {
2663     maUnusedFormats.erase( nFormatIdx );
2664 }
2665 
PopUnusedFormatIndex()2666 sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex()
2667 {
2668     DBG_ASSERT( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
2669     sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin();
2670     SetUsedFormatIndex( nFormatIdx );
2671     return nFormatIdx;
2672 }
2673 
HasVarPointFormat() const2674 bool XclImpChTypeGroup::HasVarPointFormat() const
2675 {
2676     return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) &&
2677         ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) ||         // multiple series allowed
2678             ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) &&    // or exactly 1 series?
2679                 (maSeries.size() == 1)));
2680 }
2681 
HasConnectorLines() const2682 bool XclImpChTypeGroup::HasConnectorLines() const
2683 {
2684     // existence of connector lines (only in stacked bar charts)
2685     bool bAnyStacked = maType.IsStacked() || maType.IsPercent();
2686     XclImpChLineFormatRef xConnLine = maChartLines.get( EXC_CHCHARTLINE_CONNECT );
2687     return bAnyStacked && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) && xConnLine.is() && xConnLine->HasLine();
2688 }
2689 
GetSingleSeriesTitle() const2690 const String& XclImpChTypeGroup::GetSingleSeriesTitle() const
2691 {
2692     // no automatic title for series with trendlines or error bars
2693     // pie charts always show an automatic title, even if more series exist
2694     return (mxFirstSeries.is() && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ?
2695         mxFirstSeries->GetTitle() : String::EmptyString();
2696 }
2697 
ConvertChart3d(ScfPropertySet & rPropSet) const2698 void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const
2699 {
2700     if( mxChart3d.is() )
2701         mxChart3d->Convert( rPropSet, Is3dWallChart() );
2702 }
2703 
CreateCoordSystem() const2704 Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const
2705 {
2706     return maType.CreateCoordSystem( Is3dChart() );
2707 }
2708 
CreateChartType(Reference<XDiagram> xDiagram,sal_Int32 nApiAxesSetIdx) const2709 Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const
2710 {
2711     DBG_ASSERT( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
2712 
2713     // create the chart type object
2714     Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() );
2715 
2716     // bar chart connector lines
2717     if( HasConnectorLines() )
2718     {
2719         ScfPropertySet aDiaProp( xDiagram );
2720         aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true );
2721     }
2722 
2723     /*  Stock chart needs special processing. Create one 'big' series with
2724         data sequences of different roles. */
2725     if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2726         CreateStockSeries( xChartType, nApiAxesSetIdx );
2727     else
2728         CreateDataSeries( xChartType, nApiAxesSetIdx );
2729 
2730     return xChartType;
2731 }
2732 
CreateCategSequence() const2733 Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const
2734 {
2735     Reference< XLabeledDataSequence > xLabeledSeq;
2736     // create category sequence from first visible series
2737     if( mxFirstSeries.is() )
2738         xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG );
2739     return xLabeledSeq;
2740 }
2741 
ReadChDropBar(XclImpStream & rStrm)2742 void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm )
2743 {
2744     sal_uInt16 nDropBar = EXC_CHDROPBAR_NONE;
2745     if( !maDropBars.has( EXC_CHDROPBAR_UP ) )
2746         nDropBar = EXC_CHDROPBAR_UP;
2747     else if( !maDropBars.has( EXC_CHDROPBAR_DOWN ) )
2748         nDropBar = EXC_CHDROPBAR_DOWN;
2749 
2750     if( nDropBar != EXC_CHDROPBAR_NONE )
2751     {
2752         XclImpChDropBarRef xDropBar( new XclImpChDropBar( nDropBar ) );
2753         xDropBar->ReadRecordGroup( rStrm );
2754         maDropBars[ nDropBar ] = xDropBar;
2755     }
2756 }
2757 
ReadChChartLine(XclImpStream & rStrm)2758 void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm )
2759 {
2760     sal_uInt16 nLineId = rStrm.ReaduInt16();
2761     if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() )
2762     {
2763         XclImpChLineFormatRef xLineFmt( new XclImpChLineFormat );
2764         xLineFmt->ReadChLineFormat( rStrm );
2765         maChartLines[ nLineId ] = xLineFmt;
2766     }
2767 }
2768 
ReadChDataFormat(XclImpStream & rStrm)2769 void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm )
2770 {
2771     // global series and data point format
2772     XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
2773     xDataFmt->ReadRecordGroup( rStrm );
2774     const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
2775     if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) &&
2776             (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) )
2777         mxGroupFmt = xDataFmt;
2778 }
2779 
2780 
InsertDataSeries(Reference<XChartType> xChartType,Reference<XDataSeries> xSeries,sal_Int32 nApiAxesSetIdx) const2781 void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType,
2782         Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const
2783 {
2784     Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2785     if( xSeriesCont.is() && xSeries.is() )
2786     {
2787         // series stacking mode
2788         cssc2::StackingDirection eStacking = cssc2::StackingDirection_NO_STACKING;
2789         // stacked overrides deep-3d
2790         if( maType.IsStacked() || maType.IsPercent() )
2791             eStacking = cssc2::StackingDirection_Y_STACKING;
2792         else if( Is3dDeepChart() )
2793             eStacking = cssc2::StackingDirection_Z_STACKING;
2794 
2795         // additional series properties
2796         ScfPropertySet aSeriesProp( xSeries );
2797         aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking );
2798         aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx );
2799 
2800         // insert series into container
2801         try
2802         {
2803             xSeriesCont->addDataSeries( xSeries );
2804         }
2805         catch( Exception& )
2806         {
2807             DBG_ERRORFILE( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
2808         }
2809     }
2810 }
2811 
CreateDataSeries(Reference<XChartType> xChartType,sal_Int32 nApiAxesSetIdx) const2812 void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2813 {
2814     bool bSpline = false;
2815     for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
2816     {
2817         Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries();
2818         InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2819         bSpline |= (*aIt)->HasSpline();
2820     }
2821     // spline - TODO: set at single series (#i66858#)
2822     if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) )
2823     {
2824         ScfPropertySet aTypeProp( xChartType );
2825         aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES );
2826     }
2827 }
2828 
CreateStockSeries(Reference<XChartType> xChartType,sal_Int32 nApiAxesSetIdx) const2829 void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
2830 {
2831     // create the data series object
2832     Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
2833     Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
2834     if( xDataSink.is() )
2835     {
2836         // create a list of data sequences from all series
2837         ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
2838         DBG_ASSERT( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
2839         int nRoleIdx = (maSeries.size() == 3) ? 1 : 0;
2840         for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end();
2841                 (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
2842         {
2843             // create a data sequence with a specific role
2844             OUString aRole;
2845             switch( nRoleIdx )
2846             {
2847                 case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES;     break;
2848                 case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES;     break;
2849                 case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES;      break;
2850                 case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES;    break;
2851             }
2852             Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole );
2853             if( xDataSeq.is() )
2854                 aLabeledSeqVec.push_back( xDataSeq );
2855         }
2856 
2857         // attach labeled data sequences to series and insert series into chart type
2858         xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
2859 
2860         // formatting of special stock chart elements
2861         ScfPropertySet aTypeProp( xChartType );
2862         aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() );
2863         aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() );
2864         aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true );
2865         // hi-lo line format
2866         XclImpChLineFormatRef xHiLoLine = maChartLines.get( EXC_CHCHARTLINE_HILO );
2867         if( xHiLoLine.is() )
2868         {
2869             ScfPropertySet aSeriesProp( xDataSeries );
2870             xHiLoLine->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2871         }
2872         // white dropbar format
2873         XclImpChDropBarRef xUpBar = maDropBars.get( EXC_CHDROPBAR_UP );
2874         Reference< XPropertySet > xWhitePropSet;
2875         if( xUpBar.is() && aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY ) )
2876         {
2877             ScfPropertySet aBarProp( xWhitePropSet );
2878             xUpBar->Convert( GetChRoot(), aBarProp );
2879         }
2880         // black dropbar format
2881         XclImpChDropBarRef xDownBar = maDropBars.get( EXC_CHDROPBAR_DOWN );
2882         Reference< XPropertySet > xBlackPropSet;
2883         if( xDownBar.is() && aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY ) )
2884         {
2885             ScfPropertySet aBarProp( xBlackPropSet );
2886             xDownBar->Convert( GetChRoot(), aBarProp );
2887         }
2888 
2889         // insert the series into the chart type object
2890         InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
2891     }
2892 }
2893 
2894 // Axes =======================================================================
2895 
XclImpChLabelRange(const XclImpChRoot & rRoot)2896 XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) :
2897     XclImpChRoot( rRoot )
2898 {
2899 }
2900 
ReadChLabelRange(XclImpStream & rStrm)2901 void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm )
2902 {
2903     rStrm >> maLabelData.mnCross >> maLabelData.mnLabelFreq >> maLabelData.mnTickFreq >> maLabelData.mnFlags;
2904 }
2905 
ReadChDateRange(XclImpStream & rStrm)2906 void XclImpChLabelRange::ReadChDateRange( XclImpStream& rStrm )
2907 {
2908     rStrm   >> maDateData.mnMinDate
2909             >> maDateData.mnMaxDate
2910             >> maDateData.mnMajorStep
2911             >> maDateData.mnMajorUnit
2912             >> maDateData.mnMinorStep
2913             >> maDateData.mnMinorUnit
2914             >> maDateData.mnBaseUnit
2915             >> maDateData.mnCross
2916             >> maDateData.mnFlags;
2917 }
2918 
Convert(ScfPropertySet & rPropSet,ScaleData & rScaleData,bool bMirrorOrient) const2919 void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const
2920 {
2921     // automatic axis type detection
2922     rScaleData.AutoDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE );
2923 
2924     // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
2925     if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
2926     {
2927         /*  Chart2 requires axis type CATEGORY for automatic category/date axis
2928             (even if it is a date axis currently). */
2929         rScaleData.AxisType = rScaleData.AutoDateAxis ? cssc2::AxisType::CATEGORY : cssc2::AxisType::DATE;
2930         rScaleData.Scaling.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LINEARSCALING ), UNO_QUERY );
2931         /*  Min/max values depend on base time unit, they specify the number of
2932             days, months, or years starting from null date. */
2933         lclConvertTimeValue( GetRoot(), rScaleData.Minimum, maDateData.mnMinDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN ), maDateData.mnBaseUnit );
2934         lclConvertTimeValue( GetRoot(), rScaleData.Maximum, maDateData.mnMaxDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX ), maDateData.mnBaseUnit );
2935         // increment
2936         cssc::TimeIncrement& rTimeIncrement = rScaleData.TimeIncrement;
2937         lclConvertTimeInterval( rTimeIncrement.MajorTimeInterval, maDateData.mnMajorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR ), maDateData.mnMajorUnit );
2938         lclConvertTimeInterval( rTimeIncrement.MinorTimeInterval, maDateData.mnMinorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR ), maDateData.mnMinorUnit );
2939         // base unit
2940         if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE ) )
2941             rTimeIncrement.TimeResolution.clear();
2942         else
2943             rTimeIncrement.TimeResolution <<= lclGetApiTimeUnit( maDateData.mnBaseUnit );
2944     }
2945     else
2946     {
2947         // do not overlap text unless all labels are visible
2948         rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maLabelData.mnLabelFreq == 1 );
2949         // do not break text into several lines unless all labels are visible
2950         rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maLabelData.mnLabelFreq == 1 );
2951         // do not stagger labels in two lines
2952         rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE );
2953     }
2954 
2955     // reverse order
2956     bool bReverse = ::get_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient;
2957     rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
2958 
2959     //! TODO #i58731# show n-th category
2960 }
2961 
ConvertAxisPosition(ScfPropertySet & rPropSet,bool b3dChart) const2962 void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const
2963 {
2964     /*  Crossing mode (max-cross flag overrides other crossing settings). Excel
2965         does not move the Y axis in 3D charts, regardless of actual settings.
2966         But: the Y axis has to be moved to "end", if the X axis is mirrored,
2967         to keep it at the left end of the chart. */
2968     bool bMaxCross = ::get_flag( maLabelData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS );
2969     cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
2970     rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
2971 
2972     // crossing position (depending on axis type text/date)
2973     if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
2974     {
2975         bool bAutoCross = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2976         /*  Crossing position value depends on base time unit, it specifies the
2977             number of days, months, or years from null date. Note that Excel
2978             2007/2010 write broken BIFF8 files, they always stores the number
2979             of days cregardless of the base time unit (and they are reading it
2980             the same way, thus wrongly displaying files written by Excel
2981             97-2003). This filter sticks to the correct behaviour of Excel
2982             97-2003. */
2983         double fCrossingPos = bAutoCross ? 1.0 : lclGetSerialDay( GetRoot(), maDateData.mnCross, maDateData.mnBaseUnit );
2984         rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
2985     }
2986     else
2987     {
2988         double fCrossingPos = b3dChart ? 1.0 : maLabelData.mnCross;
2989         rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
2990     }
2991 }
2992 
2993 // ----------------------------------------------------------------------------
2994 
XclImpChValueRange(const XclImpChRoot & rRoot)2995 XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) :
2996     XclImpChRoot( rRoot )
2997 {
2998 }
2999 
ReadChValueRange(XclImpStream & rStrm)3000 void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm )
3001 {
3002     rStrm   >> maData.mfMin
3003             >> maData.mfMax
3004             >> maData.mfMajorStep
3005             >> maData.mfMinorStep
3006             >> maData.mfCross
3007             >> maData.mnFlags;
3008 }
3009 
Convert(ScaleData & rScaleData,bool bMirrorOrient) const3010 void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const
3011 {
3012     // scaling algorithm
3013     bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3014     OUString aScalingService = bLogScale ? SERVICE_CHART2_LOGSCALING : SERVICE_CHART2_LINEARSCALING;
3015     rScaleData.Scaling.set( ScfApiHelper::CreateInstance( aScalingService ), UNO_QUERY );
3016 
3017     // min/max
3018     lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) );
3019     lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) );
3020 
3021     // increment
3022     bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR );
3023     bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR );
3024     // major increment
3025     IncrementData& rIncrementData = rScaleData.IncrementData;
3026     lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor );
3027     // minor increment
3028     Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
3029     rSubIncrementSeq.realloc( 1 );
3030     Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount;
3031     rIntervalCount.clear();
3032     if( bLogScale )
3033     {
3034         if( !bAutoMinor )
3035             rIntervalCount <<= sal_Int32( 9 );
3036     }
3037     else
3038     {
3039         if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) )
3040         {
3041             double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5;
3042             if( (1.0 <= fCount) && (fCount < 1001.0) )
3043                 rIntervalCount <<= static_cast< sal_Int32 >( fCount );
3044         }
3045     }
3046 
3047     // reverse order
3048     bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient;
3049     rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
3050 }
3051 
ConvertAxisPosition(ScfPropertySet & rPropSet) const3052 void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const
3053 {
3054     bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
3055     bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
3056     bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
3057 
3058     // crossing mode (max-cross flag overrides other crossing settings)
3059     cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
3060     rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
3061 
3062     // crossing position
3063     double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross;
3064     if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos );
3065     rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
3066 }
3067 
3068 // ----------------------------------------------------------------------------
3069 
3070 namespace {
3071 
lclGetApiTickmarks(sal_uInt8 nXclTickPos)3072 sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos )
3073 {
3074     using namespace ::com::sun::star::chart2::TickmarkStyle;
3075     sal_Int32 nApiTickmarks = NONE;
3076     ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) );
3077     ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) );
3078     return nApiTickmarks;
3079 }
3080 
lclGetApiLabelPosition(sal_Int8 nXclLabelPos)3081 cssc::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos )
3082 {
3083     using namespace ::com::sun::star::chart;
3084     switch( nXclLabelPos )
3085     {
3086         case EXC_CHTICK_LOW:    return ChartAxisLabelPosition_OUTSIDE_START;
3087         case EXC_CHTICK_HIGH:   return ChartAxisLabelPosition_OUTSIDE_END;
3088         case EXC_CHTICK_NEXT:   return ChartAxisLabelPosition_NEAR_AXIS;
3089     }
3090     return ChartAxisLabelPosition_NEAR_AXIS;
3091 }
3092 
3093 } // namespace
3094 
XclImpChTick(const XclImpChRoot & rRoot)3095 XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) :
3096     XclImpChRoot( rRoot )
3097 {
3098 }
3099 
ReadChTick(XclImpStream & rStrm)3100 void XclImpChTick::ReadChTick( XclImpStream& rStrm )
3101 {
3102     rStrm   >> maData.mnMajor
3103             >> maData.mnMinor
3104             >> maData.mnLabelPos
3105             >> maData.mnBackMode;
3106     rStrm.Ignore( 16 );
3107     rStrm   >> maData.maTextColor
3108             >> maData.mnFlags;
3109 
3110     if( GetBiff() == EXC_BIFF8 )
3111     {
3112         // #116397# BIFF8: index into palette used instead of RGB data
3113         maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
3114         // rotation
3115         rStrm >> maData.mnRotation;
3116     }
3117     else
3118     {
3119         // BIFF2-BIFF7: get rotation from text orientation
3120         sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 );
3121         maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
3122     }
3123 }
3124 
GetFontColor() const3125 Color XclImpChTick::GetFontColor() const
3126 {
3127     return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
3128 }
3129 
GetRotation() const3130 sal_uInt16 XclImpChTick::GetRotation() const
3131 {
3132     return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation;
3133 }
3134 
Convert(ScfPropertySet & rPropSet) const3135 void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const
3136 {
3137     rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) );
3138     rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) );
3139     rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) );
3140     rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, cssc::ChartAxisMarkPosition_AT_AXIS );
3141 }
3142 
3143 // ----------------------------------------------------------------------------
3144 
XclImpChAxis(const XclImpChRoot & rRoot,sal_uInt16 nAxisType)3145 XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) :
3146     XclImpChRoot( rRoot ),
3147     mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
3148 {
3149     maData.mnType = nAxisType;
3150 }
3151 
ReadHeaderRecord(XclImpStream & rStrm)3152 void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm )
3153 {
3154     rStrm >> maData.mnType;
3155 }
3156 
ReadSubRecord(XclImpStream & rStrm)3157 void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm )
3158 {
3159     switch( rStrm.GetRecId() )
3160     {
3161         case EXC_ID_CHLABELRANGE:
3162             mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3163             mxLabelRange->ReadChLabelRange( rStrm );
3164         break;
3165         case EXC_ID_CHDATERANGE:
3166             if( !mxLabelRange )
3167                 mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3168             mxLabelRange->ReadChDateRange( rStrm );
3169         break;
3170         case EXC_ID_CHVALUERANGE:
3171             mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3172             mxValueRange->ReadChValueRange( rStrm );
3173         break;
3174         case EXC_ID_CHFORMAT:
3175             rStrm >> mnNumFmtIdx;
3176         break;
3177         case EXC_ID_CHTICK:
3178             mxTick.reset( new XclImpChTick( GetChRoot() ) );
3179             mxTick->ReadChTick( rStrm );
3180         break;
3181         case EXC_ID_CHFONT:
3182             mxFont.reset( new XclImpChFont );
3183             mxFont->ReadChFont( rStrm );
3184         break;
3185         case EXC_ID_CHAXISLINE:
3186             ReadChAxisLine( rStrm );
3187         break;
3188     }
3189 }
3190 
Finalize()3191 void XclImpChAxis::Finalize()
3192 {
3193     // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
3194     if( !mxLabelRange )
3195         mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
3196     if( !mxValueRange )
3197         mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
3198     // remove invisible grid lines completely
3199     if( mxMajorGrid.is() && !mxMajorGrid->HasLine() )
3200         mxMajorGrid.reset();
3201     if( mxMinorGrid.is() && !mxMinorGrid->HasLine() )
3202         mxMinorGrid.reset();
3203     // default tick settings different in OOChart and Excel
3204     if( !mxTick )
3205         mxTick.reset( new XclImpChTick( GetChRoot() ) );
3206     // #i4140# different default axis line color
3207     if( !mxAxisLine )
3208     {
3209         XclChLineFormat aLineFmt;
3210         // set "show axis" flag, default if line format record is missing
3211         ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS );
3212         mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) );
3213     }
3214     // add wall/floor frame for 3d charts
3215     if( !mxWallFrame )
3216         CreateWallFrame();
3217 }
3218 
GetFontIndex() const3219 sal_uInt16 XclImpChAxis::GetFontIndex() const
3220 {
3221     return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
3222 }
3223 
GetFontColor() const3224 Color XclImpChAxis::GetFontColor() const
3225 {
3226     return mxTick.is() ? mxTick->GetFontColor() : GetFontAutoColor();
3227 }
3228 
GetRotation() const3229 sal_uInt16 XclImpChAxis::GetRotation() const
3230 {
3231     return mxTick.is() ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION;
3232 }
3233 
CreateAxis(const XclImpChTypeGroup & rTypeGroup,const XclImpChAxis * pCrossingAxis) const3234 Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const
3235 {
3236     // create the axis object (always)
3237     Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY );
3238     if( xAxis.is() )
3239     {
3240         ScfPropertySet aAxisProp( xAxis );
3241         // #i58688# axis enabled
3242         aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() );
3243 
3244         // axis line properties
3245         if( mxAxisLine.is() )
3246             mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
3247         // axis ticks properties
3248         if( mxTick.is() )
3249             mxTick->Convert( aAxisProp );
3250 
3251         // axis caption text --------------------------------------------------
3252 
3253         // radar charts disable their category labels via chart type, not via axis
3254         bool bHasLabels = HasLabels() &&
3255             ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels());
3256         aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels );
3257         if( bHasLabels )
3258         {
3259             // font settings from CHFONT record or from default text
3260             if( mxFont.is() )
3261                 ConvertFontBase( GetChRoot(), aAxisProp );
3262             else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ).get() )
3263                 pDefText->ConvertFont( aAxisProp );
3264             // label text rotation
3265             ConvertRotationBase( GetChRoot(), aAxisProp, true );
3266             // number format
3267             sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx );
3268             if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
3269                 aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) );
3270         }
3271 
3272         // axis scaling and increment -----------------------------------------
3273 
3274         const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo();
3275         ScaleData aScaleData = xAxis->getScaleData();
3276         // set axis type
3277         switch( GetAxisType() )
3278         {
3279             case EXC_CHAXIS_X:
3280                 if( rTypeInfo.mbCategoryAxis )
3281                 {
3282                     aScaleData.AxisType = cssc2::AxisType::CATEGORY;
3283                     aScaleData.Categories = rTypeGroup.CreateCategSequence();
3284                 }
3285                 else
3286                     aScaleData.AxisType = cssc2::AxisType::REALNUMBER;
3287             break;
3288             case EXC_CHAXIS_Y:
3289                 aScaleData.AxisType = rTypeGroup.IsPercent() ?
3290                     cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER;
3291             break;
3292             case EXC_CHAXIS_Z:
3293                 aScaleData.AxisType = cssc2::AxisType::SERIES;
3294             break;
3295         }
3296         // axis scaling settings, dependent on axis type
3297         switch( aScaleData.AxisType )
3298         {
3299             case cssc2::AxisType::CATEGORY:
3300             case cssc2::AxisType::SERIES:
3301                 // #i71684# radar charts have reversed rotation direction
3302                 mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR );
3303             break;
3304             case cssc2::AxisType::REALNUMBER:
3305             case cssc2::AxisType::PERCENT:
3306                 // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
3307                 mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
3308             break;
3309             default:
3310                 DBG_ERRORFILE( "XclImpChAxis::CreateAxis - unknown axis type" );
3311         }
3312 
3313         /*  Do not set a value to the Origin member anymore (will be done via
3314             new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
3315         aScaleData.Origin.clear();
3316 
3317         // write back
3318         xAxis->setScaleData( aScaleData );
3319 
3320         // grid ---------------------------------------------------------------
3321 
3322         // main grid
3323         ScfPropertySet aGridProp( xAxis->getGridProperties() );
3324         aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() );
3325         if( mxMajorGrid.is() )
3326             mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3327         // sub grid
3328         Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3329         if( aSubGridPropSeq.hasElements() )
3330         {
3331             ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3332             aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() );
3333             if( mxMinorGrid.is() )
3334                 mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3335         }
3336 
3337         // position of crossing axis ------------------------------------------
3338 
3339         if( pCrossingAxis )
3340             pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup );
3341     }
3342     return xAxis;
3343 }
3344 
ConvertWall(ScfPropertySet & rPropSet) const3345 void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const
3346 {
3347     // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode
3348     if( mxWallFrame.is() )
3349         mxWallFrame->Convert( rPropSet, true );
3350 }
3351 
ConvertAxisPosition(ScfPropertySet & rPropSet,const XclImpChTypeGroup & rTypeGroup) const3352 void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const
3353 {
3354     if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) )
3355         mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() );
3356     else
3357         mxValueRange->ConvertAxisPosition( rPropSet );
3358 }
3359 
ReadChAxisLine(XclImpStream & rStrm)3360 void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm )
3361 {
3362     XclImpChLineFormatRef* pxLineFmt = 0;
3363     bool bWallFrame = false;
3364     switch( rStrm.ReaduInt16() )
3365     {
3366         case EXC_CHAXISLINE_AXISLINE:   pxLineFmt = &mxAxisLine;    break;
3367         case EXC_CHAXISLINE_MAJORGRID:  pxLineFmt = &mxMajorGrid;   break;
3368         case EXC_CHAXISLINE_MINORGRID:  pxLineFmt = &mxMinorGrid;   break;
3369         case EXC_CHAXISLINE_WALLS:      bWallFrame = true;          break;
3370     }
3371     if( bWallFrame )
3372         CreateWallFrame();
3373 
3374     bool bLoop = pxLineFmt || bWallFrame;
3375     while( bLoop )
3376     {
3377         sal_uInt16 nRecId = rStrm.GetNextRecId();
3378         bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) ||
3379                  (nRecId == EXC_ID_CHAREAFORMAT) ||
3380                  (nRecId == EXC_ID_CHESCHERFORMAT))
3381                  && rStrm.StartNextRecord();
3382         if( bLoop )
3383         {
3384             if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) )
3385             {
3386                 pxLineFmt->reset( new XclImpChLineFormat );
3387                 (*pxLineFmt)->ReadChLineFormat( rStrm );
3388             }
3389             else if( bWallFrame && mxWallFrame.is() )
3390             {
3391                 mxWallFrame->ReadSubRecord( rStrm );
3392             }
3393         }
3394     }
3395 }
3396 
CreateWallFrame()3397 void XclImpChAxis::CreateWallFrame()
3398 {
3399     switch( GetAxisType() )
3400     {
3401         case EXC_CHAXIS_X:
3402             mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) );
3403         break;
3404         case EXC_CHAXIS_Y:
3405             mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) );
3406         break;
3407         default:
3408             mxWallFrame.reset();
3409     }
3410 }
3411 
3412 // ----------------------------------------------------------------------------
3413 
XclImpChAxesSet(const XclImpChRoot & rRoot,sal_uInt16 nAxesSetId)3414 XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3415     XclImpChRoot( rRoot )
3416 {
3417     maData.mnAxesSetId = nAxesSetId;
3418 }
3419 
ReadHeaderRecord(XclImpStream & rStrm)3420 void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm )
3421 {
3422     rStrm >> maData.mnAxesSetId >> maData.maRect;
3423 }
3424 
ReadSubRecord(XclImpStream & rStrm)3425 void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm )
3426 {
3427     switch( rStrm.GetRecId() )
3428     {
3429         case EXC_ID_CHFRAMEPOS:
3430             mxFramePos.reset( new XclImpChFramePos );
3431             mxFramePos->ReadChFramePos( rStrm );
3432         break;
3433         case EXC_ID_CHAXIS:
3434             ReadChAxis( rStrm );
3435         break;
3436         case EXC_ID_CHTEXT:
3437             ReadChText( rStrm );
3438         break;
3439         case EXC_ID_CHPLOTFRAME:
3440             ReadChPlotFrame( rStrm );
3441         break;
3442         case EXC_ID_CHTYPEGROUP:
3443             ReadChTypeGroup( rStrm );
3444         break;
3445     }
3446 }
3447 
Finalize()3448 void XclImpChAxesSet::Finalize()
3449 {
3450     if( IsValidAxesSet() )
3451     {
3452         // finalize chart type groups, erase empty groups without series
3453         XclImpChTypeGroupMap aValidGroups;
3454         for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3455         {
3456             XclImpChTypeGroupRef xTypeGroup = aIt->second;
3457             xTypeGroup->Finalize();
3458             if( xTypeGroup->IsValidGroup() )
3459                 aValidGroups[ aIt->first ] = xTypeGroup;
3460         }
3461         maTypeGroups.swap( aValidGroups );
3462     }
3463 
3464     // invalid chart type groups are deleted now, check again with IsValidAxesSet()
3465     if( IsValidAxesSet() )
3466     {
3467         // always create missing axis objects
3468         if( !mxXAxis )
3469             mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) );
3470         if( !mxYAxis )
3471             mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) );
3472         if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() )
3473             mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) );
3474 
3475         // finalize axes
3476         if( mxXAxis.is() ) mxXAxis->Finalize();
3477         if( mxYAxis.is() ) mxYAxis->Finalize();
3478         if( mxZAxis.is() ) mxZAxis->Finalize();
3479 
3480         // finalize axis titles
3481         XclImpChTextRef xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE );
3482         String aAutoTitle = CREATE_STRING( "Axis Title" );
3483         lclFinalizeTitle( mxXAxisTitle, xDefText, aAutoTitle );
3484         lclFinalizeTitle( mxYAxisTitle, xDefText, aAutoTitle );
3485         lclFinalizeTitle( mxZAxisTitle, xDefText, aAutoTitle );
3486 
3487         // #i47745# missing plot frame -> invisible border and area
3488         if( !mxPlotFrame )
3489             mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3490     }
3491 }
3492 
GetFirstTypeGroup() const3493 XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const
3494 {
3495     XclImpChTypeGroupRef xTypeGroup;
3496     if( !maTypeGroups.empty() )
3497         xTypeGroup = maTypeGroups.begin()->second;
3498     return xTypeGroup;
3499 }
3500 
GetLegend() const3501 XclImpChLegendRef XclImpChAxesSet::GetLegend() const
3502 {
3503     XclImpChLegendRef xLegend;
3504     for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt )
3505         xLegend = aIt->second->GetLegend();
3506     return xLegend;
3507 }
3508 
GetSingleSeriesTitle() const3509 const String& XclImpChAxesSet::GetSingleSeriesTitle() const
3510 {
3511     return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : String::EmptyString();
3512 }
3513 
Convert(Reference<XDiagram> xDiagram) const3514 void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const
3515 {
3516     if( IsValidAxesSet() && xDiagram.is() )
3517     {
3518         // diagram background formatting
3519         if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY )
3520             ConvertBackground( xDiagram );
3521 
3522         // create the coordinate system, this inserts all chart types and series
3523         Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram );
3524         if( xCoordSystem.is() )
3525         {
3526             // insert coordinate system, if not already done
3527             try
3528             {
3529                 Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW );
3530                 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3531                 if( aCoordSystems.getLength() == 0 )
3532                     xCoordSystemCont->addCoordinateSystem( xCoordSystem );
3533             }
3534             catch( Exception& )
3535             {
3536                 DBG_ERRORFILE( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
3537             }
3538 
3539             // create the axes with grids and axis titles and insert them into the diagram
3540             ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() );
3541             ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() );
3542             ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 );
3543         }
3544     }
3545 }
3546 
ConvertTitlePositions() const3547 void XclImpChAxesSet::ConvertTitlePositions() const
3548 {
3549     if( mxXAxisTitle.is() )
3550         mxXAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_X ) );
3551     if( mxYAxisTitle.is() )
3552         mxYAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Y ) );
3553     if( mxZAxisTitle.is() )
3554         mxZAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Z ) );
3555 }
3556 
ReadChAxis(XclImpStream & rStrm)3557 void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm )
3558 {
3559     XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) );
3560     xAxis->ReadRecordGroup( rStrm );
3561 
3562     switch( xAxis->GetAxisType() )
3563     {
3564         case EXC_CHAXIS_X:  mxXAxis = xAxis;    break;
3565         case EXC_CHAXIS_Y:  mxYAxis = xAxis;    break;
3566         case EXC_CHAXIS_Z:  mxZAxis = xAxis;    break;
3567     }
3568 }
3569 
ReadChText(XclImpStream & rStrm)3570 void XclImpChAxesSet::ReadChText( XclImpStream& rStrm )
3571 {
3572     XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3573     xText->ReadRecordGroup( rStrm );
3574 
3575     switch( xText->GetLinkTarget() )
3576     {
3577         case EXC_CHOBJLINK_XAXIS:   mxXAxisTitle = xText;   break;
3578         case EXC_CHOBJLINK_YAXIS:   mxYAxisTitle = xText;   break;
3579         case EXC_CHOBJLINK_ZAXIS:   mxZAxisTitle = xText;   break;
3580     }
3581 }
3582 
ReadChPlotFrame(XclImpStream & rStrm)3583 void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm )
3584 {
3585     if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() )
3586     {
3587         mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
3588         mxPlotFrame->ReadRecordGroup( rStrm );
3589     }
3590 }
3591 
ReadChTypeGroup(XclImpStream & rStrm)3592 void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm )
3593 {
3594     XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
3595     xTypeGroup->ReadRecordGroup( rStrm );
3596     maTypeGroups[ xTypeGroup->GetGroupIdx() ] = xTypeGroup;
3597 }
3598 
CreateCoordSystem(Reference<XDiagram> xDiagram) const3599 Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const
3600 {
3601     Reference< XCoordinateSystem > xCoordSystem;
3602 
3603     /*  Try to get existing ccordinate system. For now, all series from primary
3604         and secondary axes sets are inserted into one coordinate system. Later,
3605         this should be changed to use one coordinate system for each axes set. */
3606     Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY );
3607     if( xCoordSystemCont.is() )
3608     {
3609         Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
3610         DBG_ASSERT( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
3611         if( aCoordSystems.getLength() > 0 )
3612             xCoordSystem = aCoordSystems[ 0 ];
3613     }
3614 
3615     // create the coordinate system according to the first chart type
3616     if( !xCoordSystem.is() )
3617     {
3618         XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3619         if( xTypeGroup.is() )
3620         {
3621             xCoordSystem = xTypeGroup->CreateCoordSystem();
3622             // convert 3d chart settings
3623             ScfPropertySet aDiaProp( xDiagram );
3624             xTypeGroup->ConvertChart3d( aDiaProp );
3625         }
3626     }
3627 
3628     /*  Create XChartType objects for all chart type groups. Each group will
3629         add its series to the data provider attached to the chart document. */
3630     Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3631     if( xChartTypeCont.is() )
3632     {
3633         sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3634         for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
3635         {
3636             try
3637             {
3638                 Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx );
3639                 if( xChartType.is() )
3640                     xChartTypeCont->addChartType( xChartType );
3641             }
3642             catch( Exception& )
3643             {
3644                 DBG_ERRORFILE( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
3645             }
3646         }
3647     }
3648 
3649     return xCoordSystem;
3650 }
3651 
ConvertAxis(XclImpChAxisRef xChAxis,XclImpChTextRef xChAxisTitle,Reference<XCoordinateSystem> xCoordSystem,const XclImpChAxis * pCrossingAxis) const3652 void XclImpChAxesSet::ConvertAxis(
3653         XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle,
3654         Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const
3655 {
3656     if( xChAxis.is() )
3657     {
3658         // create and attach the axis object
3659         Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis );
3660         if( xAxis.is() )
3661         {
3662             // create and attach the axis title
3663             if( xChAxisTitle.is() ) try
3664             {
3665                 Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW );
3666                 Reference< XTitle > xTitle( xChAxisTitle->CreateTitle(), UNO_SET_THROW );
3667                 xTitled->setTitleObject( xTitle );
3668             }
3669             catch( Exception& )
3670             {
3671                 DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
3672             }
3673 
3674             // insert axis into coordinate system
3675             try
3676             {
3677                 sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension();
3678                 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3679                 xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx );
3680             }
3681             catch( Exception& )
3682             {
3683                 DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
3684             }
3685         }
3686     }
3687 }
3688 
CreateAxis(const XclImpChAxis & rChAxis,const XclImpChAxis * pCrossingAxis) const3689 Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const
3690 {
3691     Reference< XAxis > xAxis;
3692     if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() )
3693         xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis );
3694     return xAxis;
3695 }
3696 
ConvertBackground(Reference<XDiagram> xDiagram) const3697 void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const
3698 {
3699     XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3700     if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
3701     {
3702         // wall/floor formatting (3D charts)
3703         if( mxXAxis.is() )
3704         {
3705             ScfPropertySet aWallProp( xDiagram->getWall() );
3706             mxXAxis->ConvertWall( aWallProp );
3707         }
3708         if( mxYAxis.is() )
3709         {
3710             ScfPropertySet aFloorProp( xDiagram->getFloor() );
3711             mxYAxis->ConvertWall( aFloorProp );
3712         }
3713     }
3714     else if( mxPlotFrame.is() )
3715     {
3716         // diagram background formatting
3717         ScfPropertySet aWallProp( xDiagram->getWall() );
3718         mxPlotFrame->Convert( aWallProp );
3719     }
3720 }
3721 
3722 // The chart object ===========================================================
3723 
XclImpChChart(const XclImpRoot & rRoot)3724 XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) :
3725     XclImpChRoot( rRoot, *this )
3726 {
3727     mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3728     mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3729 }
3730 
~XclImpChChart()3731 XclImpChChart::~XclImpChChart()
3732 {
3733 }
3734 
ReadHeaderRecord(XclImpStream & rStrm)3735 void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm )
3736 {
3737     // coordinates are stored as 16.16 fixed point
3738     rStrm >> maRect;
3739 }
3740 
ReadSubRecord(XclImpStream & rStrm)3741 void XclImpChChart::ReadSubRecord( XclImpStream& rStrm )
3742 {
3743     switch( rStrm.GetRecId() )
3744     {
3745         case EXC_ID_CHFRAME:
3746             mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3747             mxFrame->ReadRecordGroup( rStrm );
3748         break;
3749         case EXC_ID_CHSERIES:
3750             ReadChSeries( rStrm );
3751         break;
3752         case EXC_ID_CHPROPERTIES:
3753             ReadChProperties( rStrm );
3754         break;
3755         case EXC_ID_CHDEFAULTTEXT:
3756             ReadChDefaultText( rStrm );
3757         break;
3758         case EXC_ID_CHAXESSET:
3759             ReadChAxesSet( rStrm );
3760         break;
3761         case EXC_ID_CHTEXT:
3762             ReadChText( rStrm );
3763         break;
3764         case EXC_ID_CHEND:
3765             Finalize();     // finalize the entire chart object
3766         break;
3767     }
3768 }
3769 
ReadChDefaultText(XclImpStream & rStrm)3770 void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm )
3771 {
3772     sal_uInt16 nTextId = rStrm.ReaduInt16();
3773     if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() )
3774     {
3775         XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3776         xText->ReadRecordGroup( rStrm );
3777         maDefTexts[ nTextId ] = xText;
3778     }
3779 }
3780 
ReadChDataFormat(XclImpStream & rStrm)3781 void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm )
3782 {
3783     XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
3784     xDataFmt->ReadRecordGroup( rStrm );
3785     if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3786     {
3787         XclImpChDataFormatRef& rxMapFmt = maDataFmts[ xDataFmt->GetPointPos() ];
3788         /*  Do not overwrite existing data format group, Excel always uses the
3789             first data format group occurring in any CHSERIES group. */
3790         if( !rxMapFmt )
3791             rxMapFmt = xDataFmt;
3792     }
3793 }
3794 
UpdateObjFrame(const XclObjLineData & rLineData,const XclObjFillData & rFillData)3795 void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
3796 {
3797     if( !mxFrame )
3798         mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3799     mxFrame->UpdateObjFrame( rLineData, rFillData );
3800 }
3801 
GetTypeGroup(sal_uInt16 nGroupIdx) const3802 XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const
3803 {
3804     XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx );
3805     if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx );
3806     if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup();
3807     return xTypeGroup;
3808 }
3809 
GetDefaultText(XclChTextType eTextType) const3810 XclImpChTextRef XclImpChChart::GetDefaultText( XclChTextType eTextType ) const
3811 {
3812     sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL;
3813     bool bBiff8 = GetBiff() == EXC_BIFF8;
3814     switch( eTextType )
3815     {
3816         case EXC_CHTEXTTYPE_TITLE:      nDefTextId = EXC_CHDEFTEXT_GLOBAL;                                  break;
3817         case EXC_CHTEXTTYPE_LEGEND:     nDefTextId = EXC_CHDEFTEXT_GLOBAL;                                  break;
3818         case EXC_CHTEXTTYPE_AXISTITLE:  nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3819         case EXC_CHTEXTTYPE_AXISLABEL:  nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3820         case EXC_CHTEXTTYPE_DATALABEL:  nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
3821     }
3822     return maDefTexts.get( nDefTextId );
3823 }
3824 
IsManualPlotArea() const3825 bool XclImpChChart::IsManualPlotArea() const
3826 {
3827     // there is no real automatic mode in BIFF5 charts
3828     return (GetBiff() <= EXC_BIFF5) || ::get_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3829 }
3830 
Convert(Reference<XChartDocument> xChartDoc,XclImpDffConverter & rDffConv,const OUString & rObjName,const Rectangle & rChartRect) const3831 void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc,
3832         XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
3833 {
3834     // initialize conversion (locks the model to suppress any internal updates)
3835     InitConversion( xChartDoc, rChartRect );
3836 
3837     // chart frame formatting
3838     if( mxFrame.is() )
3839     {
3840         ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3841         mxFrame->Convert( aFrameProp );
3842     }
3843 
3844     // chart title
3845     if( mxTitle.is() ) try
3846     {
3847         Reference< XTitled > xTitled( xChartDoc, UNO_QUERY_THROW );
3848         Reference< XTitle > xTitle( mxTitle->CreateTitle(), UNO_SET_THROW );
3849         xTitled->setTitleObject( xTitle );
3850     }
3851     catch( Exception& )
3852     {
3853     }
3854 
3855     /*  Create the diagram object and attach it to the chart document. Currently,
3856         one diagram is used to carry all coordinate systems and data series. */
3857     Reference< XDiagram > xDiagram = CreateDiagram();
3858     xChartDoc->setFirstDiagram( xDiagram );
3859 
3860     // coordinate systems and chart types, convert axis settings
3861     mxPrimAxesSet->Convert( xDiagram );
3862     mxSecnAxesSet->Convert( xDiagram );
3863 
3864     // legend
3865     if( xDiagram.is() && mxLegend.is() )
3866         xDiagram->setLegend( mxLegend->CreateLegend() );
3867 
3868     /*  Following all conversions needing the old Chart1 API that involves full
3869         initialization of the chart view. */
3870     Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY );
3871     if( xChart1Doc.is() )
3872     {
3873         Reference< cssc::XDiagram > xDiagram1 = xChart1Doc->getDiagram();
3874 
3875         /*  Set the 'IncludeHiddenCells' property via the old API as only this
3876             ensures that the data provider and all created sequences get this
3877             flag correctly. */
3878         ScfPropertySet aDiaProp( xDiagram1 );
3879         bool bShowVisCells = ::get_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY );
3880         aDiaProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells );
3881 
3882         // plot area position and size (there is no real automatic mode in BIFF5 charts)
3883         XclImpChFramePosRef xPlotAreaPos = mxPrimAxesSet->GetPlotAreaFramePos();
3884         if( IsManualPlotArea() && xPlotAreaPos.is() ) try
3885         {
3886             const XclChFramePos& rFramePos = xPlotAreaPos->GetFramePosData();
3887             if( (rFramePos.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rFramePos.mnBRMode == EXC_CHFRAMEPOS_PARENT) )
3888             {
3889                 Reference< cssc::XDiagramPositioning > xPositioning( xDiagram1, UNO_QUERY_THROW );
3890                 ::com::sun::star::awt::Rectangle aDiagramRect = CalcHmmFromChartRect( rFramePos.maRect );
3891                 // for pie charts, always set inner plot area size to exclude the data labels as Excel does
3892                 const XclImpChTypeGroup* pFirstTypeGroup = mxPrimAxesSet->GetFirstTypeGroup().get();
3893                 if( pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE) )
3894                     xPositioning->setDiagramPositionExcludingAxes( aDiagramRect );
3895                 else if( pFirstTypeGroup && pFirstTypeGroup->Is3dChart() )
3896                     xPositioning->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect );
3897                 else
3898                     xPositioning->setDiagramPositionIncludingAxes( aDiagramRect );
3899             }
3900         }
3901         catch( Exception& )
3902         {
3903         }
3904 
3905         // positions of all title objects
3906         if( mxTitle.is() )
3907             mxTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE ) );
3908         mxPrimAxesSet->ConvertTitlePositions();
3909         mxSecnAxesSet->ConvertTitlePositions();
3910     }
3911 
3912     // unlock the model
3913     FinishConversion( rDffConv );
3914 
3915     // start listening to this chart
3916     ScDocument& rDoc = GetRoot().GetDoc();
3917     if( ScChartListenerCollection* pChartCollection = rDoc.GetChartListenerCollection() )
3918     {
3919         ::std::auto_ptr< ::std::vector< ScSharedTokenRef > > xRefTokens( new ::std::vector< ScSharedTokenRef > );
3920         for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
3921             (*aIt)->FillAllSourceLinks( *xRefTokens );
3922         if( !xRefTokens->empty() )
3923         {
3924             ::std::auto_ptr< ScChartListener > xListener( new ScChartListener( rObjName, &rDoc, xRefTokens.release() ) );
3925             xListener->SetUsed( true );
3926             xListener->StartListeningTo();
3927             pChartCollection->Insert( xListener.release() );
3928         }
3929     }
3930 }
3931 
ReadChSeries(XclImpStream & rStrm)3932 void XclImpChChart::ReadChSeries( XclImpStream& rStrm )
3933 {
3934     sal_uInt16 nNewSeriesIdx = static_cast< sal_uInt16 >( maSeries.size() );
3935     XclImpChSeriesRef xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx ) );
3936     xSeries->ReadRecordGroup( rStrm );
3937     maSeries.push_back( xSeries );
3938 }
3939 
ReadChProperties(XclImpStream & rStrm)3940 void XclImpChChart::ReadChProperties( XclImpStream& rStrm )
3941 {
3942     rStrm >> maProps.mnFlags >> maProps.mnEmptyMode;
3943 }
3944 
ReadChAxesSet(XclImpStream & rStrm)3945 void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm )
3946 {
3947     XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) );
3948     xAxesSet->ReadRecordGroup( rStrm );
3949     switch( xAxesSet->GetAxesSetId() )
3950     {
3951         case EXC_CHAXESSET_PRIMARY:     mxPrimAxesSet = xAxesSet;   break;
3952         case EXC_CHAXESSET_SECONDARY:   mxSecnAxesSet = xAxesSet;   break;
3953     }
3954 }
3955 
ReadChText(XclImpStream & rStrm)3956 void XclImpChChart::ReadChText( XclImpStream& rStrm )
3957 {
3958     XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
3959     xText->ReadRecordGroup( rStrm );
3960     switch( xText->GetLinkTarget() )
3961     {
3962         case EXC_CHOBJLINK_TITLE:
3963             mxTitle = xText;
3964         break;
3965         case EXC_CHOBJLINK_DATA:
3966         {
3967             sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx;
3968             if( nSeriesIdx < maSeries.size() )
3969                 maSeries[ nSeriesIdx ]->SetDataLabel( xText );
3970         }
3971         break;
3972     }
3973 }
3974 
Finalize()3975 void XclImpChChart::Finalize()
3976 {
3977     // finalize series (must be done first)
3978     FinalizeSeries();
3979     // #i49218# legend may be attached to primary or secondary axes set
3980     mxLegend = mxPrimAxesSet->GetLegend();
3981     if( !mxLegend )
3982         mxLegend = mxSecnAxesSet->GetLegend();
3983     if( mxLegend.is() )
3984         mxLegend->Finalize();
3985     // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
3986     mxPrimAxesSet->Finalize();
3987     mxSecnAxesSet->Finalize();
3988     // formatting of all series
3989     FinalizeDataFormats();
3990     // #i47745# missing frame -> invisible border and area
3991     if( !mxFrame )
3992         mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
3993     // chart title
3994     FinalizeTitle();
3995 }
3996 
FinalizeSeries()3997 void XclImpChChart::FinalizeSeries()
3998 {
3999     for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt )
4000     {
4001         XclImpChSeriesRef xSeries = *aSIt;
4002         if( xSeries->HasParentSeries() )
4003         {
4004             /*  Process child series (trend lines and error bars). Data of
4005                 child series will be set at the connected parent series. */
4006             if( xSeries->GetParentIdx() < maSeries.size() )
4007                 maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries );
4008         }
4009         else
4010         {
4011             // insert the series into the related chart type group
4012             if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() )
4013                 pTypeGroup->AddSeries( xSeries );
4014         }
4015     }
4016 }
4017 
FinalizeDataFormats()4018 void XclImpChChart::FinalizeDataFormats()
4019 {
4020     /*  #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
4021         Each CHDATAFORMAT group specifies the series and data point it is
4022         assigned to. This makes it possible to have a data format that is
4023         related to another series, e.g. a CHDATAFORMAT group for series 2 is
4024         part of a CHSERIES group that describes series 1. Therefore the chart
4025         itself has collected all CHDATAFORMAT groups to be able to store data
4026         format groups for series that have not been imported at that time. This
4027         loop finally assigns these groups to the related series. */
4028     for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt )
4029     {
4030         sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx;
4031         if( nSeriesIdx < maSeries.size() )
4032             maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second );
4033     }
4034 
4035     /*  #i51639# (part 2): Finalize data formats of all series. This adds for
4036         example missing CHDATAFORMAT groups for entire series that are needed
4037         for automatic colors of lines and areas. */
4038     for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt )
4039         (*aVIt)->FinalizeDataFormats();
4040 }
4041 
FinalizeTitle()4042 void XclImpChChart::FinalizeTitle()
4043 {
4044     // special handling for auto-generated title
4045     String aAutoTitle;
4046     if( !mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString()) )
4047     {
4048         // automatic title from first series name (if there are no series on secondary axes set)
4049         if( !mxSecnAxesSet->IsValidAxesSet() )
4050             aAutoTitle = mxPrimAxesSet->GetSingleSeriesTitle();
4051         if( mxTitle.is() || (aAutoTitle.Len() > 0) )
4052         {
4053             if( !mxTitle )
4054                 mxTitle.reset( new XclImpChText( GetChRoot() ) );
4055             if( aAutoTitle.Len() == 0 )
4056                 aAutoTitle = CREATE_STRING( "Chart Title" );
4057         }
4058     }
4059 
4060     // will reset mxTitle, if it does not contain a string and no auto title exists
4061     lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ), aAutoTitle );
4062 }
4063 
CreateDiagram() const4064 Reference< XDiagram > XclImpChChart::CreateDiagram() const
4065 {
4066     // create a diagram object
4067     Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY );
4068 
4069     // convert global chart settings
4070     ScfPropertySet aDiaProp( xDiagram );
4071 
4072     // treatment of missing values
4073     using namespace cssc::MissingValueTreatment;
4074     sal_Int32 nMissingValues = LEAVE_GAP;
4075     switch( maProps.mnEmptyMode )
4076     {
4077         case EXC_CHPROPS_EMPTY_SKIP:        nMissingValues = LEAVE_GAP; break;
4078         case EXC_CHPROPS_EMPTY_ZERO:        nMissingValues = USE_ZERO;  break;
4079         case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE;  break;
4080     }
4081     aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues );
4082 
4083     return xDiagram;
4084 }
4085 
4086 // ----------------------------------------------------------------------------
4087 
XclImpChartDrawing(const XclImpRoot & rRoot,bool bOwnTab)4088 XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot& rRoot, bool bOwnTab ) :
4089     XclImpDrawing( rRoot, bOwnTab ), // sheet charts may contain OLE objects
4090     mnScTab( rRoot.GetCurrScTab() ),
4091     mbOwnTab( bOwnTab )
4092 {
4093 }
4094 
ConvertObjects(XclImpDffConverter & rDffConv,const Reference<XModel> & rxModel,const Rectangle & rChartRect)4095 void XclImpChartDrawing::ConvertObjects( XclImpDffConverter& rDffConv,
4096         const Reference< XModel >& rxModel, const Rectangle& rChartRect )
4097 {
4098     maChartRect = rChartRect;   // needed in CalcAnchorRect() callback
4099 
4100     SdrModel* pSdrModel = 0;
4101     SdrPage* pSdrPage = 0;
4102     if( mbOwnTab )
4103     {
4104         // chart sheet: insert all shapes into the sheet, not into the chart object
4105         pSdrModel = GetDoc().GetDrawLayer();
4106         pSdrPage = GetSdrPage( mnScTab );
4107     }
4108     else
4109     {
4110         // embedded chart object: insert all shapes into the chart
4111         try
4112         {
4113             Reference< XDrawPageSupplier > xDrawPageSupp( rxModel, UNO_QUERY_THROW );
4114             Reference< XDrawPage > xDrawPage( xDrawPageSupp->getDrawPage(), UNO_SET_THROW );
4115             pSdrPage = ::GetSdrPageFromXDrawPage( xDrawPage );
4116             pSdrModel = pSdrPage ? pSdrPage->GetModel() : 0;
4117         }
4118         catch( Exception& )
4119         {
4120         }
4121     }
4122 
4123     if( pSdrModel && pSdrPage )
4124         ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
4125 }
4126 
CalcAnchorRect(const XclObjAnchor & rAnchor,bool bDffAnchor) const4127 Rectangle XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool bDffAnchor ) const
4128 {
4129     /*  In objects with DFF client anchor, the position of the shape is stored
4130         in the cell address components of the client anchor. In old BIFF3-BIFF5
4131         objects, the position is stored in the offset components of the anchor. */
4132     Rectangle aRect(
4133         static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnCol : rAnchor.mnLX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth()  + 0.5 ),
4134         static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnRow : rAnchor.mnTY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ),
4135         static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnCol  : rAnchor.mnRX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth()  + 0.5 ),
4136         static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnRow  : rAnchor.mnBY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ) );
4137     aRect.Justify();
4138     // move shapes into chart area for sheet charts
4139     if( mbOwnTab )
4140         aRect.Move( maChartRect.Left(), maChartRect.Top() );
4141     return aRect;
4142 }
4143 
OnObjectInserted(const XclImpDrawObjBase &)4144 void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase& )
4145 {
4146 }
4147 
4148 // ----------------------------------------------------------------------------
4149 
XclImpChart(const XclImpRoot & rRoot,bool bOwnTab)4150 XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) :
4151     XclImpRoot( rRoot ),
4152     mbOwnTab( bOwnTab ),
4153     mbIsPivotChart( false )
4154 {
4155 }
4156 
~XclImpChart()4157 XclImpChart::~XclImpChart()
4158 {
4159 }
4160 
ReadChartSubStream(XclImpStream & rStrm)4161 void XclImpChart::ReadChartSubStream( XclImpStream& rStrm )
4162 {
4163     XclImpPageSettings& rPageSett = GetPageSettings();
4164     XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
4165 
4166     bool bLoop = true;
4167     while( bLoop && rStrm.StartNextRecord() )
4168     {
4169         // page settings - only for charts in entire sheet
4170         if( mbOwnTab ) switch( rStrm.GetRecId() )
4171         {
4172             case EXC_ID_HORPAGEBREAKS:
4173             case EXC_ID_VERPAGEBREAKS:  rPageSett.ReadPageBreaks( rStrm );      break;
4174             case EXC_ID_HEADER:
4175             case EXC_ID_FOOTER:         rPageSett.ReadHeaderFooter( rStrm );    break;
4176             case EXC_ID_LEFTMARGIN:
4177             case EXC_ID_RIGHTMARGIN:
4178             case EXC_ID_TOPMARGIN:
4179             case EXC_ID_BOTTOMMARGIN:   rPageSett.ReadMargin( rStrm );          break;
4180             case EXC_ID_PRINTHEADERS:   rPageSett.ReadPrintHeaders( rStrm );    break;
4181             case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm );  break;
4182             case EXC_ID_HCENTER:
4183             case EXC_ID_VCENTER:        rPageSett.ReadCenter( rStrm );          break;
4184             case EXC_ID_SETUP:          rPageSett.ReadSetup( rStrm );           break;
4185             case EXC_ID8_IMGDATA:       rPageSett.ReadImgData( rStrm );         break;
4186 
4187             case EXC_ID_WINDOW2:        rTabViewSett.ReadWindow2( rStrm, true );break;
4188             case EXC_ID_SCL:            rTabViewSett.ReadScl( rStrm );          break;
4189 
4190             case EXC_ID_SHEETEXT: //0x0862
4191             {
4192                 // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
4193                 XclImpPalette& rPal = GetPalette();
4194                 rTabViewSett.ReadTabBgColor( rStrm,  rPal);
4195             }
4196             break;
4197 
4198             case EXC_ID_CODENAME:       ReadCodeName( rStrm, false );           break;
4199         }
4200 
4201         // common records
4202         switch( rStrm.GetRecId() )
4203         {
4204             case EXC_ID_EOF:            bLoop = false;                          break;
4205 
4206             // #i31882# ignore embedded chart objects
4207             case EXC_ID2_BOF:
4208             case EXC_ID3_BOF:
4209             case EXC_ID4_BOF:
4210             case EXC_ID5_BOF:           XclTools::SkipSubStream( rStrm );       break;
4211 
4212             case EXC_ID_CHCHART:        ReadChChart( rStrm );                   break;
4213 
4214             case EXC_ID8_CHPIVOTREF:
4215                 GetTracer().TracePivotChartExists();
4216                 mbIsPivotChart = true;
4217             break;
4218 
4219             // BIFF specific records
4220             default: switch( GetBiff() )
4221             {
4222                 case EXC_BIFF5: switch( rStrm.GetRecId() )
4223                 {
4224                     case EXC_ID_OBJ:        GetChartDrawing().ReadObj( rStrm );         break;
4225                 }
4226                 break;
4227                 case EXC_BIFF8: switch( rStrm.GetRecId() )
4228                 {
4229                     case EXC_ID_MSODRAWING: GetChartDrawing().ReadMsoDrawing( rStrm );  break;
4230                     // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
4231                     case EXC_ID_OBJ:        GetChartDrawing().ReadObj( rStrm );         break;
4232                 }
4233                 break;
4234                 default:;
4235             }
4236         }
4237     }
4238 }
4239 
UpdateObjFrame(const XclObjLineData & rLineData,const XclObjFillData & rFillData)4240 void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
4241 {
4242     if( !mxChartData )
4243         mxChartData.reset( new XclImpChChart( GetRoot() ) );
4244     mxChartData->UpdateObjFrame( rLineData, rFillData );
4245 }
4246 
GetProgressSize() const4247 sal_Size XclImpChart::GetProgressSize() const
4248 {
4249     return
4250         (mxChartData.is() ? mxChartData->GetProgressSize() : 0) +
4251         (mxChartDrawing.is() ? mxChartDrawing->GetProgressSize() : 0);
4252 }
4253 
Convert(Reference<XModel> xModel,XclImpDffConverter & rDffConv,const OUString & rObjName,const Rectangle & rChartRect) const4254 void XclImpChart::Convert( Reference< XModel > xModel, XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
4255 {
4256     Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
4257     if( xChartDoc.is() )
4258     {
4259         if( mxChartData.is() )
4260             mxChartData->Convert( xChartDoc, rDffConv, rObjName, rChartRect );
4261         if( mxChartDrawing.is() )
4262             mxChartDrawing->ConvertObjects( rDffConv, xModel, rChartRect );
4263     }
4264 }
4265 
GetChartDrawing()4266 XclImpChartDrawing& XclImpChart::GetChartDrawing()
4267 {
4268     if( !mxChartDrawing )
4269         mxChartDrawing.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab ) );
4270     return *mxChartDrawing;
4271 }
4272 
ReadChChart(XclImpStream & rStrm)4273 void XclImpChart::ReadChChart( XclImpStream& rStrm )
4274 {
4275     mxChartData.reset( new XclImpChChart( GetRoot() ) );
4276     mxChartData->ReadRecordGroup( rStrm );
4277 }
4278 
4279 // ============================================================================
4280 
4281