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