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