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