Update to m13
[ooovba.git] / sc / source / filter / xlsx / xlsx-xechart.cxx
blob5198737cfa6e9e59f10b18b51ad202302c2dadac
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xechart.cxx,v $
10 * $Revision: 1.10.62.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "xlsx/xladdress.hxx"
35 #include "xlsx/xlconst.hxx"
36 #include "xlsx/xlformula.hxx"
37 #include "xechart.hxx"
39 #include <com/sun/star/i18n/XBreakIterator.hpp>
40 #include <com/sun/star/i18n/ScriptType.hpp>
41 #include <com/sun/star/drawing/FillStyle.hpp>
42 #include <com/sun/star/chart/XChartDocument.hpp>
43 #include <com/sun/star/chart2/XChartDocument.hpp>
44 #include <com/sun/star/chart2/XDiagram.hpp>
45 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
46 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
47 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
48 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
49 #include <com/sun/star/chart2/XTitled.hpp>
50 #include <com/sun/star/chart2/XColorScheme.hpp>
51 #include <com/sun/star/chart2/data/XDataSource.hpp>
52 #include <com/sun/star/chart2/AxisType.hpp>
53 #include <com/sun/star/chart2/CurveStyle.hpp>
54 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
55 #include <com/sun/star/chart2/DataPointLabel.hpp>
56 #include <com/sun/star/chart2/StackingDirection.hpp>
57 #include <com/sun/star/chart2/TickmarkStyle.hpp>
58 #include <com/sun/star/chart/DataLabelPlacement.hpp>
59 #include <com/sun/star/chart/ErrorBarStyle.hpp>
61 #include <vcl/outdev.hxx>
62 #include <svx/escherex.hxx>
64 #include "document.hxx"
65 #include "rangelst.hxx"
66 #include "rangeutl.hxx"
67 #include "xeformula.hxx"
68 #include "xehelper.hxx"
69 #include "xepage.hxx"
70 #include "xestyle.hxx"
71 #include "compiler.hxx"
72 #include "tokenarray.hxx"
73 #include "token.hxx"
75 using ::rtl::OUString;
76 using ::com::sun::star::uno::Any;
77 using ::com::sun::star::uno::Reference;
78 using ::com::sun::star::uno::Sequence;
79 using ::com::sun::star::uno::UNO_QUERY;
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::chart2::XChartDocument;
85 using ::com::sun::star::chart2::XDiagram;
86 using ::com::sun::star::chart2::XCoordinateSystemContainer;
87 using ::com::sun::star::chart2::XCoordinateSystem;
88 using ::com::sun::star::chart2::XChartTypeContainer;
89 using ::com::sun::star::chart2::XChartType;
90 using ::com::sun::star::chart2::XDataSeriesContainer;
91 using ::com::sun::star::chart2::XDataSeries;
92 using ::com::sun::star::chart2::XRegressionCurveContainer;
93 using ::com::sun::star::chart2::XRegressionCurve;
94 using ::com::sun::star::chart2::XAxis;
95 using ::com::sun::star::chart2::XScaling;
96 using ::com::sun::star::chart2::ScaleData;
97 using ::com::sun::star::chart2::IncrementData;
98 using ::com::sun::star::chart2::SubIncrement;
99 using ::com::sun::star::chart2::XLegend;
100 using ::com::sun::star::chart2::XTitled;
101 using ::com::sun::star::chart2::XTitle;
102 using ::com::sun::star::chart2::XFormattedString;
103 using ::com::sun::star::chart2::XColorScheme;
105 using ::com::sun::star::chart2::data::XDataSource;
106 using ::com::sun::star::chart2::data::XLabeledDataSequence;
107 using ::com::sun::star::chart2::data::XDataSequence;
109 // Helpers ====================================================================
111 namespace {
113 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
115 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
118 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
120 if( xRec.is() )
121 xRec->Save( rStrm );
124 /** Saves the passed record (group) together with a leading value record. */
125 template< typename Type >
126 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
128 if( xRec.is() )
130 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
131 xRec->Save( rStrm );
135 template< typename Type >
136 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny, bool bPercent )
138 if (!rAny.hasValue())
139 return true;
141 if (rAny >>= rValue)
143 if (bPercent)
144 rValue *= 100.0;
145 return false;
147 else
148 return true;
151 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, Reference< XScaling > xScaling, bool bPercent )
153 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny, bPercent );
154 if( !bIsAuto && xScaling.is() )
155 rfValue = xScaling->doScaling( rfValue );
157 return bIsAuto;
160 } // namespace
162 // Common =====================================================================
164 /** Stores global data needed in various classes of the Chart export filter. */
165 class XclExpChRootData : public XclChRootData
167 public:
168 explicit XclExpChRootData( XclExpChChart* pChartData );
170 /** Returns a reference to the parent chart data object. */
171 inline XclExpChChart& GetChartData() const { return *mpChartData; }
173 private:
174 XclExpChChart* mpChartData; /// Pointer to the chart data object.
177 XclExpChRootData::XclExpChRootData( XclExpChChart* pChartData ) :
178 mpChartData( pChartData )
182 // ----------------------------------------------------------------------------
184 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart* pChartData ) :
185 XclExpRoot( rRoot ),
186 mxChData( new XclExpChRootData( pChartData ) )
190 XclExpChRoot::~XclExpChRoot()
194 XclExpChChart& XclExpChRoot::GetChartData() const
196 return mxChData->GetChartData();
199 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
201 return mxChData->GetTypeInfoProvider().GetTypeInfo( eType );
204 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
206 return mxChData->GetTypeInfoProvider().GetTypeInfoFromService( rServiceName );
209 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
211 return mxChData->GetFormatInfoProvider().GetFormatInfo( eObjType );
214 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc ) const
216 mxChData->InitConversion( xChartDoc );
219 void XclExpChRoot::FinishConversion() const
221 mxChData->FinishConversion();
224 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
226 XclExpPalette& rPal = GetPalette();
227 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
230 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
232 DBG_ASSERT( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
233 rColor = GetPalette().GetDefColor( nSysColorIdx );
234 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
237 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
238 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
240 GetChartPropSetHelper().ReadLineProperties(
241 rLineFmt, mxChData->GetLineDashTable(), rPropSet, ePropMode );
244 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
245 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
247 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
250 void XclExpChRoot::ConvertEscherFormat(
251 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
252 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
254 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
255 mxChData->GetGradientTable(), mxChData->GetHatchTable(), mxChData->GetBitmapTable(), rPropSet, ePropMode );
258 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
260 XclFontData aFontData;
261 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
262 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
265 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
267 sal_Int32 nApiRot = 0;
268 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
269 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
272 // ----------------------------------------------------------------------------
274 XclExpChGroupBase::XclExpChGroupBase( sal_uInt16 nRecId, sal_Size nRecSize ) :
275 XclExpRecord( nRecId, nRecSize )
279 XclExpChGroupBase::~XclExpChGroupBase()
283 void XclExpChGroupBase::Save( XclExpStream& rStrm )
285 // header record
286 XclExpRecord::Save( rStrm );
287 // group records
288 if( HasSubRecords() )
290 // CHBEGIN record
291 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
292 // embedded records
293 WriteSubRecords( rStrm );
294 // CHEND record
295 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
299 bool XclExpChGroupBase::HasSubRecords() const
301 return true;
304 // Frame formatting ===========================================================
306 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
307 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
308 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
312 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
314 switch( eDefFrameType )
316 case EXC_CHFRAMETYPE_AUTO:
317 SetAuto( true );
318 break;
319 case EXC_CHFRAMETYPE_INVISIBLE:
320 SetAuto( false );
321 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
322 break;
323 default:
324 DBG_ERRORFILE( "XclExpChLineFormat::SetDefault - unknown frame type" );
328 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
329 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
331 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
332 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
333 if( HasLine() )
335 // detect system color, set color identifier (TODO: detect automatic series line)
336 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
338 // store color index from automatic format data
339 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
340 // try to set automatic mode
341 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
342 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
344 else
346 // user defined color - register in palette
347 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
350 else
352 // no line - set default system color
353 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
357 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
359 return
360 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
361 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
364 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
366 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
367 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
368 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
371 namespace {
373 /** Creates a CHLINEFORMAT record from the passed property set. */
374 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
375 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
377 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
378 xLineFmt->Convert( rRoot, rPropSet, eObjType );
379 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
380 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
381 xLineFmt.reset();
382 return xLineFmt;
385 } // namespace
387 // ----------------------------------------------------------------------------
389 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
390 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
391 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
392 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
396 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
397 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
399 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
400 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
401 if( HasArea() )
403 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
404 // detect system color, set color identifier (TODO: detect automatic series area)
405 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
407 // store color index from automatic format data
408 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
409 // set automatic mode
410 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
412 else
414 // user defined color - register color in palette
415 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
417 // background color (default system color for solid fills)
418 if( bSolid )
419 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
420 else
421 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
423 else
425 // no area - set default system colors
426 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
427 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
429 return bComplexFill;
432 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
434 switch( eDefFrameType )
436 case EXC_CHFRAMETYPE_AUTO:
437 SetAuto( true );
438 break;
439 case EXC_CHFRAMETYPE_INVISIBLE:
440 SetAuto( false );
441 maData.mnPattern = EXC_PATT_NONE;
442 break;
443 default:
444 DBG_ERRORFILE( "XclExpChAreaFormat::SetDefault - unknown frame type" );
448 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
450 return
451 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
452 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
455 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
457 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
458 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
460 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
461 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
465 // ----------------------------------------------------------------------------
467 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
468 XclExpChGroupBase( EXC_ID_CHESCHERFORMAT ),
469 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
470 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
472 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
473 (void)rRoot;
476 void XclExpChEscherFormat::Convert( const XclExpChRoot& rRoot,
477 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
479 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
480 rRoot.ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
481 // register colors in palette
482 mnColor1Id = RegisterColor( rRoot, ESCHER_Prop_fillColor );
483 mnColor2Id = RegisterColor( rRoot, ESCHER_Prop_fillBackColor );
486 bool XclExpChEscherFormat::IsValid() const
488 return maData.mxEscherSet.is();
491 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
493 if( maData.mxEscherSet.is() )
495 // replace RGB colors with palette indexes in the Escher container
496 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
497 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
498 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
500 // save the record group
501 XclExpChGroupBase::Save( rStrm );
505 bool XclExpChEscherFormat::HasSubRecords() const
507 // no subrecords for gradients
508 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
511 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
513 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
514 rStrm << maPicFmt.mnBmpMode << maPicFmt.mnFormat << maPicFmt.mnFlags << maPicFmt.mfScale;
515 rStrm.EndRecord();
518 sal_uInt32 XclExpChEscherFormat::RegisterColor( const XclExpChRoot& rRoot, sal_uInt16 nPropId )
520 sal_uInt32 nBGRValue;
521 if( maData.mxEscherSet.is() && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
523 // swap red and blue
524 Color aColor( RGB_COLORDATA(
525 COLORDATA_BLUE( nBGRValue ),
526 COLORDATA_GREEN( nBGRValue ),
527 COLORDATA_RED( nBGRValue ) ) );
528 return rRoot.GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
530 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
533 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
535 DBG_ASSERT( maData.mxEscherSet.is(), "XclExpChEscherFormat::WriteBody - missing property container" );
536 // write Escher property container via temporary memory stream
537 SvMemoryStream aMemStrm;
538 maData.mxEscherSet->Commit( aMemStrm );
539 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
540 rStrm.CopyFromStream( aMemStrm );
543 // ----------------------------------------------------------------------------
545 XclExpChFrameBase::XclExpChFrameBase()
549 XclExpChFrameBase::~XclExpChFrameBase()
553 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
554 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
556 // line format
557 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
558 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
559 // area format (only for frame objects)
560 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
562 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
563 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
564 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
566 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
567 mxEscherFmt->Convert( rRoot, rPropSet, eObjType );
568 if( mxEscherFmt->IsValid() )
569 mxAreaFmt->SetAuto( false );
570 else
571 mxEscherFmt.reset();
576 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
577 XclChFrameType eDefFrameType, bool bIsFrame )
579 // line format
580 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
581 mxLineFmt->SetDefault( eDefFrameType );
582 // area format (only for frame objects)
583 if( bIsFrame )
585 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
586 mxAreaFmt->SetDefault( eDefFrameType );
587 mxEscherFmt.reset();
591 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
593 return
594 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
595 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
598 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
600 lclSaveRecord( rStrm, mxLineFmt );
601 lclSaveRecord( rStrm, mxAreaFmt );
602 lclSaveRecord( rStrm, mxEscherFmt );
605 // ----------------------------------------------------------------------------
607 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
608 XclExpChGroupBase( EXC_ID_CHFRAME, 4 ),
609 XclExpChRoot( rRoot ),
610 meObjType( eObjType )
614 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
616 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
619 bool XclExpChFrame::IsDefault() const
621 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
624 bool XclExpChFrame::IsDeleteable() const
626 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
629 void XclExpChFrame::Save( XclExpStream& rStrm )
631 switch( meObjType )
633 // wall/floor frame without CHFRAME header record
634 case EXC_CHOBJTYPE_WALL3D:
635 case EXC_CHOBJTYPE_FLOOR3D:
636 WriteFrameRecords( rStrm );
637 break;
638 default:
639 XclExpChGroupBase::Save( rStrm );
643 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
645 WriteFrameRecords( rStrm );
648 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
650 rStrm << maData.mnFormat << maData.mnFlags;
653 namespace {
655 /** Creates a CHFRAME record from the passed property set. */
656 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
657 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
659 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
660 xFrame->Convert( rPropSet );
661 if( xFrame->IsDeleteable() )
662 xFrame.reset();
663 return xFrame;
666 void lclAddDoubleRefData(ScTokenArray& rArray, const ::formula::FormulaToken& rToken,
667 SCsTAB nTab1, SCsTAB nTab2, SCsCOL nCol1, SCsCOL nCol2, SCsROW nRow1, SCsROW nRow2)
669 using namespace ::formula;
671 StackVar eType = rToken.GetType();
672 bool bExternal = (eType == svExternalDoubleRef);
673 DBG_ASSERT(eType == svDoubleRef || eType == svExternalDoubleRef, "not a double ref token!");
675 ScComplexRefData aData;
677 aData.InitFlags();
678 aData.Ref1.SetFlag3D(true);
679 aData.Ref1.SetTabRel(false);
680 aData.Ref1.SetColRel(false);
681 aData.Ref1.SetRowRel(false);
682 aData.Ref2.SetFlag3D(false);
683 aData.Ref2.SetTabRel(false);
684 aData.Ref2.SetColRel(false);
685 aData.Ref2.SetRowRel(false);
687 aData.Ref1.nTab = nTab1;
688 aData.Ref1.nCol = nCol1;
689 aData.Ref1.nRow = nRow1;
690 aData.Ref2.nTab = nTab2;
691 aData.Ref2.nCol = nCol2;
692 aData.Ref2.nRow = nRow2;
694 if (bExternal)
695 rArray.AddExternalDoubleReference(rToken.GetIndex(), rToken.GetString(), aData);
696 else
697 rArray.AddDoubleReference(aData);
700 } // namespace
702 // Source links ===============================================================
704 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
705 XclExpRecord( EXC_ID_CHSOURCELINK ),
706 XclExpChRoot( rRoot )
708 maData.mnDestType = nDestType;
709 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
712 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
714 using namespace ::formula;
716 mxLinkFmla.reset();
717 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
718 sal_uInt16 nValueCount = nDefCount;
720 if (!xDataSeq.is())
721 return nValueCount;
723 // Compile the range representation string into token array. Note that the
724 // source range text depends on the current grammar.
725 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
726 ScRangeList aScRanges;
727 ScCompiler aComp(GetDocPtr(), ScAddress());
728 aComp.SetGrammar(GetDocPtr()->GetGrammar());
729 ScTokenArray* pArray = aComp.CompileString(aRangeRepr);
730 if (!pArray)
731 return nValueCount;
733 ScTokenArray aArray;
734 pArray->Reset();
735 bool bFirst = true;
736 for (const FormulaToken* p = pArray->First(); p; p = pArray->Next())
738 StackVar eType = p->GetType();
739 if (eType == svSingleRef || eType == svExternalSingleRef)
741 // For a single ref token, just add it to the new token array as is.
742 if (bFirst)
743 bFirst = false;
744 else
745 aArray.AddOpCode(ocUnion);
747 aArray.AddToken(*p);
750 if (eType != svDoubleRef && eType != svExternalDoubleRef)
751 continue;
753 // split 3-dimensional ranges into single sheets.
754 const ScComplexRefData& r = static_cast<const ScToken*>(p)->GetDoubleRef();
755 const ScSingleRefData& s = r.Ref1;
756 const ScSingleRefData& e = r.Ref2;
757 for (SCsTAB nTab = s.nTab; nTab <= e.nTab; ++nTab)
759 if (bSplitToColumns && (s.nRow != e.nRow))
761 // split 2-dimensional ranges into single columns.
762 for (SCsCOL nCol = s.nCol; nCol <= e.nCol; ++nCol)
764 if (bFirst)
765 bFirst = false;
766 else
767 aArray.AddOpCode(ocUnion);
769 lclAddDoubleRefData(aArray, *p, nTab, nTab, nCol, nCol, s.nRow, e.nRow);
772 else
774 if (bFirst)
775 bFirst = false;
776 else
777 aArray.AddOpCode(ocUnion);
779 lclAddDoubleRefData(aArray, *p, nTab, nTab, s.nCol, e.nCol, s.nRow, e.nRow);
784 const ScAddress aBaseCell(0,0,0);
785 mxLinkFmla = GetFormulaCompiler().CreateFormula(EXC_FMLATYPE_CHART, aArray, &aBaseCell);
786 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
787 nValueCount = ulimit_cast< sal_uInt16 >( aScRanges.GetCellCount(), EXC_CHDATAFORMAT_MAXPOINTCOUNT );
788 return nValueCount;
791 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
793 mxString.reset();
794 sal_uInt16 nFontIdx = EXC_FONT_APP;
795 if( rStringSeq.hasElements() )
797 mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
798 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
799 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
801 // convert all formatted string entries from the sequence
802 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
803 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
804 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
806 if( pIt->is() )
808 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
809 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
810 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
811 OUString aText = (*pIt)->getString();
812 ScfPropertySet aStrProp( *pIt );
814 // #i63255# get script type for leading weak characters
815 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
817 // process all script portions
818 sal_Int32 nPortionPos = 0;
819 sal_Int32 nTextLen = aText.getLength();
820 while( nPortionPos < nTextLen )
822 // get script type and end position of next script portion
823 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
824 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
826 // reuse previous script for following weak portions
827 if( nScript == ApiScriptType::WEAK )
828 nScript = nLastScript;
830 // Excel start position of this portion
831 sal_uInt16 nXclPortionStart = mxString->Len();
832 // add portion text to Excel string
833 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
834 if( nXclPortionStart < mxString->Len() )
836 // find font index variable dependent on script type
837 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
838 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
840 // insert font into buffer (if not yet done)
841 if( rnFontIdx == EXC_FONT_NOTFOUND )
842 rnFontIdx = ConvertFont( aStrProp, nScript );
844 // insert font index into format run vector
845 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
848 // go to next script portion
849 nLastScript = nScript;
850 nPortionPos = nPortionEnd;
854 if( !mxString->IsEmpty() )
856 // get leading font index
857 const XclFormatRunVec& rFormats = mxString->GetFormats();
858 DBG_ASSERT( !rFormats.empty() && (rFormats.front().mnChar == 0),
859 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
860 // remove leading format run, if entire string is equally formatted
861 if( rFormats.size() == 1 )
862 nFontIdx = mxString->RemoveLeadingFont();
863 else if( !rFormats.empty() )
864 nFontIdx = rFormats.front().mnFontIdx;
865 // add trailing format run, if string is rich-formatted
866 if( mxString->IsRich() )
867 mxString->AppendTrailingFormat( EXC_FONT_APP );
870 return nFontIdx;
873 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
875 sal_Int32 nApiNumFmt = 0;
876 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
878 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
879 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
883 void XclExpChSourceLink::AppendString( const String& rStr )
885 if (!mxString.is())
886 return;
887 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
890 void XclExpChSourceLink::Save( XclExpStream& rStrm )
892 // CHFORMATRUNS record
893 if( mxString.is() && mxString->IsRich() )
895 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
896 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
897 mxString->WriteFormats( rStrm, true );
898 rStrm.EndRecord();
900 // CHSOURCELINK record
901 XclExpRecord::Save( rStrm );
902 // CHSTRING record
903 if( mxString.is() && !mxString->IsEmpty() )
905 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
906 rStrm << sal_uInt16( 0 ) << *mxString;
907 rStrm.EndRecord();
911 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
913 rStrm << maData.mnDestType
914 << maData.mnLinkType
915 << maData.mnFlags
916 << maData.mnNumFmtIdx
917 << mxLinkFmla;
920 // Text =======================================================================
922 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
923 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
927 // ----------------------------------------------------------------------------
929 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
930 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
932 maData.mnTarget = nLinkTarget;
933 maData.maPointPos = rPointPos;
936 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
938 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
941 // ----------------------------------------------------------------------------
943 XclExpChFontBase::~XclExpChFontBase()
947 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
949 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
951 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
952 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
956 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
958 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
961 void XclExpChFontBase::ConvertRotationBase(
962 const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
964 sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet );
965 SetRotation( nRotation );
968 // ----------------------------------------------------------------------------
970 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
971 XclExpChGroupBase( EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
972 XclExpChRoot( rRoot ),
973 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
977 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
979 mxFont = xFont;
980 maData.maTextColor = rColor;
981 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
982 mnTextColorId = nColorId;
985 void XclExpChText::SetRotation( sal_uInt16 nRotation )
987 maData.mnRotation = nRotation;
988 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
991 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const String* pSubTitle )
993 mxSrcLink.reset();
994 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
996 if( xTitle.is() )
998 // title frame formatting
999 ScfPropertySet aTitleProp( xTitle );
1000 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1002 // string sequence
1003 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1004 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1005 if (pSubTitle)
1007 // append subtitle as the 2nd line of the title.
1008 String aSubTitle = String::CreateFromAscii("\n");
1009 aSubTitle.Append(*pSubTitle);
1010 mxSrcLink->AppendString(aSubTitle);
1013 ConvertFontBase( GetChRoot(), nFontIdx );
1015 // rotation
1016 ConvertRotationBase( GetChRoot(), aTitleProp );
1018 else
1020 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1024 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1026 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1027 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1028 ConvertFontBase( GetChRoot(), rPropSet );
1031 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1032 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1034 namespace cssc = ::com::sun::star::chart2;
1035 cssc::DataPointLabel aPointLabel;
1036 if( rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1038 //! TODO: make value and percent independent
1039 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1040 bool bShowValue = aPointLabel.ShowNumber;
1041 bool bShowPercent = bIsPie && !bShowValue && aPointLabel.ShowNumberInPercent;
1042 bool bShowCateg = !bShowValue && aPointLabel.ShowCategoryName;
1043 bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1044 bool bShowSymbol = bShowAny && aPointLabel.ShowLegendSymbol;
1046 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1047 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1048 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1049 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1050 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1051 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowSymbol );
1052 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1054 if( bShowAny )
1056 // font settings
1057 ConvertFontBase( GetChRoot(), rPropSet );
1058 // label placement
1059 sal_Int32 nPlacement = 0;
1060 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1062 using namespace ::com::sun::star::chart::DataLabelPlacement;
1063 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1065 maData.mnPlacement = EXC_CHTEXT_POS_DEFAULT;
1067 else switch( nPlacement )
1069 case AVOID_OVERLAP: maData.mnPlacement = EXC_CHTEXT_POS_AUTO; break;
1070 case CENTER: maData.mnPlacement = EXC_CHTEXT_POS_CENTER; break;
1071 case TOP: maData.mnPlacement = EXC_CHTEXT_POS_ABOVE; break;
1072 case TOP_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1073 case LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1074 case BOTTOM_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1075 case BOTTOM: maData.mnPlacement = EXC_CHTEXT_POS_BELOW; break;
1076 case BOTTOM_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1077 case RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1078 case TOP_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1079 case INSIDE: maData.mnPlacement = EXC_CHTEXT_POS_INSIDE; break;
1080 case OUTSIDE: maData.mnPlacement = EXC_CHTEXT_POS_OUTSIDE; break;
1081 case NEAR_ORIGIN: maData.mnPlacement = EXC_CHTEXT_POS_AXIS; break;
1082 default: DBG_ERRORFILE( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1085 // source link (contains number format)
1086 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1087 if( bShowValue || bShowPercent )
1088 // percentage format wins over value format
1089 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1090 // object link
1091 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1092 // return true to indicate existing label
1093 return true;
1096 return false;
1099 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1101 // required flags
1102 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1103 if( GetBiff() == EXC_BIFF8 )
1104 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1105 // frame formatting
1106 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1107 // font settings
1108 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1109 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1110 ConvertFontBase( GetChRoot(), rPropSet );
1111 // source link (contains number format)
1112 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1113 mxSrcLink->ConvertNumFmt( rPropSet, false );
1114 // object link
1115 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1118 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1120 sal_uInt16 nFlags = 0;
1121 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1122 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1123 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1124 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1125 return nFlags;
1128 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1130 // CHFONT record
1131 lclSaveRecord( rStrm, mxFont );
1132 // CHSOURCELINK group
1133 lclSaveRecord( rStrm, mxSrcLink );
1134 // CHFRAME group
1135 lclSaveRecord( rStrm, mxFrame );
1136 // CHOBJECTLINK record
1137 lclSaveRecord( rStrm, mxObjLink );
1140 void XclExpChText::WriteBody( XclExpStream& rStrm )
1142 rStrm << maData.mnHAlign
1143 << maData.mnVAlign
1144 << maData.mnBackMode
1145 << maData.maTextColor
1146 << maData.maRect
1147 << maData.mnFlags;
1149 if( GetBiff() == EXC_BIFF8 )
1151 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1152 << maData.mnPlacement
1153 << maData.mnRotation;
1157 // ----------------------------------------------------------------------------
1159 namespace {
1161 /** Creates and returns an Excel text object from the passed title. */
1162 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
1163 const String* pSubTitle = NULL )
1165 Reference< XTitle > xTitle;
1166 if( xTitled.is() )
1167 xTitle = xTitled->getTitleObject();
1169 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1170 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1171 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1172 will be interpreted as auto-generated title showing the series title in
1173 charts that contain exactly one data series. */
1174 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1175 xText.reset();
1177 return xText;
1182 // Data series ================================================================
1184 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1185 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1186 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1187 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1191 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1192 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1194 rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1195 /* Set marker line/fill color to series line color.
1196 TODO: remove this if OOChart supports own colors in markers. */
1197 Color aLineColor;
1198 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1199 maData.maLineColor = maData.maFillColor = aLineColor;
1200 // register colors in palette
1201 RegisterColors( rRoot );
1204 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1205 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1207 // clear the automatic flag
1208 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1209 // symbol type and color
1210 if( bCloseSymbol )
1212 // set symbol type for the 'close' data series
1213 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1214 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1215 // set symbol line/fill color to series line color
1216 Color aLineColor;
1217 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1219 maData.maLineColor = maData.maFillColor = aLineColor;
1220 RegisterColors( rRoot );
1223 else
1225 // set invisible symbol
1226 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1230 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1232 if( HasMarker() )
1234 if( HasLineColor() )
1235 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1236 if( HasFillColor() )
1237 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1241 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1243 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1244 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1246 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1247 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1251 // ----------------------------------------------------------------------------
1253 XclExpChPieFormat::XclExpChPieFormat() :
1254 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1258 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1260 double fApiDist(0.0);
1261 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1262 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1265 // ----------------------------------------------------------------------------
1267 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1268 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1272 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1274 sal_Int32 nApiType(0);
1275 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1277 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1278 switch( nApiType )
1280 case CUBOID:
1281 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1282 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1283 break;
1284 case PYRAMID:
1285 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1286 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1287 break;
1288 case CYLINDER:
1289 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1290 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1291 break;
1292 case CONE:
1293 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1294 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1295 break;
1296 default:
1297 DBG_ERRORFILE( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1302 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1304 rStrm << maData.mnBase << maData.mnTop;
1307 // ----------------------------------------------------------------------------
1309 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1310 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1314 // ----------------------------------------------------------------------------
1316 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1317 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1318 XclExpChGroupBase( EXC_ID_CHDATAFORMAT, 8 ),
1319 XclExpChRoot( rRoot )
1321 maData.maPointPos = rPointPos;
1322 maData.mnFormatIdx = nFormatIdx;
1325 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1327 // line and area formatting
1328 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1330 // data point symbols
1331 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1332 if( !bIsFrame )
1334 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1335 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1338 // pie segments
1339 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1341 mxPieFmt.reset( new XclExpChPieFormat );
1342 mxPieFmt->Convert( rPropSet );
1345 // 3D bars (only allowed for entire series in BIFF8)
1346 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1348 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1349 mx3dDataFmt->Convert( rPropSet );
1352 // spline
1353 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1354 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1356 // data point labels
1357 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1358 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1360 // CHTEXT groups for data labels are stored in global CHCHART group
1361 GetChartData().SetDataLabel( xLabel );
1362 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1366 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1368 // set line format to invisible
1369 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1370 // set symbols to invisible or to 'close' series symbol
1371 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1372 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1375 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1377 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1380 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1382 lclSaveRecord( rStrm, mx3dDataFmt );
1383 WriteFrameRecords( rStrm );
1384 lclSaveRecord( rStrm, mxPieFmt );
1385 lclSaveRecord( rStrm, mxMarkerFmt );
1386 lclSaveRecord( rStrm, mxSeriesFmt );
1387 lclSaveRecord( rStrm, mxAttLabel );
1390 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1392 rStrm << maData.maPointPos.mnPointIdx
1393 << maData.maPointPos.mnSeriesIdx
1394 << maData.mnFormatIdx
1395 << maData.mnFlags;
1398 // ----------------------------------------------------------------------------
1400 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1401 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1402 XclExpChRoot( rRoot )
1406 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1408 if( !xRegCurve.is() )
1409 return false;
1411 // trend line type
1412 ScfPropertySet aCurveProp( xRegCurve );
1413 OUString aService = aCurveProp.GetServiceName();
1414 if( aService == SERVICE_CHART2_LINEARREGCURVE )
1416 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1417 maData.mnOrder = 1;
1419 else if( aService == SERVICE_CHART2_EXPREGCURVE )
1420 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1421 else if( aService == SERVICE_CHART2_LOGREGCURVE )
1422 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1423 else if( aService == SERVICE_CHART2_POTREGCURVE )
1424 maData.mnLineType = EXC_CHSERTREND_POWER;
1425 else
1426 return false;
1428 // line formatting
1429 XclChDataPointPos aPointPos( nSeriesIdx );
1430 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1431 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1433 // #i83100# show equation and correlation coefficient
1434 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1435 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1436 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1438 // #i83100# formatting of the equation text box
1439 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1441 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1442 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1445 // missing features
1446 // #i20819# polynomial trend lines
1447 // #i66819# moving average trend lines
1448 // #i5085# manual trend line size
1449 // #i34093# manual crossing point
1450 return true;
1453 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1455 rStrm << maData.mnLineType
1456 << maData.mnOrder
1457 << maData.mfIntercept
1458 << maData.mnShowEquation
1459 << maData.mnShowRSquared
1460 << maData.mfForecastFor
1461 << maData.mfForecastBack;
1464 // ----------------------------------------------------------------------------
1466 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1467 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1468 XclExpChRoot( rRoot )
1470 maData.mnBarType = nBarType;
1473 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1475 sal_Int32 nBarStyle = 0;
1476 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1477 if( bOk )
1479 namespace cssc = ::com::sun::star::chart;
1480 switch( nBarStyle )
1482 case cssc::ErrorBarStyle::ABSOLUTE:
1483 maData.mnSourceType = EXC_CHSERERR_FIXED;
1484 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1485 break;
1486 case cssc::ErrorBarStyle::RELATIVE:
1487 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1488 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1489 break;
1490 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1491 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1492 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1493 break;
1494 case cssc::ErrorBarStyle::STANDARD_ERROR:
1495 maData.mnSourceType = EXC_CHSERERR_STDERR;
1496 break;
1497 case cssc::ErrorBarStyle::FROM_DATA:
1499 bOk = false;
1500 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1501 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1502 if( xDataSource.is() )
1504 // find first sequence with current role
1505 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1506 Reference< XDataSequence > xValueSeq;
1508 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1509 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1510 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1511 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1513 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1514 ScfPropertySet aValueProp( xTmpValueSeq );
1515 OUString aCurrRole;
1516 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1517 xValueSeq = xTmpValueSeq;
1519 if( xValueSeq.is() )
1521 // #i86465# pass value count back to series
1522 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1523 bOk = maData.mnValueCount > 0;
1527 break;
1528 default:
1529 bOk = false;
1532 return bOk;
1535 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1537 rStrm << maData.mnBarType
1538 << maData.mnSourceType
1539 << maData.mnLineEnd
1540 << sal_uInt8( 1 ) // must be 1 to make line visible
1541 << maData.mfValue
1542 << maData.mnValueCount;
1545 // ----------------------------------------------------------------------------
1547 namespace {
1549 /** Returns the property set of the specified data point. */
1550 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1552 ScfPropertySet aPropSet;
1555 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1557 catch( Exception& )
1559 DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1561 return aPropSet;
1564 } // namespace
1566 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1567 XclExpChGroupBase( EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1568 XclExpChRoot( rRoot ),
1569 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1570 mnSeriesIdx( nSeriesIdx ),
1571 mnParentIdx( EXC_CHSERIES_INVALID )
1573 // CHSOURCELINK records are always required, even if unused
1574 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1575 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1576 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1577 if( GetBiff() == EXC_BIFF8 )
1578 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1581 bool XclExpChSeries::ConvertDataSeries(
1582 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1583 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1585 bool bOk = false;
1586 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1587 if( xDataSource.is() )
1589 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq;
1591 // find first sequence with role 'values-y'
1592 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1593 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1594 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1595 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1597 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1598 ScfPropertySet aValueProp( xTmpValueSeq );
1599 OUString aRole;
1600 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1602 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1604 xYValueSeq = xTmpValueSeq;
1605 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1607 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1609 xXValueSeq = xTmpValueSeq;
1614 bOk = xYValueSeq.is();
1615 if( bOk )
1617 // chart type group index
1618 mnGroupIdx = nGroupIdx;
1620 // convert source links
1621 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1622 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1624 // X values of XY charts
1625 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1627 // series formatting
1628 XclChDataPointPos aPointPos( mnSeriesIdx );
1629 ScfPropertySet aSeriesProp( xDataSeries );
1630 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1631 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1633 // trend lines
1634 CreateTrendLines( xDataSeries );
1636 // error bars
1637 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1638 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1640 if( maData.mnValueCount > 0 )
1642 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1644 /* #i91063# Create missing fill properties in pie/doughnut charts.
1645 If freshly created (never saved to ODF), these charts show
1646 varying point colors but do not return these points via API. */
1647 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1649 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1650 if( xColorScheme.is() )
1652 const OUString aFillStyleName = CREATE_OUSTRING( "FillStyle" );
1653 const OUString aColorName = CREATE_OUSTRING( "Color" );
1654 namespace csscd = ::com::sun::star::drawing;
1655 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1657 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1658 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1659 // test that the point fill style is solid, but no color is set
1660 csscd::FillStyle eFillStyle = csscd::FillStyle_NONE;
1661 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1662 (eFillStyle == csscd::FillStyle_SOLID) &&
1663 !aPointProp.HasProperty( aColorName ) )
1665 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1671 // data point formatting
1672 Sequence< sal_Int32 > aPointIndexes;
1673 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1675 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1676 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1677 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1679 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1680 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1681 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1682 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1683 maPointFmts.AppendRecord( xPointFmt );
1689 return bOk;
1692 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1693 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1695 bool bOk = false;
1696 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1697 if( xDataSource.is() )
1699 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1701 // find first sequence with passed role
1702 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1703 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1704 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1705 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1707 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1708 ScfPropertySet aValueProp( xTmpValueSeq );
1709 OUString aRole;
1710 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
1712 xYValueSeq = xTmpValueSeq;
1713 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1717 bOk = xYValueSeq.is();
1718 if( bOk )
1720 // chart type group index
1721 mnGroupIdx = nGroupIdx;
1722 // convert source links
1723 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1724 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1725 // series formatting
1726 ScfPropertySet aSeriesProp( xDataSeries );
1727 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
1728 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
1731 return bOk;
1734 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
1736 InitFromParent( rParent );
1737 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
1738 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
1739 if( bOk )
1741 mxSeriesFmt = mxTrendLine->GetDataFormat();
1742 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
1744 return bOk;
1747 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
1749 InitFromParent( rParent );
1750 // error bar settings
1751 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
1752 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
1753 if( bOk )
1755 // error bar formatting
1756 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
1757 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
1759 return bOk;
1762 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
1764 if( xCategSeq.is() )
1765 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
1768 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
1770 lclSaveRecord( rStrm, mxTitleLink );
1771 lclSaveRecord( rStrm, mxValueLink );
1772 lclSaveRecord( rStrm, mxCategLink );
1773 lclSaveRecord( rStrm, mxBubbleLink );
1774 lclSaveRecord( rStrm, mxSeriesFmt );
1775 maPointFmts.Save( rStrm );
1776 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
1777 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
1778 if( mnParentIdx != EXC_CHSERIES_INVALID )
1779 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
1780 lclSaveRecord( rStrm, mxTrendLine );
1781 lclSaveRecord( rStrm, mxErrorBar );
1784 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
1786 // index to parent series is stored 1-based
1787 mnParentIdx = rParent.mnSeriesIdx + 1;
1788 /* #i86465# MSO2007 SP1 expects correct point counts in child series
1789 (there was no problem in Excel2003 or Excel2007 without SP1...) */
1790 maData.mnCategCount = rParent.maData.mnCategCount;
1791 maData.mnValueCount = rParent.maData.mnValueCount;
1794 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
1796 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
1797 if( xRegCurveCont.is() )
1799 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
1800 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
1801 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
1802 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
1804 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1805 if( xSeries.is() && !xSeries->ConvertTrendLine( *this, *pIt ) )
1806 GetChartData().RemoveLastSeries();
1811 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
1812 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
1814 Reference< XPropertySet > xErrorBar;
1815 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
1817 ScfPropertySet aErrorProp( xErrorBar );
1818 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
1819 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
1823 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
1824 const OUString& rShowPropName, sal_uInt8 nBarId )
1826 if( rPropSet.GetBoolProperty( rShowPropName ) )
1828 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1829 if( xSeries.is() && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
1830 GetChartData().RemoveLastSeries();
1834 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
1836 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
1837 if( GetBiff() == EXC_BIFF8 )
1838 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
1841 // Chart type groups ==========================================================
1843 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
1844 XclExpRecord( EXC_ID_CHUNKNOWN ),
1845 XclExpChRoot( rRoot ),
1846 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
1850 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
1851 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
1853 if( xChartType.is() )
1855 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
1856 // special handling for some chart types
1857 switch( maTypeInfo.meTypeCateg )
1859 case EXC_CHTYPECATEG_BAR:
1861 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
1862 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
1863 ScfPropertySet aTypeProp( xChartType );
1864 Sequence< sal_Int32 > aInt32Seq;
1865 maData.mnOverlap = 0;
1866 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
1867 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
1868 maData.mnGap = 150;
1869 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
1870 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
1872 break;
1873 case EXC_CHTYPECATEG_RADAR:
1874 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
1875 break;
1876 case EXC_CHTYPECATEG_PIE:
1878 ScfPropertySet aTypeProp( xChartType );
1879 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
1880 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
1881 maData.mnPieHole = bDonut ? 50 : 0;
1882 // #i85166# starting angle of first pie slice
1883 ScfPropertySet aDiaProp( xDiagram );
1884 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
1886 break;
1887 case EXC_CHTYPECATEG_SCATTER:
1888 if( GetBiff() == EXC_BIFF8 )
1889 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
1890 break;
1891 default:;
1893 SetRecId( maTypeInfo.mnRecId );
1897 void XclExpChType::SetStacked( bool bPercent )
1899 switch( maTypeInfo.meTypeCateg )
1901 case EXC_CHTYPECATEG_LINE:
1902 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
1903 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
1904 break;
1905 case EXC_CHTYPECATEG_BAR:
1906 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
1907 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
1908 maData.mnOverlap = -100;
1909 break;
1910 default:;
1914 void XclExpChType::WriteBody( XclExpStream& rStrm )
1916 switch( GetRecId() )
1918 case EXC_ID_CHBAR:
1919 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
1920 break;
1922 case EXC_ID_CHLINE:
1923 case EXC_ID_CHAREA:
1924 case EXC_ID_CHRADARLINE:
1925 case EXC_ID_CHRADARAREA:
1926 rStrm << maData.mnFlags;
1927 break;
1929 case EXC_ID_CHPIE:
1930 rStrm << maData.mnRotation << maData.mnPieHole;
1931 if( GetBiff() == EXC_BIFF8 )
1932 rStrm << maData.mnFlags;
1933 break;
1935 case EXC_ID_CHSCATTER:
1936 if( GetBiff() == EXC_BIFF8 )
1937 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
1938 break;
1940 default:
1941 DBG_ERRORFILE( "XclExpChType::WriteBody - unknown chart type" );
1945 // ----------------------------------------------------------------------------
1947 XclExpChChart3d::XclExpChChart3d() :
1948 XclExpRecord( EXC_ID_CHCHART3D, 14 )
1952 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
1954 sal_Int32 nRotationY = 0;
1955 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
1956 sal_Int32 nRotationX = 0;
1957 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
1958 sal_Int32 nPerspective = 15;
1959 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
1961 if( b3dWallChart )
1963 // Y rotation (Excel [0..359], Chart2 [-179,180])
1964 if( nRotationY < 0 ) nRotationY += 360;
1965 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
1966 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
1967 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
1968 // perspective (Excel and Chart2 [0,100])
1969 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
1970 // flags
1971 maData.mnFlags = 0;
1972 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
1973 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
1974 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
1976 else
1978 // Y rotation not used in pie charts, but 'first pie slice angle'
1979 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
1980 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
1981 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
1982 // perspective (Excel and Chart2 [0,100])
1983 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
1984 // flags
1985 maData.mnFlags = 0;
1989 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
1991 rStrm << maData.mnRotation
1992 << maData.mnElevation
1993 << maData.mnEyeDist
1994 << maData.mnRelHeight
1995 << maData.mnRelDepth
1996 << maData.mnDepthGap
1997 << maData.mnFlags;
2000 // ----------------------------------------------------------------------------
2002 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2003 XclExpChGroupBase( EXC_ID_CHLEGEND, 20 ),
2004 XclExpChRoot( rRoot )
2008 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2010 // frame properties
2011 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2012 // text properties
2013 mxText.reset( new XclExpChText( GetChRoot() ) );
2014 mxText->ConvertLegend( rPropSet );
2015 // special legend properties
2016 GetChartPropSetHelper().ReadLegendProperties( maData, rPropSet );
2019 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2021 lclSaveRecord( rStrm, mxText );
2022 lclSaveRecord( rStrm, mxFrame );
2025 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2027 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2030 // ----------------------------------------------------------------------------
2032 XclExpChDropBar::XclExpChDropBar( XclChObjectType eObjType ) :
2033 XclExpChGroupBase( EXC_ID_CHDROPBAR, 2 ),
2034 meObjType( eObjType ),
2035 mnBarDist( 100 )
2039 void XclExpChDropBar::Convert( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
2041 if( rPropSet.Is() )
2042 ConvertFrameBase( rRoot, rPropSet, meObjType );
2043 else
2044 SetDefaultFrameBase( rRoot, EXC_CHFRAMETYPE_INVISIBLE, true );
2047 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2049 WriteFrameRecords( rStrm );
2052 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2054 rStrm << mnBarDist;
2057 // ----------------------------------------------------------------------------
2059 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2060 XclExpChGroupBase( EXC_ID_CHTYPEGROUP, 20 ),
2061 XclExpChRoot( rRoot ),
2062 maType( rRoot ),
2063 maTypeInfo( maType.GetTypeInfo() )
2065 maData.mnGroupIdx = nGroupIdx;
2068 void XclExpChTypeGroup::ConvertType(
2069 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2070 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2072 // chart type settings
2073 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2075 // spline - TODO: get from single series (#i66858#)
2076 ScfPropertySet aTypeProp( xChartType );
2077 ::com::sun::star::chart2::CurveStyle eCurveStyle;
2078 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2079 (eCurveStyle != ::com::sun::star::chart2::CurveStyle_LINES);
2081 // extended type info
2082 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2084 // 3d chart settings
2085 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2087 mxChart3d.reset( new XclExpChChart3d );
2088 ScfPropertySet aDiaProp( xDiagram );
2089 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2093 void XclExpChTypeGroup::ConvertSeries(
2094 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2095 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2097 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2098 if( xSeriesCont.is() )
2100 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2101 XDataSeriesVec aSeriesVec;
2103 // copy data series attached to the current axes set to the vector
2104 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2105 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2106 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2107 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2109 ScfPropertySet aSeriesProp( *pIt );
2110 sal_Int32 nSeriesAxesSetIdx(0);
2111 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2112 aSeriesVec.push_back( *pIt );
2115 // Are there any series in the current axes set?
2116 if( !aSeriesVec.empty() )
2118 // stacking direction (stacked/percent/deep 3d) from first series
2119 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2120 namespace cssc = ::com::sun::star::chart2;
2121 cssc::StackingDirection eStacking;
2122 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2123 eStacking = cssc::StackingDirection_NO_STACKING;
2125 // stacked or percent chart
2126 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc::StackingDirection_Y_STACKING) )
2128 // percent overrides simple stacking
2129 maType.SetStacked( bPercent );
2131 // connected data points (only in stacked bar charts)
2132 if( bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
2133 maChartLines[ EXC_CHCHARTLINE_CONNECT ].reset( new XclExpChLineFormat( GetChRoot() ) );
2135 else
2137 // reverse series order for some unstacked 2D chart types
2138 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2139 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2142 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2143 if( (eStacking == cssc::StackingDirection_NO_STACKING) && Is3dWallChart() )
2144 mxChart3d->SetClustered();
2146 // varied point colors
2147 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2149 // process all series
2150 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2152 // create Excel series object, stock charts need special processing
2153 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2154 CreateAllStockSeries( xChartType, *aIt );
2155 else
2156 CreateDataSeries( xDiagram, *aIt );
2162 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2164 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2165 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2168 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2170 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2172 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2173 mxLegend->Convert( rPropSet );
2177 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2179 maType.Save( rStrm );
2180 lclSaveRecord( rStrm, mxChart3d );
2181 lclSaveRecord( rStrm, mxLegend );
2182 lclSaveRecord( rStrm, mxUpBar );
2183 lclSaveRecord( rStrm, mxDownBar );
2184 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2185 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2188 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2190 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2193 void XclExpChTypeGroup::CreateDataSeries(
2194 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2196 // let chart create series object with correct series index
2197 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2198 if( xSeries.is() )
2200 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2201 maSeries.AppendRecord( xSeries );
2202 else
2203 GetChartData().RemoveLastSeries();
2207 void XclExpChTypeGroup::CreateAllStockSeries(
2208 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2210 // create existing series objects
2211 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2212 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2213 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2214 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2216 // formatting of special stock chart elements
2217 ScfPropertySet aTypeProp( xChartType );
2218 // hi-lo lines
2219 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2221 ScfPropertySet aSeriesProp( xDataSeries );
2222 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2223 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2224 maChartLines[ EXC_CHCHARTLINE_HILO ] = xLineFmt;
2226 // dropbars
2227 if( bHasOpen && bHasClose )
2229 // dropbar type is dependent on position in the file - always create both
2230 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2231 // white dropbar format
2232 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2233 ScfPropertySet aWhiteProp( xWhitePropSet );
2234 mxUpBar.reset( new XclExpChDropBar( EXC_CHOBJTYPE_WHITEDROPBAR ) );
2235 mxUpBar->Convert( GetChRoot(), aWhiteProp );
2236 // black dropbar format
2237 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2238 ScfPropertySet aBlackProp( xBlackPropSet );
2239 mxDownBar.reset( new XclExpChDropBar( EXC_CHOBJTYPE_BLACKDROPBAR ) );
2240 mxDownBar->Convert( GetChRoot(), aBlackProp );
2244 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2245 const OUString& rValueRole, bool bCloseSymbol )
2247 bool bOk = false;
2248 // let chart create series object with correct series index
2249 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2250 if( xSeries.is() )
2252 bOk = xSeries->ConvertStockSeries( xDataSeries,
2253 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2254 if( bOk )
2255 maSeries.AppendRecord( xSeries );
2256 else
2257 GetChartData().RemoveLastSeries();
2259 return bOk;
2262 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2264 rStrm << maData.maRect << maData.mnFlags << maData.mnGroupIdx;
2267 // Axes =======================================================================
2269 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2270 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2271 XclExpChRoot( rRoot )
2275 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, bool bMirrorOrient )
2277 // origin
2278 double fOrigin = 0.0;
2279 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin, false ) )
2280 maData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 32767 );
2282 // reverse order
2283 if( (rScaleData.Orientation == ::com::sun::star::chart2::AxisOrientation_REVERSE) != bMirrorOrient )
2285 ::set_flag( maData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2286 SwapAxisMaxCross();
2290 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2292 rStrm << maData.mnCross << maData.mnLabelFreq << maData.mnTickFreq << maData.mnFlags;
2295 // ----------------------------------------------------------------------------
2297 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2298 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2299 XclExpChRoot( rRoot )
2303 void XclExpChValueRange::Convert( const ScaleData& rScaleData, bool bPercent )
2305 // scaling algorithm
2306 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == SERVICE_CHART2_LOGSCALING;
2307 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2308 Reference< XScaling > xLogScaling;
2309 if( bLogScale )
2310 xLogScaling = rScaleData.Scaling;
2312 // min/max
2313 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, xLogScaling, bPercent );
2314 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2315 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, xLogScaling, bPercent );
2316 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2318 // origin
2319 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, xLogScaling, bPercent );
2320 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2322 // major increment
2323 const IncrementData& rIncrementData = rScaleData.IncrementData;
2324 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance, bPercent ) || (maData.mfMajorStep <= 0.0);
2325 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2326 // minor increment
2327 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2328 sal_Int32 nCount = 0;
2329 bool bAutoMinor = bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2330 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount, false ) || (nCount < 1);
2331 if( !bAutoMinor )
2332 maData.mfMinorStep = maData.mfMajorStep / nCount;
2333 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2335 // reverse order
2336 namespace cssc = ::com::sun::star::chart2;
2337 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc::AxisOrientation_REVERSE );
2340 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2342 rStrm << maData.mfMin
2343 << maData.mfMax
2344 << maData.mfMajorStep
2345 << maData.mfMinorStep
2346 << maData.mfCross
2347 << maData.mnFlags;
2350 // ----------------------------------------------------------------------------
2352 namespace {
2354 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2356 using namespace ::com::sun::star::chart2::TickmarkStyle;
2357 sal_uInt8 nXclTickPos = 0;
2358 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2359 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2360 return nXclTickPos;
2363 } // namespace
2365 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2366 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2367 XclExpChRoot( rRoot ),
2368 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2372 void XclExpChTick::Convert( const ScfPropertySet& rPropSet )
2374 // tick mark style
2375 sal_Int32 nApiTickmarks(0);
2376 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2377 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2378 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2379 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2382 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2384 maData.maTextColor = rColor;
2385 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2386 mnTextColorId = nColorId;
2389 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2391 maData.mnRotation = nRotation;
2392 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2393 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2396 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2398 rStrm << maData.mnMajor
2399 << maData.mnMinor
2400 << maData.mnLabelPos
2401 << maData.mnBackMode
2402 << maData.maRect
2403 << maData.maTextColor
2404 << maData.mnFlags;
2405 if( GetBiff() == EXC_BIFF8 )
2406 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2409 // ----------------------------------------------------------------------------
2411 namespace {
2413 /** Returns an API axis object from the passed coordinate system. */
2414 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2415 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2417 Reference< XAxis > xAxis;
2420 if( xCoordSystem.is() )
2421 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2423 catch( Exception& )
2426 return xAxis;
2429 } // namespace
2431 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2432 XclExpChGroupBase( EXC_ID_CHAXIS, 18 ),
2433 XclExpChRoot( rRoot ),
2434 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2436 maData.mnType = nAxisType;
2439 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2441 mxFont = xFont;
2442 if( mxTick.is() )
2443 mxTick->SetFontColor( rColor, nColorId );
2446 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2448 if( mxTick.is() )
2449 mxTick->SetRotation( nRotation );
2452 void XclExpChAxis::Convert( Reference< XAxis > xAxis, const XclChExtTypeInfo& rTypeInfo, sal_Int32 nApiAxesSetIdx,
2453 bool bPercent )
2455 ScfPropertySet aAxisProp( xAxis );
2456 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2458 // axis line format -------------------------------------------------------
2460 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2461 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2462 // #i58688# axis enabled
2463 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2465 // axis scaling and increment ---------------------------------------------
2467 if( bCategoryAxis )
2469 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2470 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2471 if( xAxis.is() )
2472 // #i71684# radar charts have reversed rotation direction
2473 mxLabelRange->Convert( xAxis->getScaleData(), (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2474 // swap max-cross flag for secondary X axis to have the secondary Y axis at right side
2475 if( (GetAxisType() == EXC_CHAXIS_X) && (nApiAxesSetIdx == EXC_CHAXESSET_SECONDARY) )
2476 mxLabelRange->SwapAxisMaxCross();
2478 else
2480 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
2481 if( xAxis.is() )
2482 mxValueRange->Convert( xAxis->getScaleData(), bPercent );
2485 // axis caption text ------------------------------------------------------
2487 // axis ticks properties
2488 mxTick.reset( new XclExpChTick( GetChRoot() ) );
2489 mxTick->Convert( aAxisProp );
2491 // existence and position of axis labels
2492 sal_uInt8 nLabelPos = EXC_CHTICK_NOLABEL;
2493 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR )
2494 /* Radar charts disable their category labels via chart type, not via
2495 axis, and axis labels are always 'near axis' in Chart2. */
2496 nLabelPos = EXC_CHTICK_NEXT;
2497 else if( aAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2498 /* #i85862# Axis labels in other chart types always have position 'low'
2499 in Chart2, but Excel expects 'near axis' at Y axes in 3D charts. */
2500 nLabelPos = (rTypeInfo.mb3dChart && (GetAxisType() == EXC_CHAXIS_Y)) ? EXC_CHTICK_NEXT : EXC_CHTICK_LOW;
2501 mxTick->SetLabelPos( nLabelPos );
2503 // axis label formatting and rotation
2504 ConvertFontBase( GetChRoot(), aAxisProp );
2505 ConvertRotationBase( GetChRoot(), aAxisProp );
2507 // axis number format
2508 sal_Int32 nApiNumFmt = 0;
2509 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
2510 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
2512 // grid -------------------------------------------------------------------
2514 if( xAxis.is() )
2516 // main grid
2517 ScfPropertySet aGridProp( xAxis->getGridProperties() );
2518 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2519 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
2520 // sub grid
2521 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
2522 if( aSubGridPropSeq.hasElements() )
2524 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
2525 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2526 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
2531 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
2533 if( xDiagram.is() ) switch( GetAxisType() )
2535 case EXC_CHAXIS_X:
2537 ScfPropertySet aWallProp( xDiagram->getWall() );
2538 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
2540 break;
2541 case EXC_CHAXIS_Y:
2543 ScfPropertySet aFloorProp( xDiagram->getFloor() );
2544 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
2546 break;
2547 default:
2548 mxWallFrame.reset();
2552 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
2554 lclSaveRecord( rStrm, mxLabelRange );
2555 lclSaveRecord( rStrm, mxValueRange );
2556 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
2557 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
2558 lclSaveRecord( rStrm, mxTick );
2559 lclSaveRecord( rStrm, mxFont );
2560 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
2561 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
2562 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
2563 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
2566 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
2568 rStrm << maData.mnType << maData.maRect;
2571 // ----------------------------------------------------------------------------
2573 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
2574 XclExpChGroupBase( EXC_ID_CHAXESSET, 18 ),
2575 XclExpChRoot( rRoot )
2577 maData.mnAxesSetId = nAxesSetId;
2580 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
2582 /* First unused chart type group index is passed to be able to continue
2583 counting of chart type groups for secondary axes set. */
2584 sal_uInt16 nGroupIdx = nFirstGroupIdx;
2585 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
2586 if( xCoordSysCont.is() )
2588 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
2589 if( aCoordSysSeq.getLength() > 0 )
2591 /* Process first coordinate system only. Import filter puts all
2592 chart types into one coordinate system. */
2593 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
2594 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2596 // 3d mode
2597 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
2599 // percent charts
2600 namespace ApiAxisType = ::com::sun::star::chart2::AxisType;
2601 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
2602 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
2604 // connector lines in bar charts
2605 ScfPropertySet aDiaProp( xDiagram );
2606 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
2608 // swapped axes sets
2609 ScfPropertySet aCoordSysProp( xCoordSystem );
2610 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
2612 // X axis for later use
2613 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
2614 // X axis labels
2615 ScfPropertySet aXAxisProp( xApiXAxis );
2616 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
2618 // process chart types
2619 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
2620 if( xChartTypeCont.is() )
2622 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
2623 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
2624 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
2625 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
2627 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
2628 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
2629 /* If new chart type group cannot be inserted into a combination
2630 chart with existing type groups, insert all series into last
2631 contained chart type group instead of creating a new group. */
2632 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
2633 if( xLastGroup.is() && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
2635 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2637 else
2639 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2640 if( xTypeGroup->IsValidGroup() )
2642 maTypeGroups.AppendRecord( xTypeGroup );
2643 ++nGroupIdx;
2649 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
2651 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
2653 // create axes according to chart type (no axes for pie and donut charts)
2654 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
2656 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, bPercent );
2657 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, bPercent );
2658 if( pGroup->Is3dDeepChart() )
2659 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, bPercent );
2662 // X axis category ranges
2663 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
2665 const ScaleData aScaleData = xApiXAxis->getScaleData();
2666 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
2667 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
2670 // legend
2671 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2673 Reference< XLegend > xLegend = xDiagram->getLegend();
2674 if( xLegend.is() )
2676 ScfPropertySet aLegendProp( xLegend );
2677 pGroup->ConvertLegend( aLegendProp );
2684 // wall/floor/diagram frame formatting
2685 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2687 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2688 if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
2690 // wall/floor formatting (3D charts)
2691 if( mxXAxis.is() )
2692 mxXAxis->ConvertWall( xDiagram );
2693 if( mxYAxis.is() )
2694 mxYAxis->ConvertWall( xDiagram );
2696 else
2698 // diagram background formatting
2699 ScfPropertySet aWallProp( xDiagram->getWall() );
2700 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
2704 // return first unused chart type group index for next axes set
2705 return nGroupIdx;
2708 bool XclExpChAxesSet::Is3dChart() const
2710 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2711 return xTypeGroup.is() && xTypeGroup->Is3dChart();
2714 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
2716 lclSaveRecord( rStrm, mxXAxis );
2717 lclSaveRecord( rStrm, mxYAxis );
2718 lclSaveRecord( rStrm, mxZAxis );
2719 lclSaveRecord( rStrm, mxXAxisTitle );
2720 lclSaveRecord( rStrm, mxYAxisTitle );
2721 lclSaveRecord( rStrm, mxZAxisTitle );
2722 if( mxPlotFrame.is() )
2724 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
2725 mxPlotFrame->Save( rStrm );
2727 maTypeGroups.Save( rStrm );
2730 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
2732 return maTypeGroups.GetFirstRecord();
2735 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
2737 return maTypeGroups.GetLastRecord();
2740 void XclExpChAxesSet::ConvertAxis(
2741 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
2742 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
2743 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
2744 bool bPercent )
2746 // create and convert axis object
2747 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
2748 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
2749 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2750 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
2751 rxChAxis->Convert( xAxis, rTypeInfo, nApiAxesSetIdx, bPercent );
2753 // create and convert axis title
2754 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
2755 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
2758 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
2760 rStrm << maData.mnAxesSetId << maData.maRect;
2763 // The chart object ===========================================================
2765 static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
2766 String& rSubTitle)
2768 Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
2769 if (!xChartDoc1.is())
2770 return;
2772 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
2773 if (!xProp.is())
2774 return;
2776 OUString aTitle;
2777 Any any = xProp->getPropertyValue( OUString::createFromAscii("String") );
2778 if (any >>= aTitle)
2779 rSubTitle = aTitle;
2782 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
2783 Reference< XChartDocument > xChartDoc, const Size& rSize ) :
2784 XclExpChGroupBase( EXC_ID_CHCHART, 16 ),
2785 XclExpChRoot( rRoot, this )
2787 Size aPtSize = OutputDevice::LogicToLogic( rSize, MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
2788 // rectangle is stored in 16.16 fixed-point format
2789 maRect.mnX = maRect.mnY = 0;
2790 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
2791 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
2793 // global chart properties (default values)
2794 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANSERIES );
2795 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISCELLS, false );
2796 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
2798 // always create both axes set objects
2799 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
2800 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
2802 if( xChartDoc.is() )
2804 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
2806 // global chart properties (only 'include hidden cells' attribute for now)
2807 ScfPropertySet aDiagramProp( xDiagram );
2808 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
2809 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISCELLS, !bIncludeHidden );
2811 // initialize API conversion (remembers xChartDoc internally)
2812 InitConversion( xChartDoc );
2814 // chart frame
2815 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
2816 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
2818 // chart title
2819 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
2820 String aSubTitle;
2821 lcl_getChartSubTitle(xChartDoc, aSubTitle);
2822 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
2823 aSubTitle.Len() ? &aSubTitle : NULL );
2825 // diagrams (axes sets)
2826 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
2827 if( !mxPrimAxesSet->Is3dChart() )
2828 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
2830 // finish API conversion
2831 FinishConversion();
2835 XclExpChSeriesRef XclExpChChart::CreateSeries()
2837 XclExpChSeriesRef xSeries;
2838 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
2839 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
2841 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
2842 maSeries.AppendRecord( xSeries );
2844 return xSeries;
2847 void XclExpChChart::RemoveLastSeries()
2849 if( !maSeries.IsEmpty() )
2850 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
2853 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
2855 if( xText.is() )
2856 maLabels.AppendRecord( xText );
2859 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
2861 // background format
2862 lclSaveRecord( rStrm, mxFrame );
2864 // data series
2865 maSeries.Save( rStrm );
2867 // CHPROPERTIES record
2868 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
2869 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
2870 rStrm.EndRecord();
2872 // axes sets (always save primary axes set)
2873 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
2874 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
2875 mxPrimAxesSet->Save( rStrm );
2876 if( mxSecnAxesSet->IsValidAxesSet() )
2877 mxSecnAxesSet->Save( rStrm );
2879 // chart title and data labels
2880 lclSaveRecord( rStrm, mxTitle );
2881 maLabels.Save( rStrm );
2884 void XclExpChChart::WriteBody( XclExpStream& rStrm )
2886 rStrm << maRect;
2889 // ----------------------------------------------------------------------------
2891 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Size& rSize ) :
2892 XclExpSubStream( EXC_BOF_CHART ),
2893 XclExpRoot( rRoot )
2895 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
2896 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
2897 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
2899 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
2900 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rSize ) );
2903 // ============================================================================