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