fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xechart.cxx
blob4b6c300cd4a03a55180e3d0cf02c834317f9d9f9
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 .
20 #include "xechart.hxx"
22 #include <com/sun/star/i18n/XBreakIterator.hpp>
23 #include <com/sun/star/i18n/ScriptType.hpp>
24 #include <com/sun/star/drawing/FillStyle.hpp>
25 #include <com/sun/star/drawing/XShapes.hpp>
26 #include <com/sun/star/chart/XChartDocument.hpp>
27 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
28 #include <com/sun/star/chart/ChartAxisPosition.hpp>
29 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
30 #include <com/sun/star/chart/DataLabelPlacement.hpp>
31 #include <com/sun/star/chart/ErrorBarStyle.hpp>
32 #include <com/sun/star/chart/MissingValueTreatment.hpp>
33 #include <com/sun/star/chart/TimeInterval.hpp>
34 #include <com/sun/star/chart/TimeUnit.hpp>
35 #include <com/sun/star/chart/XAxisSupplier.hpp>
36 #include <com/sun/star/chart/XDiagramPositioning.hpp>
37 #include <com/sun/star/chart2/XChartDocument.hpp>
38 #include <com/sun/star/chart2/XDiagram.hpp>
39 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
40 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
41 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
42 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
43 #include <com/sun/star/chart2/XTitled.hpp>
44 #include <com/sun/star/chart2/XColorScheme.hpp>
45 #include <com/sun/star/chart2/data/XDataSource.hpp>
46 #include <com/sun/star/chart2/AxisType.hpp>
47 #include <com/sun/star/chart2/CurveStyle.hpp>
48 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
49 #include <com/sun/star/chart2/DataPointLabel.hpp>
50 #include <com/sun/star/chart2/LegendPosition.hpp>
51 #include <com/sun/star/chart2/RelativePosition.hpp>
52 #include <com/sun/star/chart2/RelativeSize.hpp>
53 #include <com/sun/star/chart2/StackingDirection.hpp>
54 #include <com/sun/star/chart2/TickmarkStyle.hpp>
56 #include <tools/gen.hxx>
57 #include <vcl/outdev.hxx>
58 #include <filter/msfilter/escherex.hxx>
60 #include "document.hxx"
61 #include "rangelst.hxx"
62 #include "rangeutl.hxx"
63 #include "compiler.hxx"
64 #include "tokenarray.hxx"
65 #include "token.hxx"
66 #include "xeescher.hxx"
67 #include "xeformula.hxx"
68 #include "xehelper.hxx"
69 #include "xepage.hxx"
70 #include "xestyle.hxx"
72 #include <boost/scoped_ptr.hpp>
74 using ::com::sun::star::uno::Any;
75 using ::com::sun::star::uno::Reference;
76 using ::com::sun::star::uno::Sequence;
77 using ::com::sun::star::uno::UNO_QUERY;
78 using ::com::sun::star::uno::UNO_QUERY_THROW;
79 using ::com::sun::star::uno::UNO_SET_THROW;
80 using ::com::sun::star::uno::Exception;
81 using ::com::sun::star::beans::XPropertySet;
82 using ::com::sun::star::i18n::XBreakIterator;
83 using ::com::sun::star::frame::XModel;
84 using ::com::sun::star::drawing::XShape;
85 using ::com::sun::star::drawing::XShapes;
87 using ::com::sun::star::chart2::IncrementData;
88 using ::com::sun::star::chart2::RelativePosition;
89 using ::com::sun::star::chart2::RelativeSize;
90 using ::com::sun::star::chart2::ScaleData;
91 using ::com::sun::star::chart2::SubIncrement;
92 using ::com::sun::star::chart2::XAxis;
93 using ::com::sun::star::chart2::XChartDocument;
94 using ::com::sun::star::chart2::XChartTypeContainer;
95 using ::com::sun::star::chart2::XColorScheme;
96 using ::com::sun::star::chart2::XCoordinateSystem;
97 using ::com::sun::star::chart2::XCoordinateSystemContainer;
98 using ::com::sun::star::chart2::XChartType;
99 using ::com::sun::star::chart2::XDataSeries;
100 using ::com::sun::star::chart2::XDataSeriesContainer;
101 using ::com::sun::star::chart2::XDiagram;
102 using ::com::sun::star::chart2::XFormattedString;
103 using ::com::sun::star::chart2::XLegend;
104 using ::com::sun::star::chart2::XRegressionCurve;
105 using ::com::sun::star::chart2::XRegressionCurveContainer;
106 using ::com::sun::star::chart2::XScaling;
107 using ::com::sun::star::chart2::XTitle;
108 using ::com::sun::star::chart2::XTitled;
110 using ::com::sun::star::chart2::data::XDataSequence;
111 using ::com::sun::star::chart2::data::XDataSource;
112 using ::com::sun::star::chart2::data::XLabeledDataSequence;
114 using ::formula::FormulaGrammar;
115 using ::formula::FormulaToken;
117 namespace cssc = ::com::sun::star::chart;
118 namespace cssc2 = ::com::sun::star::chart2;
120 // Helpers ====================================================================
122 namespace {
124 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
126 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
129 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
131 if( xRec )
132 xRec->Save( rStrm );
135 /** Saves the passed record (group) together with a leading value record. */
136 template< typename Type >
137 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
139 if( xRec )
141 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
142 xRec->Save( rStrm );
146 template<typename ValueType, typename KeyType>
147 void lclSaveRecord(XclExpStream& rStrm, ValueType* pRec, sal_uInt16 nRecId, KeyType nValue)
149 if (pRec)
151 XclExpValueRecord<KeyType>(nRecId, nValue).Save(rStrm);
152 pRec->Save(rStrm);
156 void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
158 sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
159 rStrm.StartRecord( nRecId, 12 );
160 rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
161 rStrm.EndRecord();
164 template< typename Type >
165 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
167 return !rAny.hasValue() || !(rAny >>= rValue);
170 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
172 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
173 if( !bIsAuto && bLogScale )
174 rfValue = log( rfValue ) / log( 10.0 );
175 return bIsAuto;
178 sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit )
180 DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate );
181 switch( nTimeUnit )
183 case EXC_CHDATERANGE_DAYS:
184 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
185 case EXC_CHDATERANGE_MONTHS:
186 return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16 );
187 case EXC_CHDATERANGE_YEARS:
188 return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16 );
189 default:
190 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
192 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
195 bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit )
197 double fSerialDate = 0;
198 bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny );
199 if( !bAuto )
200 rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit );
201 return bAuto;
204 sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit )
206 switch( nApiTimeUnit )
208 case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS;
209 case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS;
210 case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS;
211 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
213 return EXC_CHDATERANGE_DAYS;
216 bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny )
218 cssc::TimeInterval aInterval;
219 bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny );
220 if( !bAuto )
222 rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16 );
223 rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit );
225 return bAuto;
228 } // namespace
230 // Common =====================================================================
232 /** Stores global data needed in various classes of the Chart export filter. */
233 struct XclExpChRootData : public XclChRootData
235 typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
237 XclExpChChart& mrChartData; /// The chart data object.
238 XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
239 XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
241 inline explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {}
243 /** Registers a new future record level. */
244 void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
245 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
246 void InitializeFutureRecBlock( XclExpStream& rStrm );
247 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
248 void FinalizeFutureRecBlock( XclExpStream& rStrm );
251 void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
253 maUnwrittenFrBlocks.push_back( rFrBlock );
256 void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
258 // first call from a future record writes all missing CHFRBLOCKBEGIN records
259 if( !maUnwrittenFrBlocks.empty() )
261 // write the leading CHFRINFO record
262 if( maWrittenFrBlocks.empty() )
264 rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
265 rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
266 rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
267 rStrm.EndRecord();
269 // write all unwritten CHFRBLOCKBEGIN records
270 for( XclChFrBlockVector::const_iterator aIt = maUnwrittenFrBlocks.begin(), aEnd = maUnwrittenFrBlocks.end(); aIt != aEnd; ++aIt )
272 OSL_ENSURE( aIt->mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
273 lclWriteChFrBlockRecord( rStrm, *aIt, true );
275 // move all record infos to vector of written blocks
276 maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
277 maUnwrittenFrBlocks.clear();
281 void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
283 OSL_ENSURE( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
284 if( !maUnwrittenFrBlocks.empty() )
286 // no future record has been written, just forget the topmost level
287 maUnwrittenFrBlocks.pop_back();
289 else if( !maWrittenFrBlocks.empty() )
291 // write the CHFRBLOCKEND record for the topmost block and delete it
292 lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
293 maWrittenFrBlocks.pop_back();
297 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) :
298 XclExpRoot( rRoot ),
299 mxChData( new XclExpChRootData( rChartData ) )
303 XclExpChRoot::~XclExpChRoot()
307 Reference< XChartDocument > XclExpChRoot::GetChartDocument() const
309 return mxChData->mxChartDoc;
312 XclExpChChart& XclExpChRoot::GetChartData() const
314 return mxChData->mrChartData;
317 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
319 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
322 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
324 return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName );
327 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
329 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
332 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc, const Rectangle& rChartRect ) const
334 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
337 void XclExpChRoot::FinishConversion() const
339 mxChData->FinishConversion();
342 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
344 XclExpPalette& rPal = GetPalette();
345 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
348 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
350 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
351 rColor = GetPalette().GetDefColor( nSysColorIdx );
352 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
355 sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const
357 return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS );
360 sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const
362 return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS );
365 XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const ::com::sun::star::awt::Rectangle& rRect ) const
367 XclChRectangle aRect;
368 aRect.mnX = CalcChartXFromHmm( rRect.X );
369 aRect.mnY = CalcChartYFromHmm( rRect.Y );
370 aRect.mnWidth = CalcChartXFromHmm( rRect.Width );
371 aRect.mnHeight = CalcChartYFromHmm( rRect.Height );
372 return aRect;
375 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
376 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
378 GetChartPropSetHelper().ReadLineProperties(
379 rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode );
382 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
383 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
385 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
388 void XclExpChRoot::ConvertEscherFormat(
389 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
390 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
392 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
393 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode );
396 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
398 XclFontData aFontData;
399 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
400 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
403 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
405 sal_Int32 nApiRot = 0;
406 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
407 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
410 void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
412 mxChData->RegisterFutureRecBlock( rFrBlock );
415 void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
417 mxChData->InitializeFutureRecBlock( rStrm );
420 void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
422 mxChData->FinalizeFutureRecBlock( rStrm );
425 XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
426 sal_uInt16 nFrType, sal_uInt16 nRecId, sal_Size nRecSize ) :
427 XclExpRecord( nRecId, nRecSize ),
428 XclExpChRoot( rRoot ),
429 maFrBlock( nFrType )
433 XclExpChGroupBase::~XclExpChGroupBase()
437 void XclExpChGroupBase::Save( XclExpStream& rStrm )
439 // header record
440 XclExpRecord::Save( rStrm );
441 // group records
442 if( HasSubRecords() )
444 // register the future record context corresponding to this record group
445 RegisterFutureRecBlock( maFrBlock );
446 // CHBEGIN record
447 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
448 // embedded records
449 WriteSubRecords( rStrm );
450 // finalize the future records, must be done before the closing CHEND
451 FinalizeFutureRecBlock( rStrm );
452 // CHEND record
453 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
457 bool XclExpChGroupBase::HasSubRecords() const
459 return true;
462 void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
464 maFrBlock.mnContext = nFrContext;
465 maFrBlock.mnValue1 = nFrValue1;
466 maFrBlock.mnValue2 = nFrValue2;
469 XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
470 XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
471 XclExpFutureRecord( eRecType, nRecId, nRecSize ),
472 XclExpChRoot( rRoot )
476 void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
478 InitializeFutureRecBlock( rStrm );
479 XclExpFutureRecord::Save( rStrm );
482 // Frame formatting ===========================================================
484 XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode, sal_uInt16 nBRMode ) :
485 XclExpRecord( EXC_ID_CHFRAMEPOS, 20 )
487 maData.mnTLMode = nTLMode;
488 maData.mnBRMode = nBRMode;
491 void XclExpChFramePos::WriteBody( XclExpStream& rStrm )
493 rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect;
496 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
497 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
498 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
502 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
504 switch( eDefFrameType )
506 case EXC_CHFRAMETYPE_AUTO:
507 SetAuto( true );
508 break;
509 case EXC_CHFRAMETYPE_INVISIBLE:
510 SetAuto( false );
511 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
512 break;
513 default:
514 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" );
518 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
519 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
521 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
522 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
523 if( HasLine() )
525 // detect system color, set color identifier (TODO: detect automatic series line)
526 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
528 // store color index from automatic format data
529 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
530 // try to set automatic mode
531 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
532 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
534 else
536 // user defined color - register in palette
537 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
540 else
542 // no line - set default system color
543 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
547 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
549 return
550 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
551 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
554 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
556 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
557 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
558 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
561 namespace {
563 /** Creates a CHLINEFORMAT record from the passed property set. */
564 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
565 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
567 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
568 xLineFmt->Convert( rRoot, rPropSet, eObjType );
569 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
570 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
571 xLineFmt.reset();
572 return xLineFmt;
575 } // namespace
577 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
578 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
579 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
580 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
584 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
585 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
587 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
588 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
589 if( HasArea() )
591 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
592 // detect system color, set color identifier (TODO: detect automatic series area)
593 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
595 // store color index from automatic format data
596 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
597 // set automatic mode
598 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
600 else
602 // user defined color - register color in palette
603 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
605 // background color (default system color for solid fills)
606 if( bSolid )
607 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
608 else
609 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
611 else
613 // no area - set default system colors
614 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
615 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
617 return bComplexFill;
620 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
622 switch( eDefFrameType )
624 case EXC_CHFRAMETYPE_AUTO:
625 SetAuto( true );
626 break;
627 case EXC_CHFRAMETYPE_INVISIBLE:
628 SetAuto( false );
629 maData.mnPattern = EXC_PATT_NONE;
630 break;
631 default:
632 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" );
636 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
638 return
639 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
640 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
643 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
645 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
646 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
648 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
649 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
653 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
654 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
655 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
656 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
658 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
661 void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
663 const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
664 ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
665 // register colors in palette
666 mnColor1Id = RegisterColor( ESCHER_Prop_fillColor );
667 mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor );
670 bool XclExpChEscherFormat::IsValid() const
672 return static_cast< bool >(maData.mxEscherSet);
675 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
677 if( maData.mxEscherSet )
679 // replace RGB colors with palette indexes in the Escher container
680 const XclExpPalette& rPal = GetPalette();
681 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
682 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
684 // save the record group
685 XclExpChGroupBase::Save( rStrm );
689 bool XclExpChEscherFormat::HasSubRecords() const
691 // no subrecords for gradients
692 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
695 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
697 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
698 rStrm << maPicFmt.mnBmpMode << sal_uInt16( 0 ) << maPicFmt.mnFlags << maPicFmt.mfScale;
699 rStrm.EndRecord();
702 sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
704 sal_uInt32 nBGRValue;
705 if( maData.mxEscherSet && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
707 // swap red and blue
708 Color aColor( RGB_COLORDATA(
709 COLORDATA_BLUE( nBGRValue ),
710 COLORDATA_GREEN( nBGRValue ),
711 COLORDATA_RED( nBGRValue ) ) );
712 return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
714 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
717 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
719 OSL_ENSURE( maData.mxEscherSet, "XclExpChEscherFormat::WriteBody - missing property container" );
720 // write Escher property container via temporary memory stream
721 SvMemoryStream aMemStrm;
722 maData.mxEscherSet->Commit( aMemStrm );
723 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
724 rStrm.CopyFromStream( aMemStrm );
727 XclExpChFrameBase::XclExpChFrameBase()
731 XclExpChFrameBase::~XclExpChFrameBase()
735 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
736 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
738 // line format
739 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
740 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
741 // area format (only for frame objects)
742 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
744 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
745 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
746 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
748 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
749 mxEscherFmt->Convert( rPropSet, eObjType );
750 if( mxEscherFmt->IsValid() )
751 mxAreaFmt->SetAuto( false );
752 else
753 mxEscherFmt.reset();
758 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
759 XclChFrameType eDefFrameType, bool bIsFrame )
761 // line format
762 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
763 mxLineFmt->SetDefault( eDefFrameType );
764 // area format (only for frame objects)
765 if( bIsFrame )
767 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
768 mxAreaFmt->SetDefault( eDefFrameType );
769 mxEscherFmt.reset();
773 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
775 return
776 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
777 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
780 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
782 lclSaveRecord( rStrm, mxLineFmt );
783 lclSaveRecord( rStrm, mxAreaFmt );
784 lclSaveRecord( rStrm, mxEscherFmt );
787 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
788 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
789 meObjType( eObjType )
793 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
795 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
798 void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize )
800 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos );
801 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize );
804 bool XclExpChFrame::IsDefault() const
806 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
809 bool XclExpChFrame::IsDeleteable() const
811 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
814 void XclExpChFrame::Save( XclExpStream& rStrm )
816 switch( meObjType )
818 // wall/floor frame without CHFRAME header record
819 case EXC_CHOBJTYPE_WALL3D:
820 case EXC_CHOBJTYPE_FLOOR3D:
821 WriteFrameRecords( rStrm );
822 break;
823 default:
824 XclExpChGroupBase::Save( rStrm );
828 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
830 WriteFrameRecords( rStrm );
833 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
835 rStrm << maData.mnFormat << maData.mnFlags;
838 namespace {
840 /** Creates a CHFRAME record from the passed property set. */
841 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
842 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
844 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
845 xFrame->Convert( rPropSet );
846 if( xFrame->IsDeleteable() )
847 xFrame.reset();
848 return xFrame;
851 } // namespace
853 // Source links ===============================================================
855 namespace {
857 void lclAddDoubleRefData(
858 ScTokenArray& orArray, const FormulaToken& rToken,
859 SCsTAB nScTab1, SCsCOL nScCol1, SCsROW nScRow1,
860 SCsTAB nScTab2, SCsCOL nScCol2, SCsROW nScRow2 )
862 ScComplexRefData aComplexRef;
863 aComplexRef.InitRange(ScRange(nScCol1,nScRow1,nScTab1,nScCol2,nScRow2,nScTab2));
864 aComplexRef.Ref1.SetFlag3D( true );
866 if( orArray.GetLen() > 0 )
867 orArray.AddOpCode( ocUnion );
869 OSL_ENSURE( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),
870 "lclAddDoubleRefData - double reference token expected");
871 if( rToken.GetType() == ::formula::svExternalDoubleRef )
872 orArray.AddExternalDoubleReference(
873 rToken.GetIndex(), rToken.GetString().getString(), aComplexRef);
874 else
875 orArray.AddDoubleReference( aComplexRef );
878 } // namespace
880 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
881 XclExpRecord( EXC_ID_CHSOURCELINK ),
882 XclExpChRoot( rRoot )
884 maData.mnDestType = nDestType;
885 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
888 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
890 mxLinkFmla.reset();
891 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
893 if( !xDataSeq.is() )
894 return nDefCount;
896 // Compile the range representation string into token array. Note that the
897 // source range text depends on the current grammar.
898 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
899 ScCompiler aComp( GetDocPtr(), ScAddress() );
900 aComp.SetGrammar( GetDocPtr()->GetGrammar() );
901 boost::scoped_ptr<ScTokenArray> pArray(aComp.CompileString(aRangeRepr));
902 if( !pArray )
903 return nDefCount;
905 ScTokenArray aArray;
906 sal_uInt32 nValueCount = 0;
907 pArray->Reset();
908 for( const FormulaToken* pToken = pArray->First(); pToken; pToken = pArray->Next() )
910 switch( pToken->GetType() )
912 case ::formula::svSingleRef:
913 case ::formula::svExternalSingleRef:
914 // for a single ref token, just add it to the new token array as is
915 if( aArray.GetLen() > 0 )
916 aArray.AddOpCode( ocUnion );
917 aArray.AddToken( *pToken );
918 ++nValueCount;
919 break;
921 case ::formula::svDoubleRef:
922 case ::formula::svExternalDoubleRef:
924 // split 3-dimensional ranges into single sheets
925 const ScComplexRefData& rComplexRef = *pToken->GetDoubleRef();
926 ScAddress aAbs1 = rComplexRef.Ref1.toAbs(ScAddress());
927 ScAddress aAbs2 = rComplexRef.Ref2.toAbs(ScAddress());
928 for (SCsTAB nScTab = aAbs1.Tab(); nScTab <= aAbs2.Tab(); ++nScTab)
930 // split 2-dimensional ranges into single columns
931 if (bSplitToColumns && (aAbs1.Col() < aAbs2.Col()) && (aAbs1.Row() < aAbs2.Row()))
932 for (SCCOL nScCol = aAbs1.Col(); nScCol <= aAbs2.Col(); ++nScCol)
933 lclAddDoubleRefData(aArray, *pToken, nScTab, nScCol, aAbs1.Row(), nScTab, nScCol, aAbs2.Row());
934 else
935 lclAddDoubleRefData(aArray, *pToken, nScTab, aAbs1.Col(), aAbs1.Row(), nScTab, aAbs2.Col(), aAbs2.Row());
937 sal_uInt32 nTabs = static_cast<sal_uInt32>(aAbs2.Tab() - aAbs1.Tab() + 1);
938 sal_uInt32 nCols = static_cast<sal_uInt32>(aAbs2.Col() - aAbs1.Col() + 1);
939 sal_uInt32 nRows = static_cast<sal_uInt32>(aAbs2.Row() - aAbs1.Row() + 1);
940 nValueCount += nCols * nRows * nTabs;
942 break;
944 default:;
948 const ScAddress aBaseCell;
949 mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
950 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
951 return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
954 void XclExpChSourceLink::ConvertString( const OUString& aString )
956 mxString = XclExpStringHelper::CreateString( GetRoot(), aString, EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
959 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
961 mxString.reset();
962 sal_uInt16 nFontIdx = EXC_FONT_APP;
963 if( rStringSeq.hasElements() )
965 mxString = XclExpStringHelper::CreateString( GetRoot(), OUString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
966 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
967 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
969 // convert all formatted string entries from the sequence
970 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
971 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
972 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
974 if( pIt->is() )
976 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
977 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
978 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
979 OUString aText = (*pIt)->getString();
980 ScfPropertySet aStrProp( *pIt );
982 // #i63255# get script type for leading weak characters
983 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
985 // process all script portions
986 sal_Int32 nPortionPos = 0;
987 sal_Int32 nTextLen = aText.getLength();
988 while( nPortionPos < nTextLen )
990 // get script type and end position of next script portion
991 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
992 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
994 // reuse previous script for following weak portions
995 if( nScript == ApiScriptType::WEAK )
996 nScript = nLastScript;
998 // Excel start position of this portion
999 sal_uInt16 nXclPortionStart = mxString->Len();
1000 // add portion text to Excel string
1001 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
1002 if( nXclPortionStart < mxString->Len() )
1004 // find font index variable dependent on script type
1005 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
1006 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
1008 // insert font into buffer (if not yet done)
1009 if( rnFontIdx == EXC_FONT_NOTFOUND )
1010 rnFontIdx = ConvertFont( aStrProp, nScript );
1012 // insert font index into format run vector
1013 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
1016 // go to next script portion
1017 nLastScript = nScript;
1018 nPortionPos = nPortionEnd;
1022 if( !mxString->IsEmpty() )
1024 // get leading font index
1025 const XclFormatRunVec& rFormats = mxString->GetFormats();
1026 OSL_ENSURE( !rFormats.empty() && (rFormats.front().mnChar == 0),
1027 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
1028 // remove leading format run, if entire string is equally formatted
1029 if( rFormats.size() == 1 )
1030 nFontIdx = mxString->RemoveLeadingFont();
1031 else if( !rFormats.empty() )
1032 nFontIdx = rFormats.front().mnFontIdx;
1033 // add trailing format run, if string is rich-formatted
1034 if( mxString->IsRich() )
1035 mxString->AppendTrailingFormat( EXC_FONT_APP );
1038 return nFontIdx;
1041 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
1043 sal_Int32 nApiNumFmt = 0;
1044 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
1046 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
1047 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
1051 void XclExpChSourceLink::AppendString( const OUString& rStr )
1053 if (!mxString)
1054 return;
1055 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
1058 void XclExpChSourceLink::Save( XclExpStream& rStrm )
1060 // CHFORMATRUNS record
1061 if( mxString && mxString->IsRich() )
1063 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
1064 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
1065 mxString->WriteFormats( rStrm, true );
1066 rStrm.EndRecord();
1068 // CHSOURCELINK record
1069 XclExpRecord::Save( rStrm );
1070 // CHSTRING record
1071 if( mxString && !mxString->IsEmpty() )
1073 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
1074 rStrm << sal_uInt16( 0 ) << *mxString;
1075 rStrm.EndRecord();
1079 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
1081 rStrm << maData.mnDestType
1082 << maData.mnLinkType
1083 << maData.mnFlags
1084 << maData.mnNumFmtIdx
1085 << mxLinkFmla;
1088 // Text =======================================================================
1090 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
1091 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
1095 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
1096 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
1098 maData.mnTarget = nLinkTarget;
1099 maData.maPointPos = rPointPos;
1102 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
1104 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
1107 XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
1108 XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
1112 void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, bool bShowSeries,
1113 bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
1115 // label value flags
1116 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, bShowSeries );
1117 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
1118 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
1119 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
1120 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
1122 // label value separator
1123 maData.maSeparator = rPropSet.GetStringProperty( EXC_CHPROP_LABELSEPARATOR );
1124 if( maData.maSeparator.isEmpty() )
1125 maData.maSeparator = " ";
1128 void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
1130 XclExpString aXclSep( maData.maSeparator, EXC_STR_FORCEUNICODE | EXC_STR_SMARTFLAGS );
1131 rStrm << maData.mnFlags << aXclSep;
1134 XclExpChFontBase::~XclExpChFontBase()
1138 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
1140 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
1142 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
1143 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
1147 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
1149 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
1152 void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet& rPropSet, bool bSupportsStacked )
1154 sal_uInt16 nRotation = XclChPropSetHelper::ReadRotationProperties( rPropSet, bSupportsStacked );
1155 SetRotation( nRotation );
1158 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
1159 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
1160 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
1164 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
1166 mxFont = xFont;
1167 maData.maTextColor = rColor;
1168 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
1169 mnTextColorId = nColorId;
1172 void XclExpChText::SetRotation( sal_uInt16 nRotation )
1174 maData.mnRotation = nRotation;
1175 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
1178 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const OUString* pSubTitle )
1180 switch( nTarget )
1182 case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
1183 case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
1184 case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 0 ); break;
1185 case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
1188 mxSrcLink.reset();
1189 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
1191 if( xTitle.is() )
1193 // title frame formatting
1194 ScfPropertySet aTitleProp( xTitle );
1195 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1197 // string sequence
1198 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1199 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1200 if (pSubTitle)
1202 // append subtitle as the 2nd line of the title.
1203 OUString aSubTitle("\n");
1204 aSubTitle += *pSubTitle;
1205 mxSrcLink->AppendString(aSubTitle);
1208 ConvertFontBase( GetChRoot(), nFontIdx );
1210 // rotation
1211 ConvertRotationBase( aTitleProp, true );
1213 // manual text position - only for main title
1214 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
1215 if( nTarget == EXC_CHOBJLINK_TITLE )
1217 Any aRelPos;
1218 if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION ) && aRelPos.has< RelativePosition >() ) try
1220 // calculate absolute position for CHTEXT record
1221 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
1222 Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW );
1223 ::com::sun::star::awt::Point aPos = xTitleShape->getPosition();
1224 ::com::sun::star::awt::Size aSize = xTitleShape->getSize();
1225 ::com::sun::star::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height );
1226 maData.maRect = CalcChartRectFromHmm( aRect );
1227 ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 );
1228 // manual title position implies manual plot area
1229 GetChartData().SetManualPlotArea();
1230 // calculate the default title position in chart units
1231 sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 );
1232 sal_Int32 nDefPosY = 85;
1233 // set the position relative to the standard position
1234 XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect;
1235 rFrameRect.mnX = maData.maRect.mnX - nDefPosX;
1236 rFrameRect.mnY = maData.maRect.mnY - nDefPosY;
1238 catch( Exception& )
1243 else
1245 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1249 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1251 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1252 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1253 ConvertFontBase( GetChRoot(), rPropSet );
1256 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1257 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1259 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
1261 cssc2::DataPointLabel aPointLabel;
1262 if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1263 return false;
1265 // percentage only allowed in pie and donut charts
1266 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1267 // bubble sizes only allowed in bubble charts
1268 bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
1269 OSL_ENSURE( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
1271 // raw show flags
1272 bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1273 bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
1274 bool bShowCateg = aPointLabel.ShowCategoryName;
1275 bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1276 bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
1278 // create the CHFRLABELPROPS record for extended settings in BIFF8
1279 if( bShowAny && (GetBiff() == EXC_BIFF8) )
1281 mxLabelProps.reset( new XclExpChFrLabelProps( GetChRoot() ) );
1282 mxLabelProps->Convert( rPropSet, false, bShowCateg, bShowValue, bShowPercent, bShowBubble );
1285 // restrict to combinations allowed in CHTEXT
1286 if( bShowPercent ) bShowValue = false; // percent wins over value
1287 if( bShowValue ) bShowCateg = false; // value wins over category
1288 if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
1290 // set all flags
1291 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1292 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1293 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1294 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1295 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1296 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
1297 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
1298 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1300 if( bShowAny )
1302 // font settings
1303 ConvertFontBase( GetChRoot(), rPropSet );
1304 ConvertRotationBase( rPropSet, false );
1305 // label placement
1306 sal_Int32 nPlacement = 0;
1307 sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO;
1308 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1310 using namespace cssc::DataLabelPlacement;
1311 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1313 nLabelPos = EXC_CHTEXT_POS_DEFAULT;
1315 else switch( nPlacement )
1317 case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break;
1318 case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break;
1319 case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break;
1320 case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1321 case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1322 case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1323 case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break;
1324 case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1325 case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1326 case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1327 case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break;
1328 case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break;
1329 case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break;
1330 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1333 ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 );
1334 // source link (contains number format)
1335 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1336 if( bShowValue || bShowPercent )
1337 // percentage format wins over value format
1338 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1339 // object link
1340 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1343 /* Return true to indicate valid label settings:
1344 - for existing labels at entire series
1345 - for any settings at single data point (to be able to delete a point label) */
1346 return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
1349 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1351 // required flags
1352 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1353 if( GetBiff() == EXC_BIFF8 )
1354 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1355 // frame formatting
1356 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1357 // font settings
1358 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1359 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1360 ConvertFontBase( GetChRoot(), rPropSet );
1361 // source link (contains number format)
1362 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1363 mxSrcLink->ConvertNumFmt( rPropSet, false );
1364 // object link
1365 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1368 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1370 sal_uInt16 nFlags = 0;
1371 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1372 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1373 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1374 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1375 return nFlags;
1378 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1380 // CHFRAMEPOS record
1381 lclSaveRecord( rStrm, mxFramePos );
1382 // CHFONT record
1383 lclSaveRecord( rStrm, mxFont );
1384 // CHSOURCELINK group
1385 lclSaveRecord( rStrm, mxSrcLink );
1386 // CHFRAME group
1387 lclSaveRecord( rStrm, mxFrame );
1388 // CHOBJECTLINK record
1389 lclSaveRecord( rStrm, mxObjLink );
1390 // CHFRLABELPROPS record
1391 lclSaveRecord( rStrm, mxLabelProps );
1394 void XclExpChText::WriteBody( XclExpStream& rStrm )
1396 rStrm << maData.mnHAlign
1397 << maData.mnVAlign
1398 << maData.mnBackMode
1399 << maData.maTextColor
1400 << maData.maRect
1401 << maData.mnFlags;
1403 if( GetBiff() == EXC_BIFF8 )
1405 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1406 << maData.mnFlags2
1407 << maData.mnRotation;
1411 namespace {
1413 /** Creates and returns an Excel text object from the passed title. */
1414 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
1415 const OUString* pSubTitle = NULL )
1417 Reference< XTitle > xTitle;
1418 if( xTitled.is() )
1419 xTitle = xTitled->getTitleObject();
1421 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1422 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1423 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1424 will be interpreted as auto-generated title showing the series title in
1425 charts that contain exactly one data series. */
1426 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1427 xText.reset();
1429 return xText;
1434 // Data series ================================================================
1436 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1437 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1438 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1439 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1443 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1444 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1446 XclChPropSetHelper::ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1447 /* Set marker line/fill color to series line color.
1448 TODO: remove this if OOChart supports own colors in markers. */
1449 Color aLineColor;
1450 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1451 maData.maLineColor = maData.maFillColor = aLineColor;
1452 // register colors in palette
1453 RegisterColors( rRoot );
1456 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1457 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1459 // clear the automatic flag
1460 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1461 // symbol type and color
1462 if( bCloseSymbol )
1464 // set symbol type for the 'close' data series
1465 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1466 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1467 // set symbol line/fill color to series line color
1468 Color aLineColor;
1469 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1471 maData.maLineColor = maData.maFillColor = aLineColor;
1472 RegisterColors( rRoot );
1475 else
1477 // set invisible symbol
1478 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1482 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1484 if( HasMarker() )
1486 if( HasLineColor() )
1487 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1488 if( HasFillColor() )
1489 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1493 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1495 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1496 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1498 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1499 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1503 XclExpChPieFormat::XclExpChPieFormat() :
1504 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1508 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1510 double fApiDist(0.0);
1511 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1512 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1515 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1516 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1520 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1522 sal_Int32 nApiType(0);
1523 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1525 using namespace cssc2::DataPointGeometry3D;
1526 switch( nApiType )
1528 case CUBOID:
1529 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1530 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1531 break;
1532 case PYRAMID:
1533 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1534 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1535 break;
1536 case CYLINDER:
1537 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1538 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1539 break;
1540 case CONE:
1541 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1542 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1543 break;
1544 default:
1545 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1550 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1552 rStrm << maData.mnBase << maData.mnTop;
1555 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1556 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1560 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1561 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1562 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
1564 maData.maPointPos = rPointPos;
1565 maData.mnFormatIdx = nFormatIdx;
1568 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1570 // line and area formatting
1571 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1573 // data point symbols
1574 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1575 if( !bIsFrame )
1577 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1578 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1581 // pie segments
1582 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1584 mxPieFmt.reset( new XclExpChPieFormat );
1585 mxPieFmt->Convert( rPropSet );
1588 // 3D bars (only allowed for entire series in BIFF8)
1589 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1591 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1592 mx3dDataFmt->Convert( rPropSet );
1595 // spline
1596 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1597 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1599 // data point labels
1600 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1601 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1603 // CHTEXT groups for data labels are stored in global CHCHART group
1604 GetChartData().SetDataLabel( xLabel );
1605 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1609 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1611 // set line format to invisible
1612 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1613 // set symbols to invisible or to 'close' series symbol
1614 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1615 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1618 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1620 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1623 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1625 lclSaveRecord( rStrm, mx3dDataFmt );
1626 WriteFrameRecords( rStrm );
1627 lclSaveRecord( rStrm, mxPieFmt );
1628 lclSaveRecord( rStrm, mxMarkerFmt );
1629 lclSaveRecord( rStrm, mxSeriesFmt );
1630 lclSaveRecord( rStrm, mxAttLabel );
1633 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1635 rStrm << maData.maPointPos.mnPointIdx
1636 << maData.maPointPos.mnSeriesIdx
1637 << maData.mnFormatIdx
1638 << maData.mnFlags;
1641 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1642 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1643 XclExpChRoot( rRoot )
1647 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1649 if( !xRegCurve.is() )
1650 return false;
1652 // trend line type
1653 ScfPropertySet aCurveProp( xRegCurve );
1655 OUString aService = aCurveProp.GetServiceName();
1656 if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
1658 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1659 maData.mnOrder = 1;
1661 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
1663 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1665 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
1667 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1669 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
1671 maData.mnLineType = EXC_CHSERTREND_POWER;
1673 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
1675 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1676 sal_Int32 aDegree;
1677 aCurveProp.GetProperty(aDegree, EXC_CHPROP_POLYNOMIAL_DEGREE);
1678 maData.mnOrder = static_cast<sal_uInt8> (aDegree);
1680 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
1682 maData.mnLineType = EXC_CHSERTREND_MOVING_AVG;
1683 sal_Int32 aPeriod;
1684 aCurveProp.GetProperty(aPeriod, EXC_CHPROP_MOVING_AVERAGE_PERIOD);
1685 maData.mnOrder = static_cast<sal_uInt8> (aPeriod);
1687 else
1689 return false;
1692 aCurveProp.GetProperty(maData.mfForecastFor, EXC_CHPROP_EXTRAPOLATE_FORWARD);
1693 aCurveProp.GetProperty(maData.mfForecastBack, EXC_CHPROP_EXTRAPOLATE_BACKWARD);
1694 bool bIsForceIntercept = false;
1695 aCurveProp.GetProperty(bIsForceIntercept, EXC_CHPROP_FORCE_INTERCEPT);
1696 if (bIsForceIntercept)
1697 aCurveProp.GetProperty(maData.mfIntercept, EXC_CHPROP_INTERCEPT_VALUE);
1699 // line formatting
1700 XclChDataPointPos aPointPos( nSeriesIdx );
1701 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1702 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1704 // #i83100# show equation and correlation coefficient
1705 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1706 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1707 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1709 // #i83100# formatting of the equation text box
1710 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1712 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1713 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1716 // missing features
1717 // #i5085# manual trend line size
1718 // #i34093# manual crossing point
1719 return true;
1722 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1724 rStrm << maData.mnLineType
1725 << maData.mnOrder
1726 << maData.mfIntercept
1727 << maData.mnShowEquation
1728 << maData.mnShowRSquared
1729 << maData.mfForecastFor
1730 << maData.mfForecastBack;
1733 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1734 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1735 XclExpChRoot( rRoot )
1737 maData.mnBarType = nBarType;
1740 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1742 sal_Int32 nBarStyle = 0;
1743 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1744 if( bOk )
1746 switch( nBarStyle )
1748 case cssc::ErrorBarStyle::ABSOLUTE:
1749 maData.mnSourceType = EXC_CHSERERR_FIXED;
1750 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1751 break;
1752 case cssc::ErrorBarStyle::RELATIVE:
1753 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1754 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1755 break;
1756 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1757 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1758 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1759 break;
1760 case cssc::ErrorBarStyle::STANDARD_ERROR:
1761 maData.mnSourceType = EXC_CHSERERR_STDERR;
1762 break;
1763 case cssc::ErrorBarStyle::FROM_DATA:
1765 bOk = false;
1766 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1767 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1768 if( xDataSource.is() )
1770 // find first sequence with current role
1771 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1772 Reference< XDataSequence > xValueSeq;
1774 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1775 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1776 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1777 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1779 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1780 ScfPropertySet aValueProp( xTmpValueSeq );
1781 OUString aCurrRole;
1782 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1783 xValueSeq = xTmpValueSeq;
1785 if( xValueSeq.is() )
1787 // #i86465# pass value count back to series
1788 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1789 bOk = maData.mnValueCount > 0;
1793 break;
1794 default:
1795 bOk = false;
1798 return bOk;
1801 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1803 rStrm << maData.mnBarType
1804 << maData.mnSourceType
1805 << maData.mnLineEnd
1806 << sal_uInt8( 1 ) // must be 1 to make line visible
1807 << maData.mfValue
1808 << maData.mnValueCount;
1811 namespace {
1813 /** Returns the property set of the specified data point. */
1814 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1816 ScfPropertySet aPropSet;
1819 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1821 catch( Exception& )
1823 OSL_FAIL( "lclGetPointPropSet - no data point property set" );
1825 return aPropSet;
1828 } // namespace
1830 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1831 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1832 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1833 mnSeriesIdx( nSeriesIdx ),
1834 mnParentIdx( EXC_CHSERIES_INVALID )
1836 // CHSOURCELINK records are always required, even if unused
1837 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1838 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1839 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1840 if( GetBiff() == EXC_BIFF8 )
1841 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1844 bool XclExpChSeries::ConvertDataSeries(
1845 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1846 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1848 bool bOk = false;
1849 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1850 if( xDataSource.is() )
1852 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
1854 // find first sequence with role 'values-y'
1855 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1856 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1857 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1858 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1860 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1861 ScfPropertySet aValueProp( xTmpValueSeq );
1862 OUString aRole;
1863 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1865 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1867 xYValueSeq = xTmpValueSeq;
1868 if( !xTitleSeq.is() )
1869 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1871 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1873 xXValueSeq = xTmpValueSeq;
1875 else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES) )
1877 xBubbleSeq = xTmpValueSeq;
1878 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1883 bOk = xYValueSeq.is();
1884 if( bOk )
1886 // chart type group index
1887 mnGroupIdx = nGroupIdx;
1889 // convert source links
1890 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1891 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1893 // X values of XY charts
1894 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1896 // size values of bubble charts
1897 if( mxBubbleLink )
1898 mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
1900 // series formatting
1901 XclChDataPointPos aPointPos( mnSeriesIdx );
1902 ScfPropertySet aSeriesProp( xDataSeries );
1903 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1904 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1906 // trend lines
1907 CreateTrendLines( xDataSeries );
1909 // error bars
1910 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1911 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1913 if( maData.mnValueCount > 0 )
1915 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1917 /* #i91063# Create missing fill properties in pie/doughnut charts.
1918 If freshly created (never saved to ODF), these charts show
1919 varying point colors but do not return these points via API. */
1920 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1922 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1923 if( xColorScheme.is() )
1925 const OUString aFillStyleName = "FillStyle";
1926 const OUString aColorName = "Color";
1927 namespace cssd = ::com::sun::star::drawing;
1928 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1930 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1931 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1932 // test that the point fill style is solid, but no color is set
1933 cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
1934 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1935 (eFillStyle == cssd::FillStyle_SOLID) &&
1936 !aPointProp.HasProperty( aColorName ) )
1938 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1944 // data point formatting
1945 Sequence< sal_Int32 > aPointIndexes;
1946 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1948 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1949 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1950 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1952 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1953 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1954 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1955 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1956 maPointFmts.AppendRecord( xPointFmt );
1962 return bOk;
1965 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1966 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1968 bool bOk = false;
1969 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1970 if( xDataSource.is() )
1972 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1974 // find first sequence with passed role
1975 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1976 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1977 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1978 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1980 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1981 ScfPropertySet aValueProp( xTmpValueSeq );
1982 OUString aRole;
1983 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
1985 xYValueSeq = xTmpValueSeq;
1986 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1990 bOk = xYValueSeq.is();
1991 if( bOk )
1993 // chart type group index
1994 mnGroupIdx = nGroupIdx;
1995 // convert source links
1996 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1997 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1998 // series formatting
1999 ScfPropertySet aSeriesProp( xDataSeries );
2000 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
2001 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
2004 return bOk;
2007 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
2009 InitFromParent( rParent );
2011 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
2012 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
2013 if( bOk )
2015 OUString aName;
2016 ScfPropertySet aProperties( xRegCurve );
2017 aProperties.GetProperty(aName, EXC_CHPROP_CURVENAME);
2018 mxTitleLink->ConvertString(aName);
2020 mxSeriesFmt = mxTrendLine->GetDataFormat();
2021 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
2023 return bOk;
2026 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
2028 InitFromParent( rParent );
2029 // error bar settings
2030 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
2031 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
2032 if( bOk )
2034 // error bar formatting
2035 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
2036 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
2038 return bOk;
2041 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2043 if( xCategSeq.is() )
2044 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
2047 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
2049 lclSaveRecord( rStrm, mxTitleLink );
2050 lclSaveRecord( rStrm, mxValueLink );
2051 lclSaveRecord( rStrm, mxCategLink );
2052 lclSaveRecord( rStrm, mxBubbleLink );
2053 lclSaveRecord( rStrm, mxSeriesFmt );
2054 maPointFmts.Save( rStrm );
2055 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
2056 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
2057 if( mnParentIdx != EXC_CHSERIES_INVALID )
2058 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
2059 lclSaveRecord( rStrm, mxTrendLine );
2060 lclSaveRecord( rStrm, mxErrorBar );
2063 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
2065 // index to parent series is stored 1-based
2066 mnParentIdx = rParent.mnSeriesIdx + 1;
2067 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2068 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2069 maData.mnCategCount = rParent.maData.mnCategCount;
2070 maData.mnValueCount = rParent.maData.mnValueCount;
2073 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
2075 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2076 if( xRegCurveCont.is() )
2078 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
2079 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
2080 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
2081 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
2083 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2084 if( xSeries && !xSeries->ConvertTrendLine( *this, *pIt ) )
2085 GetChartData().RemoveLastSeries();
2090 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
2091 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
2093 Reference< XPropertySet > xErrorBar;
2094 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
2096 ScfPropertySet aErrorProp( xErrorBar );
2097 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
2098 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
2102 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
2103 const OUString& rShowPropName, sal_uInt8 nBarId )
2105 if( rPropSet.GetBoolProperty( rShowPropName ) )
2107 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2108 if( xSeries && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
2109 GetChartData().RemoveLastSeries();
2113 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
2115 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
2116 if( GetBiff() == EXC_BIFF8 )
2117 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
2120 // Chart type groups ==========================================================
2122 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
2123 XclExpRecord( EXC_ID_CHUNKNOWN ),
2124 XclExpChRoot( rRoot ),
2125 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2129 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2130 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
2132 if( xChartType.is() )
2134 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
2135 // special handling for some chart types
2136 switch( maTypeInfo.meTypeCateg )
2138 case EXC_CHTYPECATEG_BAR:
2140 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
2141 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
2142 ScfPropertySet aTypeProp( xChartType );
2143 Sequence< sal_Int32 > aInt32Seq;
2144 maData.mnOverlap = 0;
2145 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2146 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
2147 maData.mnGap = 150;
2148 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2149 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
2151 break;
2152 case EXC_CHTYPECATEG_RADAR:
2153 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
2154 break;
2155 case EXC_CHTYPECATEG_PIE:
2157 ScfPropertySet aTypeProp( xChartType );
2158 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
2159 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2160 maData.mnPieHole = bDonut ? 50 : 0;
2161 // #i85166# starting angle of first pie slice
2162 ScfPropertySet aDiaProp( xDiagram );
2163 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
2165 break;
2166 case EXC_CHTYPECATEG_SCATTER:
2167 if( GetBiff() == EXC_BIFF8 )
2168 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
2169 break;
2170 default:;
2172 SetRecId( maTypeInfo.mnRecId );
2176 void XclExpChType::SetStacked( bool bPercent )
2178 switch( maTypeInfo.meTypeCateg )
2180 case EXC_CHTYPECATEG_LINE:
2181 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
2182 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
2183 break;
2184 case EXC_CHTYPECATEG_BAR:
2185 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
2186 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
2187 maData.mnOverlap = -100;
2188 break;
2189 default:;
2193 void XclExpChType::WriteBody( XclExpStream& rStrm )
2195 switch( GetRecId() )
2197 case EXC_ID_CHBAR:
2198 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
2199 break;
2201 case EXC_ID_CHLINE:
2202 case EXC_ID_CHAREA:
2203 case EXC_ID_CHRADARLINE:
2204 case EXC_ID_CHRADARAREA:
2205 rStrm << maData.mnFlags;
2206 break;
2208 case EXC_ID_CHPIE:
2209 rStrm << maData.mnRotation << maData.mnPieHole;
2210 if( GetBiff() == EXC_BIFF8 )
2211 rStrm << maData.mnFlags;
2212 break;
2214 case EXC_ID_CHSCATTER:
2215 if( GetBiff() == EXC_BIFF8 )
2216 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
2217 break;
2219 default:
2220 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" );
2224 XclExpChChart3d::XclExpChChart3d() :
2225 XclExpRecord( EXC_ID_CHCHART3D, 14 )
2229 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
2231 sal_Int32 nRotationY = 0;
2232 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
2233 sal_Int32 nRotationX = 0;
2234 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
2235 sal_Int32 nPerspective = 15;
2236 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
2238 if( b3dWallChart )
2240 // Y rotation (Excel [0..359], Chart2 [-179,180])
2241 if( nRotationY < 0 ) nRotationY += 360;
2242 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
2243 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2244 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
2245 // perspective (Excel and Chart2 [0,100])
2246 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2247 // flags
2248 maData.mnFlags = 0;
2249 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
2250 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
2251 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
2253 else
2255 // Y rotation not used in pie charts, but 'first pie slice angle'
2256 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
2257 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2258 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
2259 // perspective (Excel and Chart2 [0,100])
2260 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2261 // flags
2262 maData.mnFlags = 0;
2266 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
2268 rStrm << maData.mnRotation
2269 << maData.mnElevation
2270 << maData.mnEyeDist
2271 << maData.mnRelHeight
2272 << maData.mnRelDepth
2273 << maData.mnDepthGap
2274 << maData.mnFlags;
2277 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2278 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
2282 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2284 // frame properties
2285 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2286 // text properties
2287 mxText.reset( new XclExpChText( GetChRoot() ) );
2288 mxText->ConvertLegend( rPropSet );
2290 // legend position and size
2291 Any aRelPosAny, aRelSizeAny;
2292 rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION );
2293 rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE );
2294 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2295 rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION );
2296 if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) )
2300 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2301 indicator of manually changed legend position/size, but due to
2302 the different anchor modes used by this property (in the
2303 RelativePosition.Anchor member) it cannot be used to calculate
2304 the position easily. For this, the Chart1 API will be used
2305 instead. */
2306 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
2307 Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW );
2308 // coordinates in CHLEGEND record written but not used by Excel
2309 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE, EXC_CHFRAMEPOS_PARENT ) );
2310 XclChFramePos& rFramePos = mxFramePos->GetFramePosData();
2311 rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE;
2312 ::com::sun::star::awt::Point aLegendPos = xChart1Legend->getPosition();
2313 rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X );
2314 rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y );
2315 // legend size, Excel expects points in CHFRAMEPOS record
2316 rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS;
2317 ::com::sun::star::awt::Size aLegendSize = xChart1Legend->getSize();
2318 rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 );
2319 rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 );
2320 maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width );
2321 maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height );
2322 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2323 // manual legend position implies manual plot area
2324 GetChartData().SetManualPlotArea();
2325 maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED;
2326 // a CHFRAME record with cleared auto flags is needed
2327 if( !mxFrame )
2328 mxFrame.reset( new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
2329 mxFrame->SetAutoFlags( false, false );
2331 catch( Exception& )
2333 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
2334 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2335 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2338 else
2340 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
2341 rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION );
2342 switch( eApiPos )
2344 case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break;
2345 case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break;
2346 case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break;
2347 case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break;
2348 default:
2349 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
2350 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2351 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2354 ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH );
2356 // other flags
2357 ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES );
2358 const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY;
2359 ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED );
2362 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2364 lclSaveRecord( rStrm, mxFramePos );
2365 lclSaveRecord( rStrm, mxText );
2366 lclSaveRecord( rStrm, mxFrame );
2369 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2371 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2374 XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
2375 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
2376 meObjType( eObjType ),
2377 mnBarDist( 100 )
2381 void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
2383 if( rPropSet.Is() )
2384 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
2385 else
2386 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
2389 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2391 WriteFrameRecords( rStrm );
2394 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2396 rStrm << mnBarDist;
2399 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2400 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
2401 maType( rRoot ),
2402 maTypeInfo( maType.GetTypeInfo() )
2404 maData.mnGroupIdx = nGroupIdx;
2407 void XclExpChTypeGroup::ConvertType(
2408 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2409 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2411 // chart type settings
2412 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2414 // spline - TODO: get from single series (#i66858#)
2415 ScfPropertySet aTypeProp( xChartType );
2416 cssc2::CurveStyle eCurveStyle;
2417 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2418 (eCurveStyle != cssc2::CurveStyle_LINES);
2420 // extended type info
2421 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2423 // 3d chart settings
2424 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2426 mxChart3d.reset( new XclExpChChart3d );
2427 ScfPropertySet aDiaProp( xDiagram );
2428 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2432 void XclExpChTypeGroup::ConvertSeries(
2433 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2434 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2436 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2437 if( xSeriesCont.is() )
2439 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2440 XDataSeriesVec aSeriesVec;
2442 // copy data series attached to the current axes set to the vector
2443 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2444 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2445 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2446 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2448 ScfPropertySet aSeriesProp( *pIt );
2449 sal_Int32 nSeriesAxesSetIdx(0);
2450 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2451 aSeriesVec.push_back( *pIt );
2454 // Are there any series in the current axes set?
2455 if( !aSeriesVec.empty() )
2457 // stacking direction (stacked/percent/deep 3d) from first series
2458 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2459 cssc2::StackingDirection eStacking;
2460 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2461 eStacking = cssc2::StackingDirection_NO_STACKING;
2463 // stacked or percent chart
2464 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) )
2466 // percent overrides simple stacking
2467 maType.SetStacked( bPercent );
2469 // connected data points (only in stacked bar charts)
2470 if (bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR))
2472 sal_uInt16 nKey = EXC_CHCHARTLINE_CONNECT;
2473 maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
2476 else
2478 // reverse series order for some unstacked 2D chart types
2479 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2480 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2483 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2484 if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() )
2485 mxChart3d->SetClustered();
2487 // varied point colors
2488 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2490 // process all series
2491 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2493 // create Excel series object, stock charts need special processing
2494 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2495 CreateAllStockSeries( xChartType, *aIt );
2496 else
2497 CreateDataSeries( xDiagram, *aIt );
2503 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2505 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2506 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2509 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2511 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2513 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2514 mxLegend->Convert( rPropSet );
2518 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2520 maType.Save( rStrm );
2521 lclSaveRecord( rStrm, mxChart3d );
2522 lclSaveRecord( rStrm, mxLegend );
2523 lclSaveRecord( rStrm, mxUpBar );
2524 lclSaveRecord( rStrm, mxDownBar );
2525 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2526 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2529 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2531 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2534 void XclExpChTypeGroup::CreateDataSeries(
2535 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2537 // let chart create series object with correct series index
2538 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2539 if( xSeries )
2541 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2542 maSeries.AppendRecord( xSeries );
2543 else
2544 GetChartData().RemoveLastSeries();
2548 void XclExpChTypeGroup::CreateAllStockSeries(
2549 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2551 // create existing series objects
2552 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2553 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2554 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2555 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2557 // formatting of special stock chart elements
2558 ScfPropertySet aTypeProp( xChartType );
2559 // hi-lo lines
2560 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2562 ScfPropertySet aSeriesProp( xDataSeries );
2563 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2564 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2565 sal_uInt16 nKey = EXC_CHCHARTLINE_HILO;
2566 maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
2568 // dropbars
2569 if( bHasOpen && bHasClose )
2571 // dropbar type is dependent on position in the file - always create both
2572 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2573 // white dropbar format
2574 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2575 ScfPropertySet aWhiteProp( xWhitePropSet );
2576 mxUpBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ) );
2577 mxUpBar->Convert( aWhiteProp );
2578 // black dropbar format
2579 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2580 ScfPropertySet aBlackProp( xBlackPropSet );
2581 mxDownBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ) );
2582 mxDownBar->Convert( aBlackProp );
2586 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2587 const OUString& rValueRole, bool bCloseSymbol )
2589 bool bOk = false;
2590 // let chart create series object with correct series index
2591 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2592 if( xSeries )
2594 bOk = xSeries->ConvertStockSeries( xDataSeries,
2595 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2596 if( bOk )
2597 maSeries.AppendRecord( xSeries );
2598 else
2599 GetChartData().RemoveLastSeries();
2601 return bOk;
2604 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2606 rStrm.WriteZeroBytes( 16 );
2607 rStrm << maData.mnFlags << maData.mnGroupIdx;
2610 // Axes =======================================================================
2612 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2613 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2614 XclExpChRoot( rRoot )
2618 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient )
2620 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2621 chart API allows to detect axis type (date axis, if property exists),
2622 and to receive the base time unit currently used in case the base time
2623 unit is set to 'automatic'. */
2624 cssc::TimeIncrement aTimeIncrement;
2625 if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT ) )
2627 // property exists -> this is a date axis currently
2628 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2630 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2631 bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >();
2632 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase );
2634 // ...but get the current base time unit from the property of the old chart API
2635 sal_Int32 nApiTimeUnit = 0;
2636 bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit;
2637 OSL_ENSURE( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot get base time unit" );
2638 maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS;
2640 /* Min/max values depend on base time unit, they specify the number of
2641 days, months, or years starting from null date. */
2642 bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit );
2643 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin );
2644 bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit );
2645 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax );
2648 // automatic axis type detection
2649 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis );
2651 // increment
2652 bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval );
2653 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor );
2654 bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval );
2655 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor );
2657 // origin
2658 double fOrigin = 0.0;
2659 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
2660 maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
2662 // reverse order
2663 if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient )
2664 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2667 void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2669 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2670 rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION );
2671 double fCrossingPos = 1.0;
2672 rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE );
2674 bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2675 switch( eAxisPos )
2677 case cssc::ChartAxisPosition_ZERO:
2678 case cssc::ChartAxisPosition_START:
2679 maLabelData.mnCross = 1;
2680 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2681 break;
2682 case cssc::ChartAxisPosition_END:
2683 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS );
2684 break;
2685 case cssc::ChartAxisPosition_VALUE:
2686 maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 );
2687 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false );
2688 if( bDateAxis )
2689 maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit );
2690 break;
2691 default:
2692 maLabelData.mnCross = 1;
2693 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2697 void XclExpChLabelRange::Save( XclExpStream& rStrm )
2699 // the CHLABELRANGE record
2700 XclExpRecord::Save( rStrm );
2702 // the CHDATERANGE record with date axis settings (BIFF8 only)
2703 if( GetBiff() == EXC_BIFF8 )
2705 rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 );
2706 rStrm << maDateData.mnMinDate
2707 << maDateData.mnMaxDate
2708 << maDateData.mnMajorStep
2709 << maDateData.mnMajorUnit
2710 << maDateData.mnMinorStep
2711 << maDateData.mnMinorUnit
2712 << maDateData.mnBaseUnit
2713 << maDateData.mnCross
2714 << maDateData.mnFlags;
2715 rStrm.EndRecord();
2719 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2721 rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags;
2724 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2725 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2726 XclExpChRoot( rRoot )
2730 void XclExpChValueRange::Convert( const ScaleData& rScaleData )
2732 // scaling algorithm
2733 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == "com.sun.star.chart2.LogarithmicScaling";
2734 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2736 // min/max
2737 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
2738 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2739 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
2740 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2742 // origin
2743 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
2744 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2746 // major increment
2747 const IncrementData& rIncrementData = rScaleData.IncrementData;
2748 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
2749 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2750 // minor increment
2751 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2752 sal_Int32 nCount = 0;
2753 bool bAutoMinor = bLogScale || bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2754 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1);
2755 if( !bAutoMinor )
2756 maData.mfMinorStep = maData.mfMajorStep / nCount;
2757 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2759 // reverse order
2760 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE );
2763 void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2765 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2766 double fCrossingPos = 0.0;
2767 if( rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE ) )
2769 switch( eAxisPos )
2771 case cssc::ChartAxisPosition_ZERO:
2772 case cssc::ChartAxisPosition_START:
2773 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2774 break;
2775 case cssc::ChartAxisPosition_END:
2776 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2777 break;
2778 case cssc::ChartAxisPosition_VALUE:
2779 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
2780 maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
2781 break;
2782 default:
2783 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2788 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2790 rStrm << maData.mfMin
2791 << maData.mfMax
2792 << maData.mfMajorStep
2793 << maData.mfMinorStep
2794 << maData.mfCross
2795 << maData.mnFlags;
2798 namespace {
2800 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2802 using namespace cssc2::TickmarkStyle;
2803 sal_uInt8 nXclTickPos = 0;
2804 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2805 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2806 return nXclTickPos;
2809 } // namespace
2811 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2812 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2813 XclExpChRoot( rRoot ),
2814 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2818 void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
2820 // tick mark style
2821 sal_Int32 nApiTickmarks = 0;
2822 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2823 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2824 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2825 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2827 // axis labels
2828 if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
2830 /* Radar charts disable their category labels via chart type, not via
2831 axis, and axis labels are always 'near axis'. */
2832 maData.mnLabelPos = EXC_CHTICK_NEXT;
2834 else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2836 // no labels
2837 maData.mnLabelPos = EXC_CHTICK_NOLABEL;
2839 else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
2841 // Excel expects 'near axis' at Y axes in 3D charts
2842 maData.mnLabelPos = EXC_CHTICK_NEXT;
2844 else
2846 cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
2847 rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION );
2848 switch( eApiLabelPos )
2850 case cssc::ChartAxisLabelPosition_NEAR_AXIS:
2851 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
2852 case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
2853 case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
2854 default: maData.mnLabelPos = EXC_CHTICK_NEXT;
2859 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2861 maData.maTextColor = rColor;
2862 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2863 mnTextColorId = nColorId;
2866 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2868 maData.mnRotation = nRotation;
2869 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2870 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2873 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2875 rStrm << maData.mnMajor
2876 << maData.mnMinor
2877 << maData.mnLabelPos
2878 << maData.mnBackMode;
2879 rStrm.WriteZeroBytes( 16 );
2880 rStrm << maData.maTextColor
2881 << maData.mnFlags;
2882 if( GetBiff() == EXC_BIFF8 )
2883 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2886 namespace {
2888 /** Returns an API axis object from the passed coordinate system. */
2889 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2890 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2892 Reference< XAxis > xAxis;
2893 if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
2895 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2897 catch( Exception& )
2900 return xAxis;
2903 Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > xChartDoc,
2904 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2906 Reference< cssc::XAxis > xChart1Axis;
2909 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW );
2910 Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
2911 switch( nApiAxesSetIdx )
2913 case EXC_CHART_AXESSET_PRIMARY:
2914 xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim );
2915 break;
2916 case EXC_CHART_AXESSET_SECONDARY:
2917 xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim );
2918 break;
2921 catch( Exception& )
2924 return xChart1Axis;
2927 } // namespace
2929 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2930 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
2931 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2933 maData.mnType = nAxisType;
2936 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2938 mxFont = xFont;
2939 if( mxTick )
2940 mxTick->SetFontColor( rColor, nColorId );
2943 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2945 if( mxTick )
2946 mxTick->SetRotation( nRotation );
2949 void XclExpChAxis::Convert( Reference< XAxis > xAxis, Reference< XAxis > xCrossingAxis,
2950 Reference< cssc::XAxis > xChart1Axis, const XclChExtTypeInfo& rTypeInfo )
2952 ScfPropertySet aAxisProp( xAxis );
2953 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2955 // axis line format -------------------------------------------------------
2957 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2958 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2959 // #i58688# axis enabled
2960 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2962 // axis scaling and increment ---------------------------------------------
2964 ScfPropertySet aCrossingProp( xCrossingAxis );
2965 if( bCategoryAxis )
2967 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2968 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2969 if( xAxis.is() )
2971 ScfPropertySet aChart1AxisProp( xChart1Axis );
2972 // #i71684# radar charts have reversed rotation direction
2973 mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2975 // get position of crossing axis on this axis from passed axis object
2976 if( aCrossingProp.Is() )
2977 mxLabelRange->ConvertAxisPosition( aCrossingProp );
2979 else
2981 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
2982 if( xAxis.is() )
2983 mxValueRange->Convert( xAxis->getScaleData() );
2984 // get position of crossing axis on this axis from passed axis object
2985 if( aCrossingProp.Is() )
2986 mxValueRange->ConvertAxisPosition( aCrossingProp );
2989 // axis caption text ------------------------------------------------------
2991 // axis ticks properties
2992 mxTick.reset( new XclExpChTick( GetChRoot() ) );
2993 mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
2995 // axis label formatting and rotation
2996 ConvertFontBase( GetChRoot(), aAxisProp );
2997 ConvertRotationBase( aAxisProp, true );
2999 // axis number format
3000 sal_Int32 nApiNumFmt = 0;
3001 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
3002 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
3004 // grid -------------------------------------------------------------------
3006 if( xAxis.is() )
3008 // main grid
3009 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3010 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3011 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3012 // sub grid
3013 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3014 if( aSubGridPropSeq.hasElements() )
3016 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3017 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
3018 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3023 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
3025 if( xDiagram.is() ) switch( GetAxisType() )
3027 case EXC_CHAXIS_X:
3029 ScfPropertySet aWallProp( xDiagram->getWall() );
3030 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
3032 break;
3033 case EXC_CHAXIS_Y:
3035 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3036 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
3038 break;
3039 default:
3040 mxWallFrame.reset();
3044 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
3046 lclSaveRecord( rStrm, mxLabelRange );
3047 lclSaveRecord( rStrm, mxValueRange );
3048 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
3049 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
3050 lclSaveRecord( rStrm, mxTick );
3051 lclSaveRecord( rStrm, mxFont );
3052 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
3053 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
3054 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
3055 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
3058 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
3060 rStrm << maData.mnType;
3061 rStrm.WriteZeroBytes( 16 );
3064 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3065 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
3067 maData.mnAxesSetId = nAxesSetId;
3068 SetFutureRecordContext( 0, nAxesSetId );
3070 /* Need to set a reasonable size for the plot area, otherwise Excel will
3071 move away embedded shapes while auto-sizing the plot area. This is just
3072 a wild guess, but will be fixed with implementing manual positioning of
3073 chart elements. */
3074 maData.maRect.mnX = 262;
3075 maData.maRect.mnY = 626;
3076 maData.maRect.mnWidth = 3187;
3077 maData.maRect.mnHeight = 2633;
3080 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
3082 /* First unused chart type group index is passed to be able to continue
3083 counting of chart type groups for secondary axes set. */
3084 sal_uInt16 nGroupIdx = nFirstGroupIdx;
3085 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
3086 if( xCoordSysCont.is() )
3088 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
3089 if( aCoordSysSeq.getLength() > 0 )
3091 /* Process first coordinate system only. Import filter puts all
3092 chart types into one coordinate system. */
3093 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
3094 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3096 // 3d mode
3097 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
3099 // percent charts
3100 namespace ApiAxisType = cssc2::AxisType;
3101 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
3102 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
3104 // connector lines in bar charts
3105 ScfPropertySet aDiaProp( xDiagram );
3106 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
3108 // swapped axes sets
3109 ScfPropertySet aCoordSysProp( xCoordSystem );
3110 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
3112 // X axis for later use
3113 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
3114 // X axis labels
3115 ScfPropertySet aXAxisProp( xApiXAxis );
3116 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
3118 // process chart types
3119 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3120 if( xChartTypeCont.is() )
3122 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
3123 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
3124 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
3125 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
3127 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
3128 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
3129 /* If new chart type group cannot be inserted into a combination
3130 chart with existing type groups, insert all series into last
3131 contained chart type group instead of creating a new group. */
3132 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
3133 if( xLastGroup && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
3135 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3137 else
3139 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
3140 if( xTypeGroup->IsValidGroup() )
3142 maTypeGroups.AppendRecord( xTypeGroup );
3143 ++nGroupIdx;
3149 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
3151 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
3153 // create axes according to chart type (no axes for pie and donut charts)
3154 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
3156 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
3157 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
3158 if( pGroup->Is3dDeepChart() )
3159 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
3162 // X axis category ranges
3163 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
3165 const ScaleData aScaleData = xApiXAxis->getScaleData();
3166 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
3167 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
3170 // legend
3171 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3173 Reference< XLegend > xLegend = xDiagram->getLegend();
3174 if( xLegend.is() )
3176 ScfPropertySet aLegendProp( xLegend );
3177 pGroup->ConvertLegend( aLegendProp );
3184 // wall/floor/diagram frame formatting
3185 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3187 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3188 if( xTypeGroup && xTypeGroup->Is3dWallChart() )
3190 // wall/floor formatting (3D charts)
3191 if( mxXAxis )
3192 mxXAxis->ConvertWall( xDiagram );
3193 if( mxYAxis )
3194 mxYAxis->ConvertWall( xDiagram );
3196 else
3198 // diagram background formatting
3199 ScfPropertySet aWallProp( xDiagram->getWall() );
3200 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
3204 // inner and outer plot area position and size
3207 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
3208 Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
3209 // set manual flag in chart data
3210 if( !xPositioning->isAutomaticDiagramPositioning() )
3211 GetChartData().SetManualPlotArea();
3212 // the CHAXESSET record contains the inner plot area
3213 maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() );
3214 // the embedded CHFRAMEPOS record contains the outer plot area
3215 mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
3216 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3217 const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get();
3218 bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE);
3219 mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect :
3220 CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() );
3222 catch( Exception& )
3226 // return first unused chart type group index for next axes set
3227 return nGroupIdx;
3230 bool XclExpChAxesSet::Is3dChart() const
3232 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3233 return xTypeGroup && xTypeGroup->Is3dChart();
3236 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
3238 lclSaveRecord( rStrm, mxFramePos );
3239 lclSaveRecord( rStrm, mxXAxis );
3240 lclSaveRecord( rStrm, mxYAxis );
3241 lclSaveRecord( rStrm, mxZAxis );
3242 lclSaveRecord( rStrm, mxXAxisTitle );
3243 lclSaveRecord( rStrm, mxYAxisTitle );
3244 lclSaveRecord( rStrm, mxZAxisTitle );
3245 if( mxPlotFrame )
3247 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
3248 mxPlotFrame->Save( rStrm );
3250 maTypeGroups.Save( rStrm );
3253 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
3255 return maTypeGroups.GetFirstRecord();
3258 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
3260 return maTypeGroups.GetLastRecord();
3263 void XclExpChAxesSet::ConvertAxis(
3264 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
3265 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
3266 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
3267 sal_Int32 nCrossingAxisDim )
3269 // create and convert axis object
3270 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
3271 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
3272 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3273 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
3274 Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
3275 Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx );
3276 rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo );
3278 // create and convert axis title
3279 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
3280 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
3283 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
3285 rStrm << maData.mnAxesSetId << maData.maRect;
3288 // The chart object ===========================================================
3290 static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
3291 OUString& rSubTitle)
3293 Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
3294 if (!xChartDoc1.is())
3295 return;
3297 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
3298 if (!xProp.is())
3299 return;
3301 OUString aTitle;
3302 Any any = xProp->getPropertyValue("String");
3303 if (any >>= aTitle)
3304 rSubTitle = aTitle;
3307 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
3308 Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) :
3309 XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
3311 Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
3312 // rectangle is stored in 16.16 fixed-point format
3313 maRect.mnX = maRect.mnY = 0;
3314 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
3315 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
3317 // global chart properties (default values)
3318 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
3319 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA );
3320 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
3322 // always create both axes set objects
3323 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
3324 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
3326 if( xChartDoc.is() )
3328 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
3330 // global chart properties (only 'include hidden cells' attribute for now)
3331 ScfPropertySet aDiagramProp( xDiagram );
3332 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
3333 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
3335 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3336 InitConversion( xChartDoc, rChartRect );
3338 // chart frame
3339 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3340 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
3342 // chart title
3343 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3344 OUString aSubTitle;
3345 lcl_getChartSubTitle(xChartDoc, aSubTitle);
3346 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
3347 !aSubTitle.isEmpty() ? &aSubTitle : NULL );
3349 // diagrams (axes sets)
3350 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
3351 if( !mxPrimAxesSet->Is3dChart() )
3352 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
3354 // treatment of missing values
3355 ScfPropertySet aDiaProp( xDiagram );
3356 sal_Int32 nMissingValues = 0;
3357 if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT ) )
3359 using namespace cssc::MissingValueTreatment;
3360 switch( nMissingValues )
3362 case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
3363 case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
3364 case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
3368 // finish API conversion
3369 FinishConversion();
3373 XclExpChSeriesRef XclExpChChart::CreateSeries()
3375 XclExpChSeriesRef xSeries;
3376 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
3377 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3379 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
3380 maSeries.AppendRecord( xSeries );
3382 return xSeries;
3385 void XclExpChChart::RemoveLastSeries()
3387 if( !maSeries.IsEmpty() )
3388 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
3391 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
3393 if( xText )
3394 maLabels.AppendRecord( xText );
3397 void XclExpChChart::SetManualPlotArea()
3399 // this flag does not exist in BIFF5
3400 if( GetBiff() == EXC_BIFF8 )
3401 ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3404 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
3406 // background format
3407 lclSaveRecord( rStrm, mxFrame );
3409 // data series
3410 maSeries.Save( rStrm );
3412 // CHPROPERTIES record
3413 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
3414 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
3415 rStrm.EndRecord();
3417 // axes sets (always save primary axes set)
3418 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
3419 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
3420 mxPrimAxesSet->Save( rStrm );
3421 if( mxSecnAxesSet->IsValidAxesSet() )
3422 mxSecnAxesSet->Save( rStrm );
3424 // chart title and data labels
3425 lclSaveRecord( rStrm, mxTitle );
3426 maLabels.Save( rStrm );
3429 void XclExpChChart::WriteBody( XclExpStream& rStrm )
3431 rStrm << maRect;
3434 XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot,
3435 const Reference< XModel >& rxModel, const Size& rChartSize ) :
3436 XclExpRoot( rRoot )
3438 if( (rChartSize.Width() > 0) && (rChartSize.Height() > 0) )
3440 ScfPropertySet aPropSet( rxModel );
3441 Reference< XShapes > xShapes;
3442 if( aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES ) && xShapes.is() && (xShapes->getCount() > 0) )
3444 /* Create a new independent object manager with own DFF stream for the
3445 DGCONTAINER, pass global manager as parent for shared usage of
3446 global DFF data (picture container etc.). */
3447 mxObjMgr.reset( new XclExpEmbeddedObjectManager( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS ) );
3448 // initialize the drawing object list
3449 mxObjMgr->StartSheet();
3450 // process the draw page (convert all shapes)
3451 mxObjRecs = mxObjMgr->ProcessDrawing( xShapes );
3452 // finalize the DFF stream
3453 mxObjMgr->EndDocument();
3458 XclExpChartDrawing::~XclExpChartDrawing()
3462 void XclExpChartDrawing::Save( XclExpStream& rStrm )
3464 if( mxObjRecs )
3465 mxObjRecs->Save( rStrm );
3468 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Rectangle& rChartRect ) :
3469 XclExpSubStream( EXC_BOF_CHART ),
3470 XclExpRoot( rRoot )
3472 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
3473 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
3474 AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) );
3475 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
3477 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3478 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) );
3481 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */