1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "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 occuring 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