bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xechart.cxx
blobfa7df367a109c5480f068c67404f7740e6a9342d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "xechart.hxx"
23 #include <com/sun/star/i18n/XBreakIterator.hpp>
24 #include <com/sun/star/i18n/ScriptType.hpp>
25 #include <com/sun/star/drawing/FillStyle.hpp>
26 #include <com/sun/star/drawing/XShapes.hpp>
27 #include <com/sun/star/chart/XChartDocument.hpp>
28 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
29 #include <com/sun/star/chart/ChartAxisPosition.hpp>
30 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
31 #include <com/sun/star/chart/DataLabelPlacement.hpp>
32 #include <com/sun/star/chart/ErrorBarStyle.hpp>
33 #include <com/sun/star/chart/MissingValueTreatment.hpp>
34 #include <com/sun/star/chart/TimeInterval.hpp>
35 #include <com/sun/star/chart/TimeUnit.hpp>
36 #include <com/sun/star/chart/XAxisSupplier.hpp>
37 #include <com/sun/star/chart/XDiagramPositioning.hpp>
38 #include <com/sun/star/chart2/XChartDocument.hpp>
39 #include <com/sun/star/chart2/XDiagram.hpp>
40 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
41 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
42 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
43 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
44 #include <com/sun/star/chart2/XTitled.hpp>
45 #include <com/sun/star/chart2/XColorScheme.hpp>
46 #include <com/sun/star/chart2/data/XDataSource.hpp>
47 #include <com/sun/star/chart2/AxisType.hpp>
48 #include <com/sun/star/chart2/CurveStyle.hpp>
49 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
50 #include <com/sun/star/chart2/DataPointLabel.hpp>
51 #include <com/sun/star/chart2/LegendPosition.hpp>
52 #include <com/sun/star/chart2/RelativePosition.hpp>
53 #include <com/sun/star/chart2/RelativeSize.hpp>
54 #include <com/sun/star/chart2/StackingDirection.hpp>
55 #include <com/sun/star/chart2/TickmarkStyle.hpp>
57 #include <tools/gen.hxx>
58 #include <vcl/outdev.hxx>
59 #include <filter/msfilter/escherex.hxx>
61 #include "document.hxx"
62 #include "rangelst.hxx"
63 #include "rangeutl.hxx"
64 #include "compiler.hxx"
65 #include "tokenarray.hxx"
66 #include "token.hxx"
67 #include "xeescher.hxx"
68 #include "xeformula.hxx"
69 #include "xehelper.hxx"
70 #include "xepage.hxx"
71 #include "xestyle.hxx"
73 using ::com::sun::star::uno::Any;
74 using ::com::sun::star::uno::Reference;
75 using ::com::sun::star::uno::Sequence;
76 using ::com::sun::star::uno::UNO_QUERY;
77 using ::com::sun::star::uno::UNO_QUERY_THROW;
78 using ::com::sun::star::uno::UNO_SET_THROW;
79 using ::com::sun::star::uno::Exception;
80 using ::com::sun::star::beans::XPropertySet;
81 using ::com::sun::star::i18n::XBreakIterator;
82 using ::com::sun::star::frame::XModel;
83 using ::com::sun::star::drawing::XShape;
84 using ::com::sun::star::drawing::XShapes;
86 using ::com::sun::star::chart2::IncrementData;
87 using ::com::sun::star::chart2::RelativePosition;
88 using ::com::sun::star::chart2::RelativeSize;
89 using ::com::sun::star::chart2::ScaleData;
90 using ::com::sun::star::chart2::SubIncrement;
91 using ::com::sun::star::chart2::XAxis;
92 using ::com::sun::star::chart2::XChartDocument;
93 using ::com::sun::star::chart2::XChartTypeContainer;
94 using ::com::sun::star::chart2::XColorScheme;
95 using ::com::sun::star::chart2::XCoordinateSystem;
96 using ::com::sun::star::chart2::XCoordinateSystemContainer;
97 using ::com::sun::star::chart2::XChartType;
98 using ::com::sun::star::chart2::XDataSeries;
99 using ::com::sun::star::chart2::XDataSeriesContainer;
100 using ::com::sun::star::chart2::XDiagram;
101 using ::com::sun::star::chart2::XFormattedString;
102 using ::com::sun::star::chart2::XLegend;
103 using ::com::sun::star::chart2::XRegressionCurve;
104 using ::com::sun::star::chart2::XRegressionCurveContainer;
105 using ::com::sun::star::chart2::XScaling;
106 using ::com::sun::star::chart2::XTitle;
107 using ::com::sun::star::chart2::XTitled;
109 using ::com::sun::star::chart2::data::XDataSequence;
110 using ::com::sun::star::chart2::data::XDataSource;
111 using ::com::sun::star::chart2::data::XLabeledDataSequence;
113 using ::formula::FormulaGrammar;
114 using ::formula::FormulaToken;
116 namespace cssc = ::com::sun::star::chart;
117 namespace cssc2 = ::com::sun::star::chart2;
119 // Helpers ====================================================================
121 namespace {
123 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
125 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
128 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
130 if( xRec )
131 xRec->Save( rStrm );
134 /** Saves the passed record (group) together with a leading value record. */
135 template< typename Type >
136 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
138 if( xRec )
140 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
141 xRec->Save( rStrm );
145 template<typename ValueType, typename KeyType>
146 void lclSaveRecord(XclExpStream& rStrm, ValueType* pRec, sal_uInt16 nRecId, KeyType nValue)
148 if (pRec)
150 XclExpValueRecord<KeyType>(nRecId, nValue).Save(rStrm);
151 pRec->Save(rStrm);
155 void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
157 sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
158 rStrm.StartRecord( nRecId, 12 );
159 rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
160 rStrm.EndRecord();
163 template< typename Type >
164 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
166 return !rAny.hasValue() || !(rAny >>= rValue);
169 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
171 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
172 if( !bIsAuto && bLogScale )
173 rfValue = log( rfValue ) / log( 10.0 );
174 return bIsAuto;
177 sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit )
179 DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate );
180 switch( nTimeUnit )
182 case EXC_CHDATERANGE_DAYS:
183 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
184 case EXC_CHDATERANGE_MONTHS:
185 return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16 );
186 case EXC_CHDATERANGE_YEARS:
187 return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16 );
188 default:
189 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
191 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
194 bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit )
196 double fSerialDate = 0;
197 bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny );
198 if( !bAuto )
199 rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit );
200 return bAuto;
203 sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit )
205 switch( nApiTimeUnit )
207 case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS;
208 case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS;
209 case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS;
210 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
212 return EXC_CHDATERANGE_DAYS;
215 bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny )
217 cssc::TimeInterval aInterval;
218 bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny );
219 if( !bAuto )
221 rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16 );
222 rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit );
224 return bAuto;
227 } // namespace
229 // Common =====================================================================
231 /** Stores global data needed in various classes of the Chart export filter. */
232 struct XclExpChRootData : public XclChRootData
234 typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
236 XclExpChChart& mrChartData; /// The chart data object.
237 XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
238 XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
240 inline explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {}
242 /** Registers a new future record level. */
243 void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
244 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
245 void InitializeFutureRecBlock( XclExpStream& rStrm );
246 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
247 void FinalizeFutureRecBlock( XclExpStream& rStrm );
250 // ----------------------------------------------------------------------------
252 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
254 maUnwrittenFrBlocks.push_back( rFrBlock );
257 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
259 // first call from a future record writes all missing CHFRBLOCKBEGIN records
260 if( !maUnwrittenFrBlocks.empty() )
262 // write the leading CHFRINFO record
263 if( maWrittenFrBlocks.empty() )
265 rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
266 rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
267 rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
268 rStrm.EndRecord();
270 // write all unwritten CHFRBLOCKBEGIN records
271 for( XclChFrBlockVector::const_iterator aIt = maUnwrittenFrBlocks.begin(), aEnd = maUnwrittenFrBlocks.end(); aIt != aEnd; ++aIt )
273 OSL_ENSURE( aIt->mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
274 lclWriteChFrBlockRecord( rStrm, *aIt, true );
276 // move all record infos to vector of written blocks
277 maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
278 maUnwrittenFrBlocks.clear();
282 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
284 OSL_ENSURE( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
285 if( !maUnwrittenFrBlocks.empty() )
287 // no future record has been written, just forget the topmost level
288 maUnwrittenFrBlocks.pop_back();
290 else if( !maWrittenFrBlocks.empty() )
292 // write the CHFRBLOCKEND record for the topmost block and delete it
293 lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
294 maWrittenFrBlocks.pop_back();
298 // ----------------------------------------------------------------------------
300 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) :
301 XclExpRoot( rRoot ),
302 mxChData( new XclExpChRootData( rChartData ) )
306 XclExpChRoot::~XclExpChRoot()
310 Reference< XChartDocument > XclExpChRoot::GetChartDocument() const
312 return mxChData->mxChartDoc;
315 XclExpChChart& XclExpChRoot::GetChartData() const
317 return mxChData->mrChartData;
320 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
322 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
325 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
327 return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName );
330 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
332 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
335 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc, const Rectangle& rChartRect ) const
337 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
340 void XclExpChRoot::FinishConversion() const
342 mxChData->FinishConversion();
345 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
347 XclExpPalette& rPal = GetPalette();
348 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
351 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
353 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
354 rColor = GetPalette().GetDefColor( nSysColorIdx );
355 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
358 sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const
360 return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS );
363 sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const
365 return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS );
368 XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const ::com::sun::star::awt::Rectangle& rRect ) const
370 XclChRectangle aRect;
371 aRect.mnX = CalcChartXFromHmm( rRect.X );
372 aRect.mnY = CalcChartYFromHmm( rRect.Y );
373 aRect.mnWidth = CalcChartXFromHmm( rRect.Width );
374 aRect.mnHeight = CalcChartYFromHmm( rRect.Height );
375 return aRect;
378 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
379 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
381 GetChartPropSetHelper().ReadLineProperties(
382 rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode );
385 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
386 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
388 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
391 void XclExpChRoot::ConvertEscherFormat(
392 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
393 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
395 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
396 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode );
399 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
401 XclFontData aFontData;
402 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
403 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
406 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
408 sal_Int32 nApiRot = 0;
409 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
410 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
413 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
415 mxChData->RegisterFutureRecBlock( rFrBlock );
418 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
420 mxChData->InitializeFutureRecBlock( rStrm );
423 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
425 mxChData->FinalizeFutureRecBlock( rStrm );
428 // ----------------------------------------------------------------------------
430 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
431 sal_uInt16 nFrType, sal_uInt16 nRecId, sal_Size nRecSize ) :
432 XclExpRecord( nRecId, nRecSize ),
433 XclExpChRoot( rRoot ),
434 maFrBlock( nFrType )
438 XclExpChGroupBase::~XclExpChGroupBase()
442 void XclExpChGroupBase::Save( XclExpStream& rStrm )
444 // header record
445 XclExpRecord::Save( rStrm );
446 // group records
447 if( HasSubRecords() )
449 // register the future record context corresponding to this record group
450 RegisterFutureRecBlock( maFrBlock );
451 // CHBEGIN record
452 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
453 // embedded records
454 WriteSubRecords( rStrm );
455 // finalize the future records, must be done before the closing CHEND
456 FinalizeFutureRecBlock( rStrm );
457 // CHEND record
458 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
462 bool XclExpChGroupBase::HasSubRecords() const
464 return true;
467 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
469 maFrBlock.mnContext = nFrContext;
470 maFrBlock.mnValue1 = nFrValue1;
471 maFrBlock.mnValue2 = nFrValue2;
474 // ----------------------------------------------------------------------------
476 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
477 XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
478 XclExpFutureRecord( eRecType, nRecId, nRecSize ),
479 XclExpChRoot( rRoot )
483 void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
485 InitializeFutureRecBlock( rStrm );
486 XclExpFutureRecord::Save( rStrm );
489 // Frame formatting ===========================================================
491 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode, sal_uInt16 nBRMode ) :
492 XclExpRecord( EXC_ID_CHFRAMEPOS, 20 )
494 maData.mnTLMode = nTLMode;
495 maData.mnBRMode = nBRMode;
498 void XclExpChFramePos::WriteBody( XclExpStream& rStrm )
500 rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect;
503 // ----------------------------------------------------------------------------
505 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
506 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
507 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
511 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
513 switch( eDefFrameType )
515 case EXC_CHFRAMETYPE_AUTO:
516 SetAuto( true );
517 break;
518 case EXC_CHFRAMETYPE_INVISIBLE:
519 SetAuto( false );
520 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
521 break;
522 default:
523 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" );
527 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
528 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
530 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
531 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
532 if( HasLine() )
534 // detect system color, set color identifier (TODO: detect automatic series line)
535 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
537 // store color index from automatic format data
538 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
539 // try to set automatic mode
540 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
541 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
543 else
545 // user defined color - register in palette
546 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
549 else
551 // no line - set default system color
552 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
556 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
558 return
559 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
560 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
563 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
565 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
566 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
567 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
570 namespace {
572 /** Creates a CHLINEFORMAT record from the passed property set. */
573 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
574 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
576 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
577 xLineFmt->Convert( rRoot, rPropSet, eObjType );
578 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
579 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
580 xLineFmt.reset();
581 return xLineFmt;
584 } // namespace
586 // ----------------------------------------------------------------------------
588 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
589 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
590 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
591 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
595 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
596 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
598 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
599 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
600 if( HasArea() )
602 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
603 // detect system color, set color identifier (TODO: detect automatic series area)
604 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
606 // store color index from automatic format data
607 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
608 // set automatic mode
609 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
611 else
613 // user defined color - register color in palette
614 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
616 // background color (default system color for solid fills)
617 if( bSolid )
618 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
619 else
620 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
622 else
624 // no area - set default system colors
625 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
626 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
628 return bComplexFill;
631 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
633 switch( eDefFrameType )
635 case EXC_CHFRAMETYPE_AUTO:
636 SetAuto( true );
637 break;
638 case EXC_CHFRAMETYPE_INVISIBLE:
639 SetAuto( false );
640 maData.mnPattern = EXC_PATT_NONE;
641 break;
642 default:
643 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" );
647 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
649 return
650 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
651 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
654 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
656 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
657 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
659 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
660 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
664 // ----------------------------------------------------------------------------
666 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
667 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
668 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
669 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
671 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
674 void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
676 const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
677 ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
678 // register colors in palette
679 mnColor1Id = RegisterColor( ESCHER_Prop_fillColor );
680 mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor );
683 bool XclExpChEscherFormat::IsValid() const
685 return static_cast< bool >(maData.mxEscherSet);
688 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
690 if( maData.mxEscherSet )
692 // replace RGB colors with palette indexes in the Escher container
693 const XclExpPalette& rPal = GetPalette();
694 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
695 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
697 // save the record group
698 XclExpChGroupBase::Save( rStrm );
702 bool XclExpChEscherFormat::HasSubRecords() const
704 // no subrecords for gradients
705 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
708 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
710 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
711 rStrm << maPicFmt.mnBmpMode << sal_uInt16( 0 ) << maPicFmt.mnFlags << maPicFmt.mfScale;
712 rStrm.EndRecord();
715 sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
717 sal_uInt32 nBGRValue;
718 if( maData.mxEscherSet && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
720 // swap red and blue
721 Color aColor( RGB_COLORDATA(
722 COLORDATA_BLUE( nBGRValue ),
723 COLORDATA_GREEN( nBGRValue ),
724 COLORDATA_RED( nBGRValue ) ) );
725 return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
727 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
730 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
732 OSL_ENSURE( maData.mxEscherSet, "XclExpChEscherFormat::WriteBody - missing property container" );
733 // write Escher property container via temporary memory stream
734 SvMemoryStream aMemStrm;
735 maData.mxEscherSet->Commit( aMemStrm );
736 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
737 rStrm.CopyFromStream( aMemStrm );
740 // ----------------------------------------------------------------------------
742 XclExpChFrameBase::XclExpChFrameBase()
746 XclExpChFrameBase::~XclExpChFrameBase()
750 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
751 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
753 // line format
754 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
755 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
756 // area format (only for frame objects)
757 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
759 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
760 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
761 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
763 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
764 mxEscherFmt->Convert( rPropSet, eObjType );
765 if( mxEscherFmt->IsValid() )
766 mxAreaFmt->SetAuto( false );
767 else
768 mxEscherFmt.reset();
773 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
774 XclChFrameType eDefFrameType, bool bIsFrame )
776 // line format
777 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
778 mxLineFmt->SetDefault( eDefFrameType );
779 // area format (only for frame objects)
780 if( bIsFrame )
782 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
783 mxAreaFmt->SetDefault( eDefFrameType );
784 mxEscherFmt.reset();
788 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
790 return
791 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
792 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
795 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
797 lclSaveRecord( rStrm, mxLineFmt );
798 lclSaveRecord( rStrm, mxAreaFmt );
799 lclSaveRecord( rStrm, mxEscherFmt );
802 // ----------------------------------------------------------------------------
804 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
805 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
806 meObjType( eObjType )
810 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
812 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
815 void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize )
817 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos );
818 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize );
821 bool XclExpChFrame::IsDefault() const
823 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
826 bool XclExpChFrame::IsDeleteable() const
828 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
831 void XclExpChFrame::Save( XclExpStream& rStrm )
833 switch( meObjType )
835 // wall/floor frame without CHFRAME header record
836 case EXC_CHOBJTYPE_WALL3D:
837 case EXC_CHOBJTYPE_FLOOR3D:
838 WriteFrameRecords( rStrm );
839 break;
840 default:
841 XclExpChGroupBase::Save( rStrm );
845 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
847 WriteFrameRecords( rStrm );
850 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
852 rStrm << maData.mnFormat << maData.mnFlags;
855 namespace {
857 /** Creates a CHFRAME record from the passed property set. */
858 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
859 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
861 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
862 xFrame->Convert( rPropSet );
863 if( xFrame->IsDeleteable() )
864 xFrame.reset();
865 return xFrame;
868 } // namespace
870 // Source links ===============================================================
872 namespace {
874 void lclAddDoubleRefData(
875 ScTokenArray& orArray, const FormulaToken& rToken,
876 SCsTAB nScTab1, SCsCOL nScCol1, SCsROW nScRow1,
877 SCsTAB nScTab2, SCsCOL nScCol2, SCsROW nScRow2 )
879 ScComplexRefData aComplexRef;
880 aComplexRef.InitFlags();
881 aComplexRef.Ref1.SetFlag3D( true );
882 aComplexRef.Ref1.nTab = nScTab1;
883 aComplexRef.Ref1.nCol = nScCol1;
884 aComplexRef.Ref1.nRow = nScRow1;
885 aComplexRef.Ref2.nTab = nScTab2;
886 aComplexRef.Ref2.nCol = nScCol2;
887 aComplexRef.Ref2.nRow = nScRow2;
889 if( orArray.GetLen() > 0 )
890 orArray.AddOpCode( ocUnion );
892 OSL_ENSURE( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),
893 "lclAddDoubleRefData - double reference token expected");
894 if( rToken.GetType() == ::formula::svExternalDoubleRef )
895 orArray.AddExternalDoubleReference( rToken.GetIndex(), rToken.GetString(), aComplexRef );
896 else
897 orArray.AddDoubleReference( aComplexRef );
900 } // namespace
902 // ----------------------------------------------------------------------------
904 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
905 XclExpRecord( EXC_ID_CHSOURCELINK ),
906 XclExpChRoot( rRoot )
908 maData.mnDestType = nDestType;
909 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
912 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
914 mxLinkFmla.reset();
915 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
917 if( !xDataSeq.is() )
918 return nDefCount;
920 // Compile the range representation string into token array. Note that the
921 // source range text depends on the current grammar.
922 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
923 ScCompiler aComp( GetDocPtr(), ScAddress() );
924 aComp.SetGrammar( GetDocPtr()->GetGrammar() );
925 ScTokenArray* pArray = aComp.CompileString( aRangeRepr );
926 if( !pArray )
927 return nDefCount;
929 ScTokenArray aArray;
930 sal_uInt32 nValueCount = 0;
931 pArray->Reset();
932 for( const FormulaToken* pToken = pArray->First(); pToken; pToken = pArray->Next() )
934 switch( pToken->GetType() )
936 case ::formula::svSingleRef:
937 case ::formula::svExternalSingleRef:
938 // for a single ref token, just add it to the new token array as is
939 if( aArray.GetLen() > 0 )
940 aArray.AddOpCode( ocUnion );
941 aArray.AddToken( *pToken );
942 ++nValueCount;
943 break;
945 case ::formula::svDoubleRef:
946 case ::formula::svExternalDoubleRef:
948 // split 3-dimensional ranges into single sheets
949 const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
950 const ScSingleRefData& rRef1 = rComplexRef.Ref1;
951 const ScSingleRefData& rRef2 = rComplexRef.Ref2;
952 for( SCsTAB nScTab = rRef1.nTab; nScTab <= rRef2.nTab; ++nScTab )
954 // split 2-dimensional ranges into single columns
955 if( bSplitToColumns && (rRef1.nCol < rRef2.nCol) && (rRef1.nRow < rRef2.nRow) )
956 for( SCsCOL nScCol = rRef1.nCol; nScCol <= rRef2.nCol; ++nScCol )
957 lclAddDoubleRefData( aArray, *pToken, nScTab, nScCol, rRef1.nRow, nScTab, nScCol, rRef2.nRow );
958 else
959 lclAddDoubleRefData( aArray, *pToken, nScTab, rRef1.nCol, rRef1.nRow, nScTab, rRef2.nCol, rRef2.nRow );
961 sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
962 sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
963 sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
964 nValueCount += nCols * nRows * nTabs;
966 break;
968 default:;
972 const ScAddress aBaseCell;
973 mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
974 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
975 return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
978 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
980 mxString.reset();
981 sal_uInt16 nFontIdx = EXC_FONT_APP;
982 if( rStringSeq.hasElements() )
984 mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
985 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
986 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
988 // convert all formatted string entries from the sequence
989 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
990 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
991 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
993 if( pIt->is() )
995 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
996 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
997 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
998 OUString aText = (*pIt)->getString();
999 ScfPropertySet aStrProp( *pIt );
1001 // #i63255# get script type for leading weak characters
1002 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
1004 // process all script portions
1005 sal_Int32 nPortionPos = 0;
1006 sal_Int32 nTextLen = aText.getLength();
1007 while( nPortionPos < nTextLen )
1009 // get script type and end position of next script portion
1010 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
1011 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
1013 // reuse previous script for following weak portions
1014 if( nScript == ApiScriptType::WEAK )
1015 nScript = nLastScript;
1017 // Excel start position of this portion
1018 sal_uInt16 nXclPortionStart = mxString->Len();
1019 // add portion text to Excel string
1020 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
1021 if( nXclPortionStart < mxString->Len() )
1023 // find font index variable dependent on script type
1024 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
1025 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
1027 // insert font into buffer (if not yet done)
1028 if( rnFontIdx == EXC_FONT_NOTFOUND )
1029 rnFontIdx = ConvertFont( aStrProp, nScript );
1031 // insert font index into format run vector
1032 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
1035 // go to next script portion
1036 nLastScript = nScript;
1037 nPortionPos = nPortionEnd;
1041 if( !mxString->IsEmpty() )
1043 // get leading font index
1044 const XclFormatRunVec& rFormats = mxString->GetFormats();
1045 OSL_ENSURE( !rFormats.empty() && (rFormats.front().mnChar == 0),
1046 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1047 // remove leading format run, if entire string is equally formatted
1048 if( rFormats.size() == 1 )
1049 nFontIdx = mxString->RemoveLeadingFont();
1050 else if( !rFormats.empty() )
1051 nFontIdx = rFormats.front().mnFontIdx;
1052 // add trailing format run, if string is rich-formatted
1053 if( mxString->IsRich() )
1054 mxString->AppendTrailingFormat( EXC_FONT_APP );
1057 return nFontIdx;
1060 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
1062 sal_Int32 nApiNumFmt = 0;
1063 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
1065 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
1066 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
1070 void XclExpChSourceLink::AppendString( const String& rStr )
1072 if (!mxString)
1073 return;
1074 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
1077 void XclExpChSourceLink::Save( XclExpStream& rStrm )
1079 // CHFORMATRUNS record
1080 if( mxString && mxString->IsRich() )
1082 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
1083 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
1084 mxString->WriteFormats( rStrm, true );
1085 rStrm.EndRecord();
1087 // CHSOURCELINK record
1088 XclExpRecord::Save( rStrm );
1089 // CHSTRING record
1090 if( mxString && !mxString->IsEmpty() )
1092 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
1093 rStrm << sal_uInt16( 0 ) << *mxString;
1094 rStrm.EndRecord();
1098 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
1100 rStrm << maData.mnDestType
1101 << maData.mnLinkType
1102 << maData.mnFlags
1103 << maData.mnNumFmtIdx
1104 << mxLinkFmla;
1107 // Text =======================================================================
1109 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
1110 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
1114 // ----------------------------------------------------------------------------
1116 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
1117 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
1119 maData.mnTarget = nLinkTarget;
1120 maData.maPointPos = rPointPos;
1123 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
1125 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
1128 // ----------------------------------------------------------------------------
1130 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
1131 XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
1135 void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, bool bShowSeries,
1136 bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
1138 // label value flags
1139 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, bShowSeries );
1140 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
1141 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
1142 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
1143 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
1145 // label value separator
1146 maData.maSeparator = rPropSet.GetStringProperty( EXC_CHPROP_LABELSEPARATOR );
1147 if( maData.maSeparator.isEmpty() )
1148 maData.maSeparator = OUString(' ');
1151 void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
1153 XclExpString aXclSep( maData.maSeparator, EXC_STR_FORCEUNICODE | EXC_STR_SMARTFLAGS );
1154 rStrm << maData.mnFlags << aXclSep;
1157 // ----------------------------------------------------------------------------
1159 XclExpChFontBase::~XclExpChFontBase()
1163 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
1165 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
1167 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
1168 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
1172 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
1174 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
1177 void XclExpChFontBase::ConvertRotationBase(
1178 const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet, bool bSupportsStacked )
1180 sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet, bSupportsStacked );
1181 SetRotation( nRotation );
1184 // ----------------------------------------------------------------------------
1186 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
1187 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
1188 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
1192 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
1194 mxFont = xFont;
1195 maData.maTextColor = rColor;
1196 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
1197 mnTextColorId = nColorId;
1200 void XclExpChText::SetRotation( sal_uInt16 nRotation )
1202 maData.mnRotation = nRotation;
1203 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
1206 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const String* pSubTitle )
1208 switch( nTarget )
1210 case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
1211 case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
1212 case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 0 ); break;
1213 case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
1216 mxSrcLink.reset();
1217 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
1219 if( xTitle.is() )
1221 // title frame formatting
1222 ScfPropertySet aTitleProp( xTitle );
1223 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1225 // string sequence
1226 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1227 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1228 if (pSubTitle)
1230 // append subtitle as the 2nd line of the title.
1231 String aSubTitle = OUString("\n");
1232 aSubTitle.Append(*pSubTitle);
1233 mxSrcLink->AppendString(aSubTitle);
1236 ConvertFontBase( GetChRoot(), nFontIdx );
1238 // rotation
1239 ConvertRotationBase( GetChRoot(), aTitleProp, true );
1241 // manual text position - only for main title
1242 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
1243 if( nTarget == EXC_CHOBJLINK_TITLE )
1245 Any aRelPos;
1246 if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION ) && aRelPos.has< RelativePosition >() ) try
1248 // calculate absolute position for CHTEXT record
1249 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
1250 Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW );
1251 ::com::sun::star::awt::Point aPos = xTitleShape->getPosition();
1252 ::com::sun::star::awt::Size aSize = xTitleShape->getSize();
1253 ::com::sun::star::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height );
1254 maData.maRect = CalcChartRectFromHmm( aRect );
1255 ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 );
1256 // manual title position implies manual plot area
1257 GetChartData().SetManualPlotArea();
1258 // calculate the default title position in chart units
1259 sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 );
1260 sal_Int32 nDefPosY = 85;
1261 // set the position relative to the standard position
1262 XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect;
1263 rFrameRect.mnX = maData.maRect.mnX - nDefPosX;
1264 rFrameRect.mnY = maData.maRect.mnY - nDefPosY;
1266 catch( Exception& )
1271 else
1273 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1277 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1279 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1280 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1281 ConvertFontBase( GetChRoot(), rPropSet );
1284 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1285 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1287 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
1289 cssc2::DataPointLabel aPointLabel;
1290 if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1291 return false;
1293 // percentage only allowed in pie and donut charts
1294 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1295 // bubble sizes only allowed in bubble charts
1296 bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
1297 OSL_ENSURE( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1299 // raw show flags
1300 bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1301 bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
1302 bool bShowCateg = aPointLabel.ShowCategoryName;
1303 bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1304 bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
1306 // create the CHFRLABELPROPS record for extended settings in BIFF8
1307 if( bShowAny && (GetBiff() == EXC_BIFF8) )
1309 mxLabelProps.reset( new XclExpChFrLabelProps( GetChRoot() ) );
1310 mxLabelProps->Convert( rPropSet, false, bShowCateg, bShowValue, bShowPercent, bShowBubble );
1313 // restrict to combinations allowed in CHTEXT
1314 if( bShowPercent ) bShowValue = false; // percent wins over value
1315 if( bShowValue ) bShowCateg = false; // value wins over category
1316 if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
1318 // set all flags
1319 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1320 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1321 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1322 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1323 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1324 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
1325 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
1326 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1328 if( bShowAny )
1330 // font settings
1331 ConvertFontBase( GetChRoot(), rPropSet );
1332 ConvertRotationBase( GetChRoot(), rPropSet, false );
1333 // label placement
1334 sal_Int32 nPlacement = 0;
1335 sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO;
1336 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1338 using namespace cssc::DataLabelPlacement;
1339 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1341 nLabelPos = EXC_CHTEXT_POS_DEFAULT;
1343 else switch( nPlacement )
1345 case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break;
1346 case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break;
1347 case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break;
1348 case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1349 case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1350 case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1351 case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break;
1352 case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1353 case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1354 case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1355 case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break;
1356 case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break;
1357 case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break;
1358 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1361 ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 );
1362 // source link (contains number format)
1363 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1364 if( bShowValue || bShowPercent )
1365 // percentage format wins over value format
1366 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1367 // object link
1368 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1371 /* Return true to indicate valid label settings:
1372 - for existing labels at entire series
1373 - for any settings at single data point (to be able to delete a point label) */
1374 return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
1377 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1379 // required flags
1380 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1381 if( GetBiff() == EXC_BIFF8 )
1382 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1383 // frame formatting
1384 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1385 // font settings
1386 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1387 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1388 ConvertFontBase( GetChRoot(), rPropSet );
1389 // source link (contains number format)
1390 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1391 mxSrcLink->ConvertNumFmt( rPropSet, false );
1392 // object link
1393 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1396 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1398 sal_uInt16 nFlags = 0;
1399 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1400 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1401 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1402 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1403 return nFlags;
1406 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1408 // CHFRAMEPOS record
1409 lclSaveRecord( rStrm, mxFramePos );
1410 // CHFONT record
1411 lclSaveRecord( rStrm, mxFont );
1412 // CHSOURCELINK group
1413 lclSaveRecord( rStrm, mxSrcLink );
1414 // CHFRAME group
1415 lclSaveRecord( rStrm, mxFrame );
1416 // CHOBJECTLINK record
1417 lclSaveRecord( rStrm, mxObjLink );
1418 // CHFRLABELPROPS record
1419 lclSaveRecord( rStrm, mxLabelProps );
1422 void XclExpChText::WriteBody( XclExpStream& rStrm )
1424 rStrm << maData.mnHAlign
1425 << maData.mnVAlign
1426 << maData.mnBackMode
1427 << maData.maTextColor
1428 << maData.maRect
1429 << maData.mnFlags;
1431 if( GetBiff() == EXC_BIFF8 )
1433 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1434 << maData.mnFlags2
1435 << maData.mnRotation;
1439 // ----------------------------------------------------------------------------
1441 namespace {
1443 /** Creates and returns an Excel text object from the passed title. */
1444 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
1445 const String* pSubTitle = NULL )
1447 Reference< XTitle > xTitle;
1448 if( xTitled.is() )
1449 xTitle = xTitled->getTitleObject();
1451 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1452 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1453 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1454 will be interpreted as auto-generated title showing the series title in
1455 charts that contain exactly one data series. */
1456 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1457 xText.reset();
1459 return xText;
1464 // Data series ================================================================
1466 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1467 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1468 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1469 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1473 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1474 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1476 rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1477 /* Set marker line/fill color to series line color.
1478 TODO: remove this if OOChart supports own colors in markers. */
1479 Color aLineColor;
1480 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1481 maData.maLineColor = maData.maFillColor = aLineColor;
1482 // register colors in palette
1483 RegisterColors( rRoot );
1486 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1487 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1489 // clear the automatic flag
1490 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1491 // symbol type and color
1492 if( bCloseSymbol )
1494 // set symbol type for the 'close' data series
1495 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1496 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1497 // set symbol line/fill color to series line color
1498 Color aLineColor;
1499 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1501 maData.maLineColor = maData.maFillColor = aLineColor;
1502 RegisterColors( rRoot );
1505 else
1507 // set invisible symbol
1508 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1512 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1514 if( HasMarker() )
1516 if( HasLineColor() )
1517 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1518 if( HasFillColor() )
1519 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1523 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1525 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1526 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1528 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1529 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1533 // ----------------------------------------------------------------------------
1535 XclExpChPieFormat::XclExpChPieFormat() :
1536 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1540 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1542 double fApiDist(0.0);
1543 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1544 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1547 // ----------------------------------------------------------------------------
1549 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1550 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1554 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1556 sal_Int32 nApiType(0);
1557 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1559 using namespace cssc2::DataPointGeometry3D;
1560 switch( nApiType )
1562 case CUBOID:
1563 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1564 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1565 break;
1566 case PYRAMID:
1567 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1568 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1569 break;
1570 case CYLINDER:
1571 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1572 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1573 break;
1574 case CONE:
1575 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1576 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1577 break;
1578 default:
1579 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1584 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1586 rStrm << maData.mnBase << maData.mnTop;
1589 // ----------------------------------------------------------------------------
1591 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1592 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1596 // ----------------------------------------------------------------------------
1598 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1599 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1600 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
1602 maData.maPointPos = rPointPos;
1603 maData.mnFormatIdx = nFormatIdx;
1606 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1608 // line and area formatting
1609 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1611 // data point symbols
1612 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1613 if( !bIsFrame )
1615 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1616 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1619 // pie segments
1620 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1622 mxPieFmt.reset( new XclExpChPieFormat );
1623 mxPieFmt->Convert( rPropSet );
1626 // 3D bars (only allowed for entire series in BIFF8)
1627 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1629 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1630 mx3dDataFmt->Convert( rPropSet );
1633 // spline
1634 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1635 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1637 // data point labels
1638 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1639 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1641 // CHTEXT groups for data labels are stored in global CHCHART group
1642 GetChartData().SetDataLabel( xLabel );
1643 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1647 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1649 // set line format to invisible
1650 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1651 // set symbols to invisible or to 'close' series symbol
1652 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1653 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1656 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1658 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1661 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1663 lclSaveRecord( rStrm, mx3dDataFmt );
1664 WriteFrameRecords( rStrm );
1665 lclSaveRecord( rStrm, mxPieFmt );
1666 lclSaveRecord( rStrm, mxMarkerFmt );
1667 lclSaveRecord( rStrm, mxSeriesFmt );
1668 lclSaveRecord( rStrm, mxAttLabel );
1671 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1673 rStrm << maData.maPointPos.mnPointIdx
1674 << maData.maPointPos.mnSeriesIdx
1675 << maData.mnFormatIdx
1676 << maData.mnFlags;
1679 // ----------------------------------------------------------------------------
1681 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1682 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1683 XclExpChRoot( rRoot )
1687 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1689 if( !xRegCurve.is() )
1690 return false;
1692 // trend line type
1693 ScfPropertySet aCurveProp( xRegCurve );
1694 OUString aService = aCurveProp.GetServiceName();
1695 if( aService == SERVICE_CHART2_LINEARREGCURVE )
1697 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1698 maData.mnOrder = 1;
1700 else if( aService == SERVICE_CHART2_EXPREGCURVE )
1701 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1702 else if( aService == SERVICE_CHART2_LOGREGCURVE )
1703 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1704 else if( aService == SERVICE_CHART2_POTREGCURVE )
1705 maData.mnLineType = EXC_CHSERTREND_POWER;
1706 else
1707 return false;
1709 // line formatting
1710 XclChDataPointPos aPointPos( nSeriesIdx );
1711 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1712 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1714 // #i83100# show equation and correlation coefficient
1715 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1716 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1717 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1719 // #i83100# formatting of the equation text box
1720 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1722 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1723 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1726 // missing features
1727 // #i20819# polynomial trend lines
1728 // #i66819# moving average trend lines
1729 // #i5085# manual trend line size
1730 // #i34093# manual crossing point
1731 return true;
1734 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1736 rStrm << maData.mnLineType
1737 << maData.mnOrder
1738 << maData.mfIntercept
1739 << maData.mnShowEquation
1740 << maData.mnShowRSquared
1741 << maData.mfForecastFor
1742 << maData.mfForecastBack;
1745 // ----------------------------------------------------------------------------
1747 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1748 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1749 XclExpChRoot( rRoot )
1751 maData.mnBarType = nBarType;
1754 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1756 sal_Int32 nBarStyle = 0;
1757 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1758 if( bOk )
1760 switch( nBarStyle )
1762 case cssc::ErrorBarStyle::ABSOLUTE:
1763 maData.mnSourceType = EXC_CHSERERR_FIXED;
1764 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1765 break;
1766 case cssc::ErrorBarStyle::RELATIVE:
1767 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1768 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1769 break;
1770 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1771 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1772 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1773 break;
1774 case cssc::ErrorBarStyle::STANDARD_ERROR:
1775 maData.mnSourceType = EXC_CHSERERR_STDERR;
1776 break;
1777 case cssc::ErrorBarStyle::FROM_DATA:
1779 bOk = false;
1780 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1781 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1782 if( xDataSource.is() )
1784 // find first sequence with current role
1785 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1786 Reference< XDataSequence > xValueSeq;
1788 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1789 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1790 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1791 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1793 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1794 ScfPropertySet aValueProp( xTmpValueSeq );
1795 OUString aCurrRole;
1796 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1797 xValueSeq = xTmpValueSeq;
1799 if( xValueSeq.is() )
1801 // #i86465# pass value count back to series
1802 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1803 bOk = maData.mnValueCount > 0;
1807 break;
1808 default:
1809 bOk = false;
1812 return bOk;
1815 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1817 rStrm << maData.mnBarType
1818 << maData.mnSourceType
1819 << maData.mnLineEnd
1820 << sal_uInt8( 1 ) // must be 1 to make line visible
1821 << maData.mfValue
1822 << maData.mnValueCount;
1825 // ----------------------------------------------------------------------------
1827 namespace {
1829 /** Returns the property set of the specified data point. */
1830 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1832 ScfPropertySet aPropSet;
1835 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1837 catch( Exception& )
1839 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1841 return aPropSet;
1844 } // namespace
1846 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1847 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1848 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1849 mnSeriesIdx( nSeriesIdx ),
1850 mnParentIdx( EXC_CHSERIES_INVALID )
1852 // CHSOURCELINK records are always required, even if unused
1853 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1854 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1855 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1856 if( GetBiff() == EXC_BIFF8 )
1857 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1860 bool XclExpChSeries::ConvertDataSeries(
1861 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1862 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1864 bool bOk = false;
1865 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1866 if( xDataSource.is() )
1868 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
1870 // find first sequence with role 'values-y'
1871 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1872 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1873 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1874 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1876 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1877 ScfPropertySet aValueProp( xTmpValueSeq );
1878 OUString aRole;
1879 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1881 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1883 xYValueSeq = xTmpValueSeq;
1884 if( !xTitleSeq.is() )
1885 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1887 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1889 xXValueSeq = xTmpValueSeq;
1891 else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES) )
1893 xBubbleSeq = xTmpValueSeq;
1894 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1899 bOk = xYValueSeq.is();
1900 if( bOk )
1902 // chart type group index
1903 mnGroupIdx = nGroupIdx;
1905 // convert source links
1906 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1907 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1909 // X values of XY charts
1910 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1912 // size values of bubble charts
1913 if( mxBubbleLink )
1914 mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
1916 // series formatting
1917 XclChDataPointPos aPointPos( mnSeriesIdx );
1918 ScfPropertySet aSeriesProp( xDataSeries );
1919 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1920 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1922 // trend lines
1923 CreateTrendLines( xDataSeries );
1925 // error bars
1926 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1927 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1929 if( maData.mnValueCount > 0 )
1931 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1933 /* #i91063# Create missing fill properties in pie/doughnut charts.
1934 If freshly created (never saved to ODF), these charts show
1935 varying point colors but do not return these points via API. */
1936 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1938 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1939 if( xColorScheme.is() )
1941 const OUString aFillStyleName = "FillStyle";
1942 const OUString aColorName = "Color";
1943 namespace cssd = ::com::sun::star::drawing;
1944 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1946 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1947 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1948 // test that the point fill style is solid, but no color is set
1949 cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
1950 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1951 (eFillStyle == cssd::FillStyle_SOLID) &&
1952 !aPointProp.HasProperty( aColorName ) )
1954 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1960 // data point formatting
1961 Sequence< sal_Int32 > aPointIndexes;
1962 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1964 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1965 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1966 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1968 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1969 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1970 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1971 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1972 maPointFmts.AppendRecord( xPointFmt );
1978 return bOk;
1981 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1982 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1984 bool bOk = false;
1985 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1986 if( xDataSource.is() )
1988 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1990 // find first sequence with passed role
1991 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1992 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1993 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1994 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1996 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1997 ScfPropertySet aValueProp( xTmpValueSeq );
1998 OUString aRole;
1999 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
2001 xYValueSeq = xTmpValueSeq;
2002 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
2006 bOk = xYValueSeq.is();
2007 if( bOk )
2009 // chart type group index
2010 mnGroupIdx = nGroupIdx;
2011 // convert source links
2012 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
2013 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
2014 // series formatting
2015 ScfPropertySet aSeriesProp( xDataSeries );
2016 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
2017 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
2020 return bOk;
2023 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
2025 InitFromParent( rParent );
2026 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
2027 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
2028 if( bOk )
2030 mxSeriesFmt = mxTrendLine->GetDataFormat();
2031 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
2033 return bOk;
2036 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
2038 InitFromParent( rParent );
2039 // error bar settings
2040 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
2041 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
2042 if( bOk )
2044 // error bar formatting
2045 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
2046 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
2048 return bOk;
2051 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2053 if( xCategSeq.is() )
2054 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
2057 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
2059 lclSaveRecord( rStrm, mxTitleLink );
2060 lclSaveRecord( rStrm, mxValueLink );
2061 lclSaveRecord( rStrm, mxCategLink );
2062 lclSaveRecord( rStrm, mxBubbleLink );
2063 lclSaveRecord( rStrm, mxSeriesFmt );
2064 maPointFmts.Save( rStrm );
2065 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
2066 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
2067 if( mnParentIdx != EXC_CHSERIES_INVALID )
2068 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
2069 lclSaveRecord( rStrm, mxTrendLine );
2070 lclSaveRecord( rStrm, mxErrorBar );
2073 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
2075 // index to parent series is stored 1-based
2076 mnParentIdx = rParent.mnSeriesIdx + 1;
2077 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2078 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2079 maData.mnCategCount = rParent.maData.mnCategCount;
2080 maData.mnValueCount = rParent.maData.mnValueCount;
2083 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
2085 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2086 if( xRegCurveCont.is() )
2088 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
2089 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
2090 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
2091 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
2093 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2094 if( xSeries && !xSeries->ConvertTrendLine( *this, *pIt ) )
2095 GetChartData().RemoveLastSeries();
2100 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
2101 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
2103 Reference< XPropertySet > xErrorBar;
2104 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
2106 ScfPropertySet aErrorProp( xErrorBar );
2107 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
2108 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
2112 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
2113 const OUString& rShowPropName, sal_uInt8 nBarId )
2115 if( rPropSet.GetBoolProperty( rShowPropName ) )
2117 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2118 if( xSeries && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
2119 GetChartData().RemoveLastSeries();
2123 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
2125 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
2126 if( GetBiff() == EXC_BIFF8 )
2127 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
2130 // Chart type groups ==========================================================
2132 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
2133 XclExpRecord( EXC_ID_CHUNKNOWN ),
2134 XclExpChRoot( rRoot ),
2135 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2139 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2140 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
2142 if( xChartType.is() )
2144 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
2145 // special handling for some chart types
2146 switch( maTypeInfo.meTypeCateg )
2148 case EXC_CHTYPECATEG_BAR:
2150 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
2151 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
2152 ScfPropertySet aTypeProp( xChartType );
2153 Sequence< sal_Int32 > aInt32Seq;
2154 maData.mnOverlap = 0;
2155 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2156 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
2157 maData.mnGap = 150;
2158 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2159 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
2161 break;
2162 case EXC_CHTYPECATEG_RADAR:
2163 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
2164 break;
2165 case EXC_CHTYPECATEG_PIE:
2167 ScfPropertySet aTypeProp( xChartType );
2168 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
2169 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2170 maData.mnPieHole = bDonut ? 50 : 0;
2171 // #i85166# starting angle of first pie slice
2172 ScfPropertySet aDiaProp( xDiagram );
2173 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
2175 break;
2176 case EXC_CHTYPECATEG_SCATTER:
2177 if( GetBiff() == EXC_BIFF8 )
2178 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
2179 break;
2180 default:;
2182 SetRecId( maTypeInfo.mnRecId );
2186 void XclExpChType::SetStacked( bool bPercent )
2188 switch( maTypeInfo.meTypeCateg )
2190 case EXC_CHTYPECATEG_LINE:
2191 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
2192 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
2193 break;
2194 case EXC_CHTYPECATEG_BAR:
2195 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
2196 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
2197 maData.mnOverlap = -100;
2198 break;
2199 default:;
2203 void XclExpChType::WriteBody( XclExpStream& rStrm )
2205 switch( GetRecId() )
2207 case EXC_ID_CHBAR:
2208 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
2209 break;
2211 case EXC_ID_CHLINE:
2212 case EXC_ID_CHAREA:
2213 case EXC_ID_CHRADARLINE:
2214 case EXC_ID_CHRADARAREA:
2215 rStrm << maData.mnFlags;
2216 break;
2218 case EXC_ID_CHPIE:
2219 rStrm << maData.mnRotation << maData.mnPieHole;
2220 if( GetBiff() == EXC_BIFF8 )
2221 rStrm << maData.mnFlags;
2222 break;
2224 case EXC_ID_CHSCATTER:
2225 if( GetBiff() == EXC_BIFF8 )
2226 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
2227 break;
2229 default:
2230 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" );
2234 // ----------------------------------------------------------------------------
2236 XclExpChChart3d::XclExpChChart3d() :
2237 XclExpRecord( EXC_ID_CHCHART3D, 14 )
2241 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
2243 sal_Int32 nRotationY = 0;
2244 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
2245 sal_Int32 nRotationX = 0;
2246 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
2247 sal_Int32 nPerspective = 15;
2248 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
2250 if( b3dWallChart )
2252 // Y rotation (Excel [0..359], Chart2 [-179,180])
2253 if( nRotationY < 0 ) nRotationY += 360;
2254 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
2255 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2256 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
2257 // perspective (Excel and Chart2 [0,100])
2258 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2259 // flags
2260 maData.mnFlags = 0;
2261 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
2262 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
2263 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
2265 else
2267 // Y rotation not used in pie charts, but 'first pie slice angle'
2268 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
2269 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2270 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
2271 // perspective (Excel and Chart2 [0,100])
2272 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2273 // flags
2274 maData.mnFlags = 0;
2278 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
2280 rStrm << maData.mnRotation
2281 << maData.mnElevation
2282 << maData.mnEyeDist
2283 << maData.mnRelHeight
2284 << maData.mnRelDepth
2285 << maData.mnDepthGap
2286 << maData.mnFlags;
2289 // ----------------------------------------------------------------------------
2291 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2292 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
2296 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2298 // frame properties
2299 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2300 // text properties
2301 mxText.reset( new XclExpChText( GetChRoot() ) );
2302 mxText->ConvertLegend( rPropSet );
2304 // legend position and size
2305 Any aRelPosAny, aRelSizeAny;
2306 rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION );
2307 rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE );
2308 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2309 rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION );
2310 if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) )
2314 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2315 indicator of manually changed legend position/size, but due to
2316 the different anchor modes used by this property (in the
2317 RelativePosition.Anchor member) it cannot be used to calculate
2318 the position easily. For this, the Chart1 API will be used
2319 instead. */
2320 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
2321 Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW );
2322 // coordinates in CHLEGEND record written but not used by Excel
2323 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE, EXC_CHFRAMEPOS_PARENT ) );
2324 XclChFramePos& rFramePos = mxFramePos->GetFramePosData();
2325 rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE;
2326 ::com::sun::star::awt::Point aLegendPos = xChart1Legend->getPosition();
2327 rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X );
2328 rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y );
2329 // legend size, Excel expects points in CHFRAMEPOS record
2330 rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS;
2331 ::com::sun::star::awt::Size aLegendSize = xChart1Legend->getSize();
2332 rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 );
2333 rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 );
2334 maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width );
2335 maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height );
2336 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2337 // manual legend position implies manual plot area
2338 GetChartData().SetManualPlotArea();
2339 maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED;
2340 // a CHFRAME record with cleared auto flags is needed
2341 if( !mxFrame )
2342 mxFrame.reset( new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2343 mxFrame->SetAutoFlags( false, false );
2345 catch( Exception& )
2347 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
2348 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2349 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2352 else
2354 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2355 rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION );
2356 switch( eApiPos )
2358 case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break;
2359 case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break;
2360 case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break;
2361 case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break;
2362 default:
2363 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
2364 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2365 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2368 ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH );
2370 // other flags
2371 ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES );
2372 const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY;
2373 ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED );
2376 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2378 lclSaveRecord( rStrm, mxFramePos );
2379 lclSaveRecord( rStrm, mxText );
2380 lclSaveRecord( rStrm, mxFrame );
2383 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2385 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2388 // ----------------------------------------------------------------------------
2390 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
2391 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
2392 meObjType( eObjType ),
2393 mnBarDist( 100 )
2397 void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
2399 if( rPropSet.Is() )
2400 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
2401 else
2402 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
2405 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2407 WriteFrameRecords( rStrm );
2410 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2412 rStrm << mnBarDist;
2415 // ----------------------------------------------------------------------------
2417 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2418 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
2419 maType( rRoot ),
2420 maTypeInfo( maType.GetTypeInfo() )
2422 maData.mnGroupIdx = nGroupIdx;
2425 void XclExpChTypeGroup::ConvertType(
2426 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2427 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2429 // chart type settings
2430 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2432 // spline - TODO: get from single series (#i66858#)
2433 ScfPropertySet aTypeProp( xChartType );
2434 cssc2::CurveStyle eCurveStyle;
2435 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2436 (eCurveStyle != cssc2::CurveStyle_LINES);
2438 // extended type info
2439 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2441 // 3d chart settings
2442 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2444 mxChart3d.reset( new XclExpChChart3d );
2445 ScfPropertySet aDiaProp( xDiagram );
2446 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2450 void XclExpChTypeGroup::ConvertSeries(
2451 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2452 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2454 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2455 if( xSeriesCont.is() )
2457 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2458 XDataSeriesVec aSeriesVec;
2460 // copy data series attached to the current axes set to the vector
2461 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2462 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2463 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2464 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2466 ScfPropertySet aSeriesProp( *pIt );
2467 sal_Int32 nSeriesAxesSetIdx(0);
2468 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2469 aSeriesVec.push_back( *pIt );
2472 // Are there any series in the current axes set?
2473 if( !aSeriesVec.empty() )
2475 // stacking direction (stacked/percent/deep 3d) from first series
2476 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2477 cssc2::StackingDirection eStacking;
2478 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2479 eStacking = cssc2::StackingDirection_NO_STACKING;
2481 // stacked or percent chart
2482 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) )
2484 // percent overrides simple stacking
2485 maType.SetStacked( bPercent );
2487 // connected data points (only in stacked bar charts)
2488 if (bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR))
2490 sal_uInt16 nKey = EXC_CHCHARTLINE_CONNECT;
2491 maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
2494 else
2496 // reverse series order for some unstacked 2D chart types
2497 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2498 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2501 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2502 if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() )
2503 mxChart3d->SetClustered();
2505 // varied point colors
2506 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2508 // process all series
2509 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2511 // create Excel series object, stock charts need special processing
2512 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2513 CreateAllStockSeries( xChartType, *aIt );
2514 else
2515 CreateDataSeries( xDiagram, *aIt );
2521 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2523 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2524 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2527 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2529 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2531 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2532 mxLegend->Convert( rPropSet );
2536 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2538 maType.Save( rStrm );
2539 lclSaveRecord( rStrm, mxChart3d );
2540 lclSaveRecord( rStrm, mxLegend );
2541 lclSaveRecord( rStrm, mxUpBar );
2542 lclSaveRecord( rStrm, mxDownBar );
2543 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2544 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2547 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2549 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2552 void XclExpChTypeGroup::CreateDataSeries(
2553 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2555 // let chart create series object with correct series index
2556 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2557 if( xSeries )
2559 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2560 maSeries.AppendRecord( xSeries );
2561 else
2562 GetChartData().RemoveLastSeries();
2566 void XclExpChTypeGroup::CreateAllStockSeries(
2567 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2569 // create existing series objects
2570 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2571 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2572 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2573 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2575 // formatting of special stock chart elements
2576 ScfPropertySet aTypeProp( xChartType );
2577 // hi-lo lines
2578 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2580 ScfPropertySet aSeriesProp( xDataSeries );
2581 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2582 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2583 sal_uInt16 nKey = EXC_CHCHARTLINE_HILO;
2584 maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
2586 // dropbars
2587 if( bHasOpen && bHasClose )
2589 // dropbar type is dependent on position in the file - always create both
2590 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2591 // white dropbar format
2592 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2593 ScfPropertySet aWhiteProp( xWhitePropSet );
2594 mxUpBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ) );
2595 mxUpBar->Convert( aWhiteProp );
2596 // black dropbar format
2597 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2598 ScfPropertySet aBlackProp( xBlackPropSet );
2599 mxDownBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ) );
2600 mxDownBar->Convert( aBlackProp );
2604 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2605 const OUString& rValueRole, bool bCloseSymbol )
2607 bool bOk = false;
2608 // let chart create series object with correct series index
2609 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2610 if( xSeries )
2612 bOk = xSeries->ConvertStockSeries( xDataSeries,
2613 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2614 if( bOk )
2615 maSeries.AppendRecord( xSeries );
2616 else
2617 GetChartData().RemoveLastSeries();
2619 return bOk;
2622 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2624 rStrm.WriteZeroBytes( 16 );
2625 rStrm << maData.mnFlags << maData.mnGroupIdx;
2628 // Axes =======================================================================
2630 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2631 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2632 XclExpChRoot( rRoot )
2636 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient )
2638 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2639 chart API allows to detect axis type (date axis, if property exists),
2640 and to receive the base time unit currently used in case the base time
2641 unit is set to 'automatic'. */
2642 cssc::TimeIncrement aTimeIncrement;
2643 if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT ) )
2645 // property exists -> this is a date axis currently
2646 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2648 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2649 bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >();
2650 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase );
2652 // ...but get the current base time unit from the property of the old chart API
2653 sal_Int32 nApiTimeUnit = 0;
2654 bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit;
2655 OSL_ENSURE( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot ghet base time unit" );
2656 maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS;
2658 /* Min/max values depend on base time unit, they specify the number of
2659 days, months, or years starting from null date. */
2660 bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit );
2661 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin );
2662 bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit );
2663 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax );
2666 // automatic axis type detection
2667 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis );
2669 // increment
2670 bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval );
2671 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor );
2672 bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval );
2673 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor );
2675 // origin
2676 double fOrigin = 0.0;
2677 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
2678 maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
2680 // reverse order
2681 if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient )
2682 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2685 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2687 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2688 rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION );
2689 double fCrossingPos = 1.0;
2690 rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE );
2692 bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2693 switch( eAxisPos )
2695 case cssc::ChartAxisPosition_ZERO:
2696 case cssc::ChartAxisPosition_START:
2697 maLabelData.mnCross = 1;
2698 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2699 break;
2700 case cssc::ChartAxisPosition_END:
2701 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS );
2702 break;
2703 case cssc::ChartAxisPosition_VALUE:
2704 maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 );
2705 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false );
2706 if( bDateAxis )
2707 maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit );
2708 break;
2709 default:
2710 maLabelData.mnCross = 1;
2711 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2715 void XclExpChLabelRange::Save( XclExpStream& rStrm )
2717 // the CHLABELRANGE record
2718 XclExpRecord::Save( rStrm );
2720 // the CHDATERANGE record with date axis settings (BIFF8 only)
2721 if( GetBiff() == EXC_BIFF8 )
2723 rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 );
2724 rStrm << maDateData.mnMinDate
2725 << maDateData.mnMaxDate
2726 << maDateData.mnMajorStep
2727 << maDateData.mnMajorUnit
2728 << maDateData.mnMinorStep
2729 << maDateData.mnMinorUnit
2730 << maDateData.mnBaseUnit
2731 << maDateData.mnCross
2732 << maDateData.mnFlags;
2733 rStrm.EndRecord();
2737 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2739 rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags;
2742 // ----------------------------------------------------------------------------
2744 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2745 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2746 XclExpChRoot( rRoot )
2750 void XclExpChValueRange::Convert( const ScaleData& rScaleData )
2752 // scaling algorithm
2753 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == "com.sun.star.chart2.LogarithmicScaling";
2754 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2756 // min/max
2757 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
2758 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2759 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
2760 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2762 // origin
2763 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
2764 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2766 // major increment
2767 const IncrementData& rIncrementData = rScaleData.IncrementData;
2768 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
2769 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2770 // minor increment
2771 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2772 sal_Int32 nCount = 0;
2773 bool bAutoMinor = bLogScale || bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2774 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1);
2775 if( !bAutoMinor )
2776 maData.mfMinorStep = maData.mfMajorStep / nCount;
2777 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2779 // reverse order
2780 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE );
2783 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2785 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2786 double fCrossingPos = 0.0;
2787 if( rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE ) )
2789 switch( eAxisPos )
2791 case cssc::ChartAxisPosition_ZERO:
2792 case cssc::ChartAxisPosition_START:
2793 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2794 break;
2795 case cssc::ChartAxisPosition_END:
2796 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2797 break;
2798 case cssc::ChartAxisPosition_VALUE:
2799 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
2800 maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
2801 break;
2802 default:
2803 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2808 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2810 rStrm << maData.mfMin
2811 << maData.mfMax
2812 << maData.mfMajorStep
2813 << maData.mfMinorStep
2814 << maData.mfCross
2815 << maData.mnFlags;
2818 // ----------------------------------------------------------------------------
2820 namespace {
2822 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2824 using namespace cssc2::TickmarkStyle;
2825 sal_uInt8 nXclTickPos = 0;
2826 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2827 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2828 return nXclTickPos;
2831 } // namespace
2833 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2834 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2835 XclExpChRoot( rRoot ),
2836 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2840 void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
2842 // tick mark style
2843 sal_Int32 nApiTickmarks = 0;
2844 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2845 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2846 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2847 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2849 // axis labels
2850 if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
2852 /* Radar charts disable their category labels via chart type, not via
2853 axis, and axis labels are always 'near axis'. */
2854 maData.mnLabelPos = EXC_CHTICK_NEXT;
2856 else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2858 // no labels
2859 maData.mnLabelPos = EXC_CHTICK_NOLABEL;
2861 else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
2863 // Excel expects 'near axis' at Y axes in 3D charts
2864 maData.mnLabelPos = EXC_CHTICK_NEXT;
2866 else
2868 cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
2869 rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION );
2870 switch( eApiLabelPos )
2872 case cssc::ChartAxisLabelPosition_NEAR_AXIS:
2873 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
2874 case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
2875 case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
2876 default: maData.mnLabelPos = EXC_CHTICK_NEXT;
2881 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2883 maData.maTextColor = rColor;
2884 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2885 mnTextColorId = nColorId;
2888 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2890 maData.mnRotation = nRotation;
2891 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2892 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2895 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2897 rStrm << maData.mnMajor
2898 << maData.mnMinor
2899 << maData.mnLabelPos
2900 << maData.mnBackMode;
2901 rStrm.WriteZeroBytes( 16 );
2902 rStrm << maData.maTextColor
2903 << maData.mnFlags;
2904 if( GetBiff() == EXC_BIFF8 )
2905 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2908 // ----------------------------------------------------------------------------
2910 namespace {
2912 /** Returns an API axis object from the passed coordinate system. */
2913 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2914 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2916 Reference< XAxis > xAxis;
2917 if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
2919 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2921 catch( Exception& )
2924 return xAxis;
2927 Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > xChartDoc,
2928 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2930 Reference< cssc::XAxis > xChart1Axis;
2933 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW );
2934 Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
2935 switch( nApiAxesSetIdx )
2937 case EXC_CHART_AXESSET_PRIMARY:
2938 xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim );
2939 break;
2940 case EXC_CHART_AXESSET_SECONDARY:
2941 xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim );
2942 break;
2945 catch( Exception& )
2948 return xChart1Axis;
2951 } // namespace
2953 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2954 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
2955 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2957 maData.mnType = nAxisType;
2960 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2962 mxFont = xFont;
2963 if( mxTick )
2964 mxTick->SetFontColor( rColor, nColorId );
2967 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2969 if( mxTick )
2970 mxTick->SetRotation( nRotation );
2973 void XclExpChAxis::Convert( Reference< XAxis > xAxis, Reference< XAxis > xCrossingAxis,
2974 Reference< cssc::XAxis > xChart1Axis, const XclChExtTypeInfo& rTypeInfo )
2976 ScfPropertySet aAxisProp( xAxis );
2977 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2979 // axis line format -------------------------------------------------------
2981 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2982 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2983 // #i58688# axis enabled
2984 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2986 // axis scaling and increment ---------------------------------------------
2988 ScfPropertySet aCrossingProp( xCrossingAxis );
2989 if( bCategoryAxis )
2991 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2992 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2993 if( xAxis.is() )
2995 ScfPropertySet aChart1AxisProp( xChart1Axis );
2996 // #i71684# radar charts have reversed rotation direction
2997 mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2999 // get position of crossing axis on this axis from passed axis object
3000 if( aCrossingProp.Is() )
3001 mxLabelRange->ConvertAxisPosition( aCrossingProp );
3003 else
3005 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
3006 if( xAxis.is() )
3007 mxValueRange->Convert( xAxis->getScaleData() );
3008 // get position of crossing axis on this axis from passed axis object
3009 if( aCrossingProp.Is() )
3010 mxValueRange->ConvertAxisPosition( aCrossingProp );
3013 // axis caption text ------------------------------------------------------
3015 // axis ticks properties
3016 mxTick.reset( new XclExpChTick( GetChRoot() ) );
3017 mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
3019 // axis label formatting and rotation
3020 ConvertFontBase( GetChRoot(), aAxisProp );
3021 ConvertRotationBase( GetChRoot(), aAxisProp, true );
3023 // axis number format
3024 sal_Int32 nApiNumFmt = 0;
3025 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
3026 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
3028 // grid -------------------------------------------------------------------
3030 if( xAxis.is() )
3032 // main grid
3033 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3034 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3035 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3036 // sub grid
3037 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3038 if( aSubGridPropSeq.hasElements() )
3040 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3041 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3042 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3047 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
3049 if( xDiagram.is() ) switch( GetAxisType() )
3051 case EXC_CHAXIS_X:
3053 ScfPropertySet aWallProp( xDiagram->getWall() );
3054 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
3056 break;
3057 case EXC_CHAXIS_Y:
3059 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3060 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
3062 break;
3063 default:
3064 mxWallFrame.reset();
3068 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
3070 lclSaveRecord( rStrm, mxLabelRange );
3071 lclSaveRecord( rStrm, mxValueRange );
3072 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
3073 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
3074 lclSaveRecord( rStrm, mxTick );
3075 lclSaveRecord( rStrm, mxFont );
3076 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
3077 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
3078 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
3079 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
3082 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
3084 rStrm << maData.mnType;
3085 rStrm.WriteZeroBytes( 16 );
3088 // ----------------------------------------------------------------------------
3090 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3091 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
3093 maData.mnAxesSetId = nAxesSetId;
3094 SetFutureRecordContext( 0, nAxesSetId );
3096 /* Need to set a reasonable size for the plot area, otherwise Excel will
3097 move away embedded shapes while auto-sizing the plot area. This is just
3098 a wild guess, but will be fixed with implementing manual positioning of
3099 chart elements. */
3100 maData.maRect.mnX = 262;
3101 maData.maRect.mnY = 626;
3102 maData.maRect.mnWidth = 3187;
3103 maData.maRect.mnHeight = 2633;
3106 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
3108 /* First unused chart type group index is passed to be able to continue
3109 counting of chart type groups for secondary axes set. */
3110 sal_uInt16 nGroupIdx = nFirstGroupIdx;
3111 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
3112 if( xCoordSysCont.is() )
3114 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
3115 if( aCoordSysSeq.getLength() > 0 )
3117 /* Process first coordinate system only. Import filter puts all
3118 chart types into one coordinate system. */
3119 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
3120 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3122 // 3d mode
3123 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
3125 // percent charts
3126 namespace ApiAxisType = cssc2::AxisType;
3127 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
3128 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
3130 // connector lines in bar charts
3131 ScfPropertySet aDiaProp( xDiagram );
3132 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
3134 // swapped axes sets
3135 ScfPropertySet aCoordSysProp( xCoordSystem );
3136 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
3138 // X axis for later use
3139 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
3140 // X axis labels
3141 ScfPropertySet aXAxisProp( xApiXAxis );
3142 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
3144 // process chart types
3145 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3146 if( xChartTypeCont.is() )
3148 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
3149 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
3150 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
3151 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
3153 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
3154 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
3155 /* If new chart type group cannot be inserted into a combination
3156 chart with existing type groups, insert all series into last
3157 contained chart type group instead of creating a new group. */
3158 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
3159 if( xLastGroup && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
3161 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3163 else
3165 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3166 if( xTypeGroup->IsValidGroup() )
3168 maTypeGroups.AppendRecord( xTypeGroup );
3169 ++nGroupIdx;
3175 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
3177 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
3179 // create axes according to chart type (no axes for pie and donut charts)
3180 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
3182 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
3183 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
3184 if( pGroup->Is3dDeepChart() )
3185 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
3188 // X axis category ranges
3189 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
3191 const ScaleData aScaleData = xApiXAxis->getScaleData();
3192 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
3193 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
3196 // legend
3197 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3199 Reference< XLegend > xLegend = xDiagram->getLegend();
3200 if( xLegend.is() )
3202 ScfPropertySet aLegendProp( xLegend );
3203 pGroup->ConvertLegend( aLegendProp );
3210 // wall/floor/diagram frame formatting
3211 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3213 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3214 if( xTypeGroup && xTypeGroup->Is3dWallChart() )
3216 // wall/floor formatting (3D charts)
3217 if( mxXAxis )
3218 mxXAxis->ConvertWall( xDiagram );
3219 if( mxYAxis )
3220 mxYAxis->ConvertWall( xDiagram );
3222 else
3224 // diagram background formatting
3225 ScfPropertySet aWallProp( xDiagram->getWall() );
3226 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
3230 // inner and outer plot area position and size
3233 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
3234 Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
3235 // set manual flag in chart data
3236 if( !xPositioning->isAutomaticDiagramPositioning() )
3237 GetChartData().SetManualPlotArea();
3238 // the CHAXESSET record contains the inner plot area
3239 maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() );
3240 // the embedded CHFRAMEPOS record contains the outer plot area
3241 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
3242 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3243 const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get();
3244 bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE);
3245 mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect :
3246 CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() );
3248 catch( Exception& )
3252 // return first unused chart type group index for next axes set
3253 return nGroupIdx;
3256 bool XclExpChAxesSet::Is3dChart() const
3258 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3259 return xTypeGroup && xTypeGroup->Is3dChart();
3262 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
3264 lclSaveRecord( rStrm, mxFramePos );
3265 lclSaveRecord( rStrm, mxXAxis );
3266 lclSaveRecord( rStrm, mxYAxis );
3267 lclSaveRecord( rStrm, mxZAxis );
3268 lclSaveRecord( rStrm, mxXAxisTitle );
3269 lclSaveRecord( rStrm, mxYAxisTitle );
3270 lclSaveRecord( rStrm, mxZAxisTitle );
3271 if( mxPlotFrame )
3273 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
3274 mxPlotFrame->Save( rStrm );
3276 maTypeGroups.Save( rStrm );
3279 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
3281 return maTypeGroups.GetFirstRecord();
3284 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
3286 return maTypeGroups.GetLastRecord();
3289 void XclExpChAxesSet::ConvertAxis(
3290 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
3291 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
3292 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
3293 sal_Int32 nCrossingAxisDim )
3295 // create and convert axis object
3296 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
3297 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
3298 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3299 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
3300 Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
3301 Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx );
3302 rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo );
3304 // create and convert axis title
3305 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
3306 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
3309 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
3311 rStrm << maData.mnAxesSetId << maData.maRect;
3314 // The chart object ===========================================================
3316 static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
3317 String& rSubTitle)
3319 Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
3320 if (!xChartDoc1.is())
3321 return;
3323 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
3324 if (!xProp.is())
3325 return;
3327 OUString aTitle;
3328 Any any = xProp->getPropertyValue( OUString("String") );
3329 if (any >>= aTitle)
3330 rSubTitle = aTitle;
3333 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
3334 Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) :
3335 XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
3337 Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
3338 // rectangle is stored in 16.16 fixed-point format
3339 maRect.mnX = maRect.mnY = 0;
3340 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
3341 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
3343 // global chart properties (default values)
3344 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
3345 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA );
3346 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
3348 // always create both axes set objects
3349 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3350 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3352 if( xChartDoc.is() )
3354 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
3356 // global chart properties (only 'include hidden cells' attribute for now)
3357 ScfPropertySet aDiagramProp( xDiagram );
3358 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
3359 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
3361 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3362 InitConversion( xChartDoc, rChartRect );
3364 // chart frame
3365 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3366 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
3368 // chart title
3369 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3370 String aSubTitle;
3371 lcl_getChartSubTitle(xChartDoc, aSubTitle);
3372 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
3373 aSubTitle.Len() ? &aSubTitle : NULL );
3375 // diagrams (axes sets)
3376 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
3377 if( !mxPrimAxesSet->Is3dChart() )
3378 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
3380 // treatment of missing values
3381 ScfPropertySet aDiaProp( xDiagram );
3382 sal_Int32 nMissingValues = 0;
3383 if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT ) )
3385 using namespace cssc::MissingValueTreatment;
3386 switch( nMissingValues )
3388 case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
3389 case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
3390 case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
3394 // finish API conversion
3395 FinishConversion();
3399 XclExpChSeriesRef XclExpChChart::CreateSeries()
3401 XclExpChSeriesRef xSeries;
3402 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
3403 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3405 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
3406 maSeries.AppendRecord( xSeries );
3408 return xSeries;
3411 void XclExpChChart::RemoveLastSeries()
3413 if( !maSeries.IsEmpty() )
3414 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
3417 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
3419 if( xText )
3420 maLabels.AppendRecord( xText );
3423 void XclExpChChart::SetManualPlotArea()
3425 // this flag does not exist in BIFF5
3426 if( GetBiff() == EXC_BIFF8 )
3427 ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3430 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
3432 // background format
3433 lclSaveRecord( rStrm, mxFrame );
3435 // data series
3436 maSeries.Save( rStrm );
3438 // CHPROPERTIES record
3439 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
3440 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
3441 rStrm.EndRecord();
3443 // axes sets (always save primary axes set)
3444 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
3445 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
3446 mxPrimAxesSet->Save( rStrm );
3447 if( mxSecnAxesSet->IsValidAxesSet() )
3448 mxSecnAxesSet->Save( rStrm );
3450 // chart title and data labels
3451 lclSaveRecord( rStrm, mxTitle );
3452 maLabels.Save( rStrm );
3455 void XclExpChChart::WriteBody( XclExpStream& rStrm )
3457 rStrm << maRect;
3460 // ----------------------------------------------------------------------------
3462 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot,
3463 const Reference< XModel >& rxModel, const Size& rChartSize ) :
3464 XclExpRoot( rRoot )
3466 if( (rChartSize.Width() > 0) && (rChartSize.Height() > 0) )
3468 ScfPropertySet aPropSet( rxModel );
3469 Reference< XShapes > xShapes;
3470 if( aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES ) && xShapes.is() && (xShapes->getCount() > 0) )
3472 /* Create a new independent object manager with own DFF stream for the
3473 DGCONTAINER, pass global manager as parent for shared usage of
3474 global DFF data (picture container etc.). */
3475 mxObjMgr.reset( new XclExpEmbeddedObjectManager( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS ) );
3476 // initialize the drawing object list
3477 mxObjMgr->StartSheet();
3478 // process the draw page (convert all shapes)
3479 mxObjRecs = mxObjMgr->ProcessDrawing( xShapes );
3480 // finalize the DFF stream
3481 mxObjMgr->EndDocument();
3486 XclExpChartDrawing::~XclExpChartDrawing()
3490 void XclExpChartDrawing::Save( XclExpStream& rStrm )
3492 if( mxObjRecs )
3493 mxObjRecs->Save( rStrm );
3496 // ----------------------------------------------------------------------------
3498 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Rectangle& rChartRect ) :
3499 XclExpSubStream( EXC_BOF_CHART ),
3500 XclExpRoot( rRoot )
3502 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
3503 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
3504 AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) );
3505 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
3507 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3508 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) );
3511 // ============================================================================
3513 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */