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