update ooo310-m15
[ooovba.git] / sc / source / filter / excel / xechart.cxx
blobcf3f218a7d4fa0fbc1df3d3489f3422caa88248c
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 "xechart.hxx"
36 #include <com/sun/star/i18n/XBreakIterator.hpp>
37 #include <com/sun/star/i18n/ScriptType.hpp>
38 #include <com/sun/star/drawing/FillStyle.hpp>
39 #include <com/sun/star/chart/XChartDocument.hpp>
40 #include <com/sun/star/chart2/XChartDocument.hpp>
41 #include <com/sun/star/chart2/XDiagram.hpp>
42 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
43 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
44 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
45 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
46 #include <com/sun/star/chart2/XTitled.hpp>
47 #include <com/sun/star/chart2/XColorScheme.hpp>
48 #include <com/sun/star/chart2/data/XDataSource.hpp>
49 #include <com/sun/star/chart2/AxisType.hpp>
50 #include <com/sun/star/chart2/CurveStyle.hpp>
51 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
52 #include <com/sun/star/chart2/DataPointLabel.hpp>
53 #include <com/sun/star/chart2/StackingDirection.hpp>
54 #include <com/sun/star/chart2/TickmarkStyle.hpp>
55 #include <com/sun/star/chart/DataLabelPlacement.hpp>
56 #include <com/sun/star/chart/ErrorBarStyle.hpp>
58 #include <vcl/outdev.hxx>
59 #include <svx/escherex.hxx>
61 #include "document.hxx"
62 #include "rangelst.hxx"
63 #include "rangeutl.hxx"
64 #include "xeformula.hxx"
65 #include "xehelper.hxx"
66 #include "xepage.hxx"
67 #include "xestyle.hxx"
68 #include "compiler.hxx"
69 #include "tokenarray.hxx"
70 #include "token.hxx"
72 using ::rtl::OUString;
73 using ::com::sun::star::uno::Any;
74 using ::com::sun::star::uno::Reference;
75 using ::com::sun::star::uno::Sequence;
76 using ::com::sun::star::uno::UNO_QUERY;
77 using ::com::sun::star::uno::Exception;
78 using ::com::sun::star::beans::XPropertySet;
79 using ::com::sun::star::i18n::XBreakIterator;
80 using ::com::sun::star::frame::XModel;
81 using ::com::sun::star::chart2::XChartDocument;
82 using ::com::sun::star::chart2::XDiagram;
83 using ::com::sun::star::chart2::XCoordinateSystemContainer;
84 using ::com::sun::star::chart2::XCoordinateSystem;
85 using ::com::sun::star::chart2::XChartTypeContainer;
86 using ::com::sun::star::chart2::XChartType;
87 using ::com::sun::star::chart2::XDataSeriesContainer;
88 using ::com::sun::star::chart2::XDataSeries;
89 using ::com::sun::star::chart2::XRegressionCurveContainer;
90 using ::com::sun::star::chart2::XRegressionCurve;
91 using ::com::sun::star::chart2::XAxis;
92 using ::com::sun::star::chart2::XScaling;
93 using ::com::sun::star::chart2::ScaleData;
94 using ::com::sun::star::chart2::IncrementData;
95 using ::com::sun::star::chart2::SubIncrement;
96 using ::com::sun::star::chart2::XLegend;
97 using ::com::sun::star::chart2::XTitled;
98 using ::com::sun::star::chart2::XTitle;
99 using ::com::sun::star::chart2::XFormattedString;
100 using ::com::sun::star::chart2::XColorScheme;
102 using ::com::sun::star::chart2::data::XDataSource;
103 using ::com::sun::star::chart2::data::XLabeledDataSequence;
104 using ::com::sun::star::chart2::data::XDataSequence;
106 // Helpers ====================================================================
108 namespace {
110 XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
112 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
115 inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
117 if( xRec.is() )
118 xRec->Save( rStrm );
121 /** Saves the passed record (group) together with a leading value record. */
122 template< typename Type >
123 void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
125 if( xRec.is() )
127 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
128 xRec->Save( rStrm );
132 template< typename Type >
133 inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny, bool bPercent )
135 if (!rAny.hasValue())
136 return true;
138 if (rAny >>= rValue)
140 if (bPercent)
141 rValue *= 100.0;
142 return false;
144 else
145 return true;
148 bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, Reference< XScaling > xScaling, bool bPercent )
150 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny, bPercent );
151 if( !bIsAuto && xScaling.is() )
152 rfValue = xScaling->doScaling( rfValue );
154 return bIsAuto;
157 } // namespace
159 // Common =====================================================================
161 /** Stores global data needed in various classes of the Chart export filter. */
162 class XclExpChRootData : public XclChRootData
164 public:
165 explicit XclExpChRootData( XclExpChChart* pChartData );
167 /** Returns a reference to the parent chart data object. */
168 inline XclExpChChart& GetChartData() const { return *mpChartData; }
170 private:
171 XclExpChChart* mpChartData; /// Pointer to the chart data object.
174 XclExpChRootData::XclExpChRootData( XclExpChChart* pChartData ) :
175 mpChartData( pChartData )
179 // ----------------------------------------------------------------------------
181 XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart* pChartData ) :
182 XclExpRoot( rRoot ),
183 mxChData( new XclExpChRootData( pChartData ) )
187 XclExpChRoot::~XclExpChRoot()
191 XclExpChChart& XclExpChRoot::GetChartData() const
193 return mxChData->GetChartData();
196 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
198 return mxChData->GetTypeInfoProvider().GetTypeInfo( eType );
201 const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
203 return mxChData->GetTypeInfoProvider().GetTypeInfoFromService( rServiceName );
206 const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
208 return mxChData->GetFormatInfoProvider().GetFormatInfo( eObjType );
211 void XclExpChRoot::InitConversion( XChartDocRef xChartDoc ) const
213 mxChData->InitConversion( xChartDoc );
216 void XclExpChRoot::FinishConversion() const
218 mxChData->FinishConversion();
221 bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
223 XclExpPalette& rPal = GetPalette();
224 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
227 void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
229 DBG_ASSERT( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
230 rColor = GetPalette().GetDefColor( nSysColorIdx );
231 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
234 void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
235 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
237 GetChartPropSetHelper().ReadLineProperties(
238 rLineFmt, mxChData->GetLineDashTable(), rPropSet, ePropMode );
241 bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
242 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
244 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
247 void XclExpChRoot::ConvertEscherFormat(
248 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
249 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
251 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
252 mxChData->GetGradientTable(), mxChData->GetHatchTable(), mxChData->GetBitmapTable(), rPropSet, ePropMode );
255 sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
257 XclFontData aFontData;
258 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
259 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
262 sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
264 sal_Int32 nApiRot = 0;
265 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
266 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
269 // ----------------------------------------------------------------------------
271 XclExpChGroupBase::XclExpChGroupBase( sal_uInt16 nRecId, sal_Size nRecSize ) :
272 XclExpRecord( nRecId, nRecSize )
276 XclExpChGroupBase::~XclExpChGroupBase()
280 void XclExpChGroupBase::Save( XclExpStream& rStrm )
282 // header record
283 XclExpRecord::Save( rStrm );
284 // group records
285 if( HasSubRecords() )
287 // CHBEGIN record
288 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
289 // embedded records
290 WriteSubRecords( rStrm );
291 // CHEND record
292 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
296 bool XclExpChGroupBase::HasSubRecords() const
298 return true;
301 // Frame formatting ===========================================================
303 XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
304 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
305 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
309 void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
311 switch( eDefFrameType )
313 case EXC_CHFRAMETYPE_AUTO:
314 SetAuto( true );
315 break;
316 case EXC_CHFRAMETYPE_INVISIBLE:
317 SetAuto( false );
318 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
319 break;
320 default:
321 DBG_ERRORFILE( "XclExpChLineFormat::SetDefault - unknown frame type" );
325 void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
326 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
328 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
329 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
330 if( HasLine() )
332 // detect system color, set color identifier (TODO: detect automatic series line)
333 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
335 // store color index from automatic format data
336 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
337 // try to set automatic mode
338 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
339 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
341 else
343 // user defined color - register in palette
344 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
347 else
349 // no line - set default system color
350 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
354 bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
356 return
357 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
358 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
361 void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
363 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
364 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
365 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
368 namespace {
370 /** Creates a CHLINEFORMAT record from the passed property set. */
371 XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
372 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
374 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
375 xLineFmt->Convert( rRoot, rPropSet, eObjType );
376 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
377 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
378 xLineFmt.reset();
379 return xLineFmt;
382 } // namespace
384 // ----------------------------------------------------------------------------
386 XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
387 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
388 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
389 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
393 bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
394 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
396 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
397 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
398 if( HasArea() )
400 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
401 // detect system color, set color identifier (TODO: detect automatic series area)
402 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
404 // store color index from automatic format data
405 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
406 // set automatic mode
407 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
409 else
411 // user defined color - register color in palette
412 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
414 // background color (default system color for solid fills)
415 if( bSolid )
416 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
417 else
418 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
420 else
422 // no area - set default system colors
423 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
424 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
426 return bComplexFill;
429 void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
431 switch( eDefFrameType )
433 case EXC_CHFRAMETYPE_AUTO:
434 SetAuto( true );
435 break;
436 case EXC_CHFRAMETYPE_INVISIBLE:
437 SetAuto( false );
438 maData.mnPattern = EXC_PATT_NONE;
439 break;
440 default:
441 DBG_ERRORFILE( "XclExpChAreaFormat::SetDefault - unknown frame type" );
445 bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
447 return
448 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
449 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
452 void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
454 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
455 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
457 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
458 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
462 // ----------------------------------------------------------------------------
464 XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
465 XclExpChGroupBase( EXC_ID_CHESCHERFORMAT ),
466 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
467 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
469 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
470 (void)rRoot;
473 void XclExpChEscherFormat::Convert( const XclExpChRoot& rRoot,
474 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
476 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
477 rRoot.ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
478 // register colors in palette
479 mnColor1Id = RegisterColor( rRoot, ESCHER_Prop_fillColor );
480 mnColor2Id = RegisterColor( rRoot, ESCHER_Prop_fillBackColor );
483 bool XclExpChEscherFormat::IsValid() const
485 return maData.mxEscherSet.is();
488 void XclExpChEscherFormat::Save( XclExpStream& rStrm )
490 if( maData.mxEscherSet.is() )
492 // replace RGB colors with palette indexes in the Escher container
493 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
494 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
495 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
497 // save the record group
498 XclExpChGroupBase::Save( rStrm );
502 bool XclExpChEscherFormat::HasSubRecords() const
504 // no subrecords for gradients
505 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
508 void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
510 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
511 rStrm << maPicFmt.mnBmpMode << maPicFmt.mnFormat << maPicFmt.mnFlags << maPicFmt.mfScale;
512 rStrm.EndRecord();
515 sal_uInt32 XclExpChEscherFormat::RegisterColor( const XclExpChRoot& rRoot, sal_uInt16 nPropId )
517 sal_uInt32 nBGRValue;
518 if( maData.mxEscherSet.is() && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
520 // swap red and blue
521 Color aColor( RGB_COLORDATA(
522 COLORDATA_BLUE( nBGRValue ),
523 COLORDATA_GREEN( nBGRValue ),
524 COLORDATA_RED( nBGRValue ) ) );
525 return rRoot.GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
527 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
530 void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
532 DBG_ASSERT( maData.mxEscherSet.is(), "XclExpChEscherFormat::WriteBody - missing property container" );
533 // write Escher property container via temporary memory stream
534 SvMemoryStream aMemStrm;
535 maData.mxEscherSet->Commit( aMemStrm );
536 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
537 rStrm.CopyFromStream( aMemStrm );
540 // ----------------------------------------------------------------------------
542 XclExpChFrameBase::XclExpChFrameBase()
546 XclExpChFrameBase::~XclExpChFrameBase()
550 void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
551 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
553 // line format
554 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
555 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
556 // area format (only for frame objects)
557 if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
559 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
560 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
561 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
563 mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
564 mxEscherFmt->Convert( rRoot, rPropSet, eObjType );
565 if( mxEscherFmt->IsValid() )
566 mxAreaFmt->SetAuto( false );
567 else
568 mxEscherFmt.reset();
573 void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
574 XclChFrameType eDefFrameType, bool bIsFrame )
576 // line format
577 mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
578 mxLineFmt->SetDefault( eDefFrameType );
579 // area format (only for frame objects)
580 if( bIsFrame )
582 mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
583 mxAreaFmt->SetDefault( eDefFrameType );
584 mxEscherFmt.reset();
588 bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
590 return
591 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
592 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
595 void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
597 lclSaveRecord( rStrm, mxLineFmt );
598 lclSaveRecord( rStrm, mxAreaFmt );
599 lclSaveRecord( rStrm, mxEscherFmt );
602 // ----------------------------------------------------------------------------
604 XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
605 XclExpChGroupBase( EXC_ID_CHFRAME, 4 ),
606 XclExpChRoot( rRoot ),
607 meObjType( eObjType )
611 void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
613 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
616 bool XclExpChFrame::IsDefault() const
618 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
621 bool XclExpChFrame::IsDeleteable() const
623 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
626 void XclExpChFrame::Save( XclExpStream& rStrm )
628 switch( meObjType )
630 // wall/floor frame without CHFRAME header record
631 case EXC_CHOBJTYPE_WALL3D:
632 case EXC_CHOBJTYPE_FLOOR3D:
633 WriteFrameRecords( rStrm );
634 break;
635 default:
636 XclExpChGroupBase::Save( rStrm );
640 void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
642 WriteFrameRecords( rStrm );
645 void XclExpChFrame::WriteBody( XclExpStream& rStrm )
647 rStrm << maData.mnFormat << maData.mnFlags;
650 namespace {
652 /** Creates a CHFRAME record from the passed property set. */
653 XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
654 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
656 XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
657 xFrame->Convert( rPropSet );
658 if( xFrame->IsDeleteable() )
659 xFrame.reset();
660 return xFrame;
663 void lclAddDoubleRefData(ScTokenArray& rArray, const ::formula::FormulaToken& rToken,
664 SCsTAB nTab1, SCsTAB nTab2, SCsCOL nCol1, SCsCOL nCol2, SCsROW nRow1, SCsROW nRow2)
666 using namespace ::formula;
668 StackVar eType = rToken.GetType();
669 bool bExternal = (eType == svExternalDoubleRef);
670 DBG_ASSERT(eType == svDoubleRef || eType == svExternalDoubleRef, "not a double ref token!");
672 ScComplexRefData aData;
674 aData.InitFlags();
675 aData.Ref1.SetFlag3D(true);
676 aData.Ref1.SetTabRel(false);
677 aData.Ref1.SetColRel(false);
678 aData.Ref1.SetRowRel(false);
679 aData.Ref2.SetFlag3D(false);
680 aData.Ref2.SetTabRel(false);
681 aData.Ref2.SetColRel(false);
682 aData.Ref2.SetRowRel(false);
684 aData.Ref1.nTab = nTab1;
685 aData.Ref1.nCol = nCol1;
686 aData.Ref1.nRow = nRow1;
687 aData.Ref2.nTab = nTab2;
688 aData.Ref2.nCol = nCol2;
689 aData.Ref2.nRow = nRow2;
691 if (bExternal)
692 rArray.AddExternalDoubleReference(rToken.GetIndex(), rToken.GetString(), aData);
693 else
694 rArray.AddDoubleReference(aData);
697 } // namespace
699 // Source links ===============================================================
701 XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
702 XclExpRecord( EXC_ID_CHSOURCELINK ),
703 XclExpChRoot( rRoot )
705 maData.mnDestType = nDestType;
706 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
709 sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
711 using namespace ::formula;
713 mxLinkFmla.reset();
714 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
715 sal_uInt16 nValueCount = nDefCount;
717 if (!xDataSeq.is())
718 return nValueCount;
720 // Compile the range representation string into token array. Note that the
721 // source range text depends on the current grammar.
722 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
723 ScRangeList aScRanges;
724 ScCompiler aComp(GetDocPtr(), ScAddress());
725 aComp.SetGrammar(GetDocPtr()->GetGrammar());
726 ScTokenArray* pArray = aComp.CompileString(aRangeRepr);
727 if (!pArray)
728 return nValueCount;
730 ScTokenArray aArray;
731 pArray->Reset();
732 bool bFirst = true;
733 for (const FormulaToken* p = pArray->First(); p; p = pArray->Next())
735 StackVar eType = p->GetType();
736 if (eType == svSingleRef || eType == svExternalSingleRef)
738 // For a single ref token, just add it to the new token array as is.
739 if (bFirst)
740 bFirst = false;
741 else
742 aArray.AddOpCode(ocUnion);
744 aArray.AddToken(*p);
747 if (eType != svDoubleRef && eType != svExternalDoubleRef)
748 continue;
750 // split 3-dimensional ranges into single sheets.
751 const ScComplexRefData& r = static_cast<const ScToken*>(p)->GetDoubleRef();
752 const ScSingleRefData& s = r.Ref1;
753 const ScSingleRefData& e = r.Ref2;
754 for (SCsTAB nTab = s.nTab; nTab <= e.nTab; ++nTab)
756 if (bSplitToColumns && (s.nRow != e.nRow))
758 // split 2-dimensional ranges into single columns.
759 for (SCsCOL nCol = s.nCol; nCol <= e.nCol; ++nCol)
761 if (bFirst)
762 bFirst = false;
763 else
764 aArray.AddOpCode(ocUnion);
766 lclAddDoubleRefData(aArray, *p, nTab, nTab, nCol, nCol, s.nRow, e.nRow);
769 else
771 if (bFirst)
772 bFirst = false;
773 else
774 aArray.AddOpCode(ocUnion);
776 lclAddDoubleRefData(aArray, *p, nTab, nTab, s.nCol, e.nCol, s.nRow, e.nRow);
781 const ScAddress aBaseCell(0,0,0);
782 mxLinkFmla = GetFormulaCompiler().CreateFormula(EXC_FMLATYPE_CHART, aArray, &aBaseCell);
783 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
784 nValueCount = ulimit_cast< sal_uInt16 >( aScRanges.GetCellCount(), EXC_CHDATAFORMAT_MAXPOINTCOUNT );
785 return nValueCount;
788 sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
790 mxString.reset();
791 sal_uInt16 nFontIdx = EXC_FONT_APP;
792 if( rStringSeq.hasElements() )
794 mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
795 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
796 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
798 // convert all formatted string entries from the sequence
799 const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
800 const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
801 for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
803 if( pIt->is() )
805 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
806 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
807 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
808 OUString aText = (*pIt)->getString();
809 ScfPropertySet aStrProp( *pIt );
811 // #i63255# get script type for leading weak characters
812 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
814 // process all script portions
815 sal_Int32 nPortionPos = 0;
816 sal_Int32 nTextLen = aText.getLength();
817 while( nPortionPos < nTextLen )
819 // get script type and end position of next script portion
820 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
821 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
823 // reuse previous script for following weak portions
824 if( nScript == ApiScriptType::WEAK )
825 nScript = nLastScript;
827 // Excel start position of this portion
828 sal_uInt16 nXclPortionStart = mxString->Len();
829 // add portion text to Excel string
830 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
831 if( nXclPortionStart < mxString->Len() )
833 // find font index variable dependent on script type
834 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
835 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
837 // insert font into buffer (if not yet done)
838 if( rnFontIdx == EXC_FONT_NOTFOUND )
839 rnFontIdx = ConvertFont( aStrProp, nScript );
841 // insert font index into format run vector
842 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
845 // go to next script portion
846 nLastScript = nScript;
847 nPortionPos = nPortionEnd;
851 if( !mxString->IsEmpty() )
853 // get leading font index
854 const XclFormatRunVec& rFormats = mxString->GetFormats();
855 DBG_ASSERT( !rFormats.empty() && (rFormats.front().mnChar == 0),
856 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
857 // remove leading format run, if entire string is equally formatted
858 if( rFormats.size() == 1 )
859 nFontIdx = mxString->RemoveLeadingFont();
860 else if( !rFormats.empty() )
861 nFontIdx = rFormats.front().mnFontIdx;
862 // add trailing format run, if string is rich-formatted
863 if( mxString->IsRich() )
864 mxString->AppendTrailingFormat( EXC_FONT_APP );
867 return nFontIdx;
870 void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
872 sal_Int32 nApiNumFmt = 0;
873 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
875 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
876 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
880 void XclExpChSourceLink::AppendString( const String& rStr )
882 if (!mxString.is())
883 return;
884 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
887 void XclExpChSourceLink::Save( XclExpStream& rStrm )
889 // CHFORMATRUNS record
890 if( mxString.is() && mxString->IsRich() )
892 sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
893 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
894 mxString->WriteFormats( rStrm, true );
895 rStrm.EndRecord();
897 // CHSOURCELINK record
898 XclExpRecord::Save( rStrm );
899 // CHSTRING record
900 if( mxString.is() && !mxString->IsEmpty() )
902 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
903 rStrm << sal_uInt16( 0 ) << *mxString;
904 rStrm.EndRecord();
908 void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
910 rStrm << maData.mnDestType
911 << maData.mnLinkType
912 << maData.mnFlags
913 << maData.mnNumFmtIdx
914 << mxLinkFmla;
917 // Text =======================================================================
919 XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
920 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
924 // ----------------------------------------------------------------------------
926 XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
927 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
929 maData.mnTarget = nLinkTarget;
930 maData.maPointPos = rPointPos;
933 void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
935 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
938 // ----------------------------------------------------------------------------
940 XclExpChFontBase::~XclExpChFontBase()
944 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
946 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
948 XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
949 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
953 void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
955 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
958 void XclExpChFontBase::ConvertRotationBase(
959 const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
961 sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet );
962 SetRotation( nRotation );
965 // ----------------------------------------------------------------------------
967 XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
968 XclExpChGroupBase( EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
969 XclExpChRoot( rRoot ),
970 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
974 void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
976 mxFont = xFont;
977 maData.maTextColor = rColor;
978 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
979 mnTextColorId = nColorId;
982 void XclExpChText::SetRotation( sal_uInt16 nRotation )
984 maData.mnRotation = nRotation;
985 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
988 void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const String* pSubTitle )
990 mxSrcLink.reset();
991 mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
993 if( xTitle.is() )
995 // title frame formatting
996 ScfPropertySet aTitleProp( xTitle );
997 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
999 // string sequence
1000 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1001 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1002 if (pSubTitle)
1004 // append subtitle as the 2nd line of the title.
1005 String aSubTitle = String::CreateFromAscii("\n");
1006 aSubTitle.Append(*pSubTitle);
1007 mxSrcLink->AppendString(aSubTitle);
1010 ConvertFontBase( GetChRoot(), nFontIdx );
1012 // rotation
1013 ConvertRotationBase( GetChRoot(), aTitleProp );
1015 else
1017 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1021 void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1023 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1024 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1025 ConvertFontBase( GetChRoot(), rPropSet );
1028 bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1029 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1031 namespace cssc = ::com::sun::star::chart2;
1032 cssc::DataPointLabel aPointLabel;
1033 if( rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
1035 //! TODO: make value and percent independent
1036 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1037 bool bShowValue = aPointLabel.ShowNumber;
1038 bool bShowPercent = bIsPie && !bShowValue && aPointLabel.ShowNumberInPercent;
1039 bool bShowCateg = !bShowValue && aPointLabel.ShowCategoryName;
1040 bool bShowAny = bShowValue || bShowPercent || bShowCateg;
1041 bool bShowSymbol = bShowAny && aPointLabel.ShowLegendSymbol;
1043 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1044 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1045 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1046 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1047 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1048 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowSymbol );
1049 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1051 if( bShowAny )
1053 // font settings
1054 ConvertFontBase( GetChRoot(), rPropSet );
1055 // label placement
1056 sal_Int32 nPlacement = 0;
1057 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
1059 using namespace ::com::sun::star::chart::DataLabelPlacement;
1060 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1062 maData.mnPlacement = EXC_CHTEXT_POS_DEFAULT;
1064 else switch( nPlacement )
1066 case AVOID_OVERLAP: maData.mnPlacement = EXC_CHTEXT_POS_AUTO; break;
1067 case CENTER: maData.mnPlacement = EXC_CHTEXT_POS_CENTER; break;
1068 case TOP: maData.mnPlacement = EXC_CHTEXT_POS_ABOVE; break;
1069 case TOP_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1070 case LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1071 case BOTTOM_LEFT: maData.mnPlacement = EXC_CHTEXT_POS_LEFT; break;
1072 case BOTTOM: maData.mnPlacement = EXC_CHTEXT_POS_BELOW; break;
1073 case BOTTOM_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1074 case RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1075 case TOP_RIGHT: maData.mnPlacement = EXC_CHTEXT_POS_RIGHT; break;
1076 case INSIDE: maData.mnPlacement = EXC_CHTEXT_POS_INSIDE; break;
1077 case OUTSIDE: maData.mnPlacement = EXC_CHTEXT_POS_OUTSIDE; break;
1078 case NEAR_ORIGIN: maData.mnPlacement = EXC_CHTEXT_POS_AXIS; break;
1079 default: DBG_ERRORFILE( "XclExpChText::ConvertDataLabel - unknown label placement type" );
1082 // source link (contains number format)
1083 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1084 if( bShowValue || bShowPercent )
1085 // percentage format wins over value format
1086 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1087 // object link
1088 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1089 // return true to indicate existing label
1090 return true;
1093 return false;
1096 void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1098 // required flags
1099 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1100 if( GetBiff() == EXC_BIFF8 )
1101 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1102 // frame formatting
1103 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1104 // font settings
1105 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1106 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1107 ConvertFontBase( GetChRoot(), rPropSet );
1108 // source link (contains number format)
1109 mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1110 mxSrcLink->ConvertNumFmt( rPropSet, false );
1111 // object link
1112 mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
1115 sal_uInt16 XclExpChText::GetAttLabelFlags() const
1117 sal_uInt16 nFlags = 0;
1118 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1119 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1120 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1121 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1122 return nFlags;
1125 void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1127 // CHFONT record
1128 lclSaveRecord( rStrm, mxFont );
1129 // CHSOURCELINK group
1130 lclSaveRecord( rStrm, mxSrcLink );
1131 // CHFRAME group
1132 lclSaveRecord( rStrm, mxFrame );
1133 // CHOBJECTLINK record
1134 lclSaveRecord( rStrm, mxObjLink );
1137 void XclExpChText::WriteBody( XclExpStream& rStrm )
1139 rStrm << maData.mnHAlign
1140 << maData.mnVAlign
1141 << maData.mnBackMode
1142 << maData.maTextColor
1143 << maData.maRect
1144 << maData.mnFlags;
1146 if( GetBiff() == EXC_BIFF8 )
1148 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1149 << maData.mnPlacement
1150 << maData.mnRotation;
1154 // ----------------------------------------------------------------------------
1156 namespace {
1158 /** Creates and returns an Excel text object from the passed title. */
1159 XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
1160 const String* pSubTitle = NULL )
1162 Reference< XTitle > xTitle;
1163 if( xTitled.is() )
1164 xTitle = xTitled->getTitleObject();
1166 XclExpChTextRef xText( new XclExpChText( rRoot ) );
1167 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1168 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1169 will be interpreted as auto-generated title showing the series title in
1170 charts that contain exactly one data series. */
1171 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1172 xText.reset();
1174 return xText;
1179 // Data series ================================================================
1181 XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1182 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1183 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1184 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1188 void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1189 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1191 rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1192 /* Set marker line/fill color to series line color.
1193 TODO: remove this if OOChart supports own colors in markers. */
1194 Color aLineColor;
1195 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1196 maData.maLineColor = maData.maFillColor = aLineColor;
1197 // register colors in palette
1198 RegisterColors( rRoot );
1201 void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1202 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1204 // clear the automatic flag
1205 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1206 // symbol type and color
1207 if( bCloseSymbol )
1209 // set symbol type for the 'close' data series
1210 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1211 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1212 // set symbol line/fill color to series line color
1213 Color aLineColor;
1214 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
1216 maData.maLineColor = maData.maFillColor = aLineColor;
1217 RegisterColors( rRoot );
1220 else
1222 // set invisible symbol
1223 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1227 void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1229 if( HasMarker() )
1231 if( HasLineColor() )
1232 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1233 if( HasFillColor() )
1234 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1238 void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1240 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1241 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1243 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1244 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1248 // ----------------------------------------------------------------------------
1250 XclExpChPieFormat::XclExpChPieFormat() :
1251 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1255 void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1257 double fApiDist(0.0);
1258 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
1259 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1262 // ----------------------------------------------------------------------------
1264 XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1265 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1269 void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1271 sal_Int32 nApiType(0);
1272 if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
1274 using namespace ::com::sun::star::chart2::DataPointGeometry3D;
1275 switch( nApiType )
1277 case CUBOID:
1278 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1279 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1280 break;
1281 case PYRAMID:
1282 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1283 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1284 break;
1285 case CYLINDER:
1286 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1287 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1288 break;
1289 case CONE:
1290 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1291 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1292 break;
1293 default:
1294 DBG_ERRORFILE( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
1299 void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1301 rStrm << maData.mnBase << maData.mnTop;
1304 // ----------------------------------------------------------------------------
1306 XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1307 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1311 // ----------------------------------------------------------------------------
1313 XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1314 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1315 XclExpChGroupBase( EXC_ID_CHDATAFORMAT, 8 ),
1316 XclExpChRoot( rRoot )
1318 maData.maPointPos = rPointPos;
1319 maData.mnFormatIdx = nFormatIdx;
1322 void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1324 // line and area formatting
1325 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1327 // data point symbols
1328 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1329 if( !bIsFrame )
1331 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1332 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1335 // pie segments
1336 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1338 mxPieFmt.reset( new XclExpChPieFormat );
1339 mxPieFmt->Convert( rPropSet );
1342 // 3D bars (only allowed for entire series in BIFF8)
1343 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1345 mx3dDataFmt.reset( new XclExpCh3dDataFormat );
1346 mx3dDataFmt->Convert( rPropSet );
1349 // spline
1350 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1351 mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
1353 // data point labels
1354 XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
1355 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1357 // CHTEXT groups for data labels are stored in global CHCHART group
1358 GetChartData().SetDataLabel( xLabel );
1359 mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
1363 void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1365 // set line format to invisible
1366 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1367 // set symbols to invisible or to 'close' series symbol
1368 mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
1369 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1372 void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1374 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1377 void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1379 lclSaveRecord( rStrm, mx3dDataFmt );
1380 WriteFrameRecords( rStrm );
1381 lclSaveRecord( rStrm, mxPieFmt );
1382 lclSaveRecord( rStrm, mxMarkerFmt );
1383 lclSaveRecord( rStrm, mxSeriesFmt );
1384 lclSaveRecord( rStrm, mxAttLabel );
1387 void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1389 rStrm << maData.maPointPos.mnPointIdx
1390 << maData.maPointPos.mnSeriesIdx
1391 << maData.mnFormatIdx
1392 << maData.mnFlags;
1395 // ----------------------------------------------------------------------------
1397 XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1398 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1399 XclExpChRoot( rRoot )
1403 bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
1405 if( !xRegCurve.is() )
1406 return false;
1408 // trend line type
1409 ScfPropertySet aCurveProp( xRegCurve );
1410 OUString aService = aCurveProp.GetServiceName();
1411 if( aService == SERVICE_CHART2_LINEARREGCURVE )
1413 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1414 maData.mnOrder = 1;
1416 else if( aService == SERVICE_CHART2_EXPREGCURVE )
1417 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1418 else if( aService == SERVICE_CHART2_LOGREGCURVE )
1419 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1420 else if( aService == SERVICE_CHART2_POTREGCURVE )
1421 maData.mnLineType = EXC_CHSERTREND_POWER;
1422 else
1423 return false;
1425 // line formatting
1426 XclChDataPointPos aPointPos( nSeriesIdx );
1427 mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
1428 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1430 // #i83100# show equation and correlation coefficient
1431 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1432 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
1433 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
1435 // #i83100# formatting of the equation text box
1436 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1438 mxLabel.reset( new XclExpChText( GetChRoot() ) );
1439 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1442 // missing features
1443 // #i20819# polynomial trend lines
1444 // #i66819# moving average trend lines
1445 // #i5085# manual trend line size
1446 // #i34093# manual crossing point
1447 return true;
1450 void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1452 rStrm << maData.mnLineType
1453 << maData.mnOrder
1454 << maData.mfIntercept
1455 << maData.mnShowEquation
1456 << maData.mnShowRSquared
1457 << maData.mfForecastFor
1458 << maData.mfForecastBack;
1461 // ----------------------------------------------------------------------------
1463 XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1464 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1465 XclExpChRoot( rRoot )
1467 maData.mnBarType = nBarType;
1470 bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1472 sal_Int32 nBarStyle = 0;
1473 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
1474 if( bOk )
1476 namespace cssc = ::com::sun::star::chart;
1477 switch( nBarStyle )
1479 case cssc::ErrorBarStyle::ABSOLUTE:
1480 maData.mnSourceType = EXC_CHSERERR_FIXED;
1481 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1482 break;
1483 case cssc::ErrorBarStyle::RELATIVE:
1484 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1485 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
1486 break;
1487 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1488 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1489 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
1490 break;
1491 case cssc::ErrorBarStyle::STANDARD_ERROR:
1492 maData.mnSourceType = EXC_CHSERERR_STDERR;
1493 break;
1494 case cssc::ErrorBarStyle::FROM_DATA:
1496 bOk = false;
1497 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1498 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1499 if( xDataSource.is() )
1501 // find first sequence with current role
1502 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1503 Reference< XDataSequence > xValueSeq;
1505 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1506 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1507 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1508 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
1510 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1511 ScfPropertySet aValueProp( xTmpValueSeq );
1512 OUString aCurrRole;
1513 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
1514 xValueSeq = xTmpValueSeq;
1516 if( xValueSeq.is() )
1518 // #i86465# pass value count back to series
1519 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1520 bOk = maData.mnValueCount > 0;
1524 break;
1525 default:
1526 bOk = false;
1529 return bOk;
1532 void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1534 rStrm << maData.mnBarType
1535 << maData.mnSourceType
1536 << maData.mnLineEnd
1537 << sal_uInt8( 1 ) // must be 1 to make line visible
1538 << maData.mfValue
1539 << maData.mnValueCount;
1542 // ----------------------------------------------------------------------------
1544 namespace {
1546 /** Returns the property set of the specified data point. */
1547 ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
1549 ScfPropertySet aPropSet;
1552 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1554 catch( Exception& )
1556 DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
1558 return aPropSet;
1561 } // namespace
1563 XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1564 XclExpChGroupBase( EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1565 XclExpChRoot( rRoot ),
1566 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1567 mnSeriesIdx( nSeriesIdx ),
1568 mnParentIdx( EXC_CHSERIES_INVALID )
1570 // CHSOURCELINK records are always required, even if unused
1571 mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
1572 mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
1573 mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
1574 if( GetBiff() == EXC_BIFF8 )
1575 mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
1578 bool XclExpChSeries::ConvertDataSeries(
1579 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
1580 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1582 bool bOk = false;
1583 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1584 if( xDataSource.is() )
1586 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq;
1588 // find first sequence with role 'values-y'
1589 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1590 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1591 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1592 for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
1594 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1595 ScfPropertySet aValueProp( xTmpValueSeq );
1596 OUString aRole;
1597 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
1599 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
1601 xYValueSeq = xTmpValueSeq;
1602 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1604 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
1606 xXValueSeq = xTmpValueSeq;
1611 bOk = xYValueSeq.is();
1612 if( bOk )
1614 // chart type group index
1615 mnGroupIdx = nGroupIdx;
1617 // convert source links
1618 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1619 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1621 // X values of XY charts
1622 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1624 // series formatting
1625 XclChDataPointPos aPointPos( mnSeriesIdx );
1626 ScfPropertySet aSeriesProp( xDataSeries );
1627 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1628 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1630 // trend lines
1631 CreateTrendLines( xDataSeries );
1633 // error bars
1634 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1635 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1637 if( maData.mnValueCount > 0 )
1639 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1641 /* #i91063# Create missing fill properties in pie/doughnut charts.
1642 If freshly created (never saved to ODF), these charts show
1643 varying point colors but do not return these points via API. */
1644 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1646 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1647 if( xColorScheme.is() )
1649 const OUString aFillStyleName = CREATE_OUSTRING( "FillStyle" );
1650 const OUString aColorName = CREATE_OUSTRING( "Color" );
1651 namespace csscd = ::com::sun::star::drawing;
1652 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1654 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1655 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1656 // test that the point fill style is solid, but no color is set
1657 csscd::FillStyle eFillStyle = csscd::FillStyle_NONE;
1658 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1659 (eFillStyle == csscd::FillStyle_SOLID) &&
1660 !aPointProp.HasProperty( aColorName ) )
1662 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1668 // data point formatting
1669 Sequence< sal_Int32 > aPointIndexes;
1670 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
1672 const sal_Int32* pnBeg = aPointIndexes.getConstArray();
1673 const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
1674 for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
1676 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
1677 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
1678 XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
1679 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1680 maPointFmts.AppendRecord( xPointFmt );
1686 return bOk;
1689 bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
1690 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1692 bool bOk = false;
1693 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1694 if( xDataSource.is() )
1696 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1698 // find first sequence with passed role
1699 Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1700 const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
1701 const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
1702 for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
1704 Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
1705 ScfPropertySet aValueProp( xTmpValueSeq );
1706 OUString aRole;
1707 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
1709 xYValueSeq = xTmpValueSeq;
1710 xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
1714 bOk = xYValueSeq.is();
1715 if( bOk )
1717 // chart type group index
1718 mnGroupIdx = nGroupIdx;
1719 // convert source links
1720 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1721 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1722 // series formatting
1723 ScfPropertySet aSeriesProp( xDataSeries );
1724 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
1725 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
1728 return bOk;
1731 bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
1733 InitFromParent( rParent );
1734 mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
1735 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
1736 if( bOk )
1738 mxSeriesFmt = mxTrendLine->GetDataFormat();
1739 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
1741 return bOk;
1744 bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
1746 InitFromParent( rParent );
1747 // error bar settings
1748 mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
1749 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
1750 if( bOk )
1752 // error bar formatting
1753 mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
1754 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
1756 return bOk;
1759 void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
1761 if( xCategSeq.is() )
1762 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
1765 void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
1767 lclSaveRecord( rStrm, mxTitleLink );
1768 lclSaveRecord( rStrm, mxValueLink );
1769 lclSaveRecord( rStrm, mxCategLink );
1770 lclSaveRecord( rStrm, mxBubbleLink );
1771 lclSaveRecord( rStrm, mxSeriesFmt );
1772 maPointFmts.Save( rStrm );
1773 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
1774 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
1775 if( mnParentIdx != EXC_CHSERIES_INVALID )
1776 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
1777 lclSaveRecord( rStrm, mxTrendLine );
1778 lclSaveRecord( rStrm, mxErrorBar );
1781 void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
1783 // index to parent series is stored 1-based
1784 mnParentIdx = rParent.mnSeriesIdx + 1;
1785 /* #i86465# MSO2007 SP1 expects correct point counts in child series
1786 (there was no problem in Excel2003 or Excel2007 without SP1...) */
1787 maData.mnCategCount = rParent.maData.mnCategCount;
1788 maData.mnValueCount = rParent.maData.mnValueCount;
1791 void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
1793 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
1794 if( xRegCurveCont.is() )
1796 Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
1797 const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
1798 const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
1799 for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
1801 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1802 if( xSeries.is() && !xSeries->ConvertTrendLine( *this, *pIt ) )
1803 GetChartData().RemoveLastSeries();
1808 void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
1809 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
1811 Reference< XPropertySet > xErrorBar;
1812 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
1814 ScfPropertySet aErrorProp( xErrorBar );
1815 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
1816 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
1820 void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
1821 const OUString& rShowPropName, sal_uInt8 nBarId )
1823 if( rPropSet.GetBoolProperty( rShowPropName ) )
1825 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
1826 if( xSeries.is() && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
1827 GetChartData().RemoveLastSeries();
1831 void XclExpChSeries::WriteBody( XclExpStream& rStrm )
1833 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
1834 if( GetBiff() == EXC_BIFF8 )
1835 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
1838 // Chart type groups ==========================================================
1840 XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
1841 XclExpRecord( EXC_ID_CHUNKNOWN ),
1842 XclExpChRoot( rRoot ),
1843 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
1847 void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
1848 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
1850 if( xChartType.is() )
1852 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
1853 // special handling for some chart types
1854 switch( maTypeInfo.meTypeCateg )
1856 case EXC_CHTYPECATEG_BAR:
1858 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
1859 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
1860 ScfPropertySet aTypeProp( xChartType );
1861 Sequence< sal_Int32 > aInt32Seq;
1862 maData.mnOverlap = 0;
1863 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
1864 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
1865 maData.mnGap = 150;
1866 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
1867 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
1869 break;
1870 case EXC_CHTYPECATEG_RADAR:
1871 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
1872 break;
1873 case EXC_CHTYPECATEG_PIE:
1875 ScfPropertySet aTypeProp( xChartType );
1876 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
1877 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
1878 maData.mnPieHole = bDonut ? 50 : 0;
1879 // #i85166# starting angle of first pie slice
1880 ScfPropertySet aDiaProp( xDiagram );
1881 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
1883 break;
1884 case EXC_CHTYPECATEG_SCATTER:
1885 if( GetBiff() == EXC_BIFF8 )
1886 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
1887 break;
1888 default:;
1890 SetRecId( maTypeInfo.mnRecId );
1894 void XclExpChType::SetStacked( bool bPercent )
1896 switch( maTypeInfo.meTypeCateg )
1898 case EXC_CHTYPECATEG_LINE:
1899 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
1900 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
1901 break;
1902 case EXC_CHTYPECATEG_BAR:
1903 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
1904 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
1905 maData.mnOverlap = -100;
1906 break;
1907 default:;
1911 void XclExpChType::WriteBody( XclExpStream& rStrm )
1913 switch( GetRecId() )
1915 case EXC_ID_CHBAR:
1916 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
1917 break;
1919 case EXC_ID_CHLINE:
1920 case EXC_ID_CHAREA:
1921 case EXC_ID_CHRADARLINE:
1922 case EXC_ID_CHRADARAREA:
1923 rStrm << maData.mnFlags;
1924 break;
1926 case EXC_ID_CHPIE:
1927 rStrm << maData.mnRotation << maData.mnPieHole;
1928 if( GetBiff() == EXC_BIFF8 )
1929 rStrm << maData.mnFlags;
1930 break;
1932 case EXC_ID_CHSCATTER:
1933 if( GetBiff() == EXC_BIFF8 )
1934 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
1935 break;
1937 default:
1938 DBG_ERRORFILE( "XclExpChType::WriteBody - unknown chart type" );
1942 // ----------------------------------------------------------------------------
1944 XclExpChChart3d::XclExpChChart3d() :
1945 XclExpRecord( EXC_ID_CHCHART3D, 14 )
1949 void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
1951 sal_Int32 nRotationY = 0;
1952 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
1953 sal_Int32 nRotationX = 0;
1954 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
1955 sal_Int32 nPerspective = 15;
1956 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
1958 if( b3dWallChart )
1960 // Y rotation (Excel [0..359], Chart2 [-179,180])
1961 if( nRotationY < 0 ) nRotationY += 360;
1962 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
1963 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
1964 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
1965 // perspective (Excel and Chart2 [0,100])
1966 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
1967 // flags
1968 maData.mnFlags = 0;
1969 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
1970 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
1971 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
1973 else
1975 // Y rotation not used in pie charts, but 'first pie slice angle'
1976 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
1977 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
1978 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
1979 // perspective (Excel and Chart2 [0,100])
1980 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
1981 // flags
1982 maData.mnFlags = 0;
1986 void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
1988 rStrm << maData.mnRotation
1989 << maData.mnElevation
1990 << maData.mnEyeDist
1991 << maData.mnRelHeight
1992 << maData.mnRelDepth
1993 << maData.mnDepthGap
1994 << maData.mnFlags;
1997 // ----------------------------------------------------------------------------
1999 XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2000 XclExpChGroupBase( EXC_ID_CHLEGEND, 20 ),
2001 XclExpChRoot( rRoot )
2005 void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2007 // frame properties
2008 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2009 // text properties
2010 mxText.reset( new XclExpChText( GetChRoot() ) );
2011 mxText->ConvertLegend( rPropSet );
2012 // special legend properties
2013 GetChartPropSetHelper().ReadLegendProperties( maData, rPropSet );
2016 void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2018 lclSaveRecord( rStrm, mxText );
2019 lclSaveRecord( rStrm, mxFrame );
2022 void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2024 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2027 // ----------------------------------------------------------------------------
2029 XclExpChDropBar::XclExpChDropBar( XclChObjectType eObjType ) :
2030 XclExpChGroupBase( EXC_ID_CHDROPBAR, 2 ),
2031 meObjType( eObjType ),
2032 mnBarDist( 100 )
2036 void XclExpChDropBar::Convert( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
2038 if( rPropSet.Is() )
2039 ConvertFrameBase( rRoot, rPropSet, meObjType );
2040 else
2041 SetDefaultFrameBase( rRoot, EXC_CHFRAMETYPE_INVISIBLE, true );
2044 void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2046 WriteFrameRecords( rStrm );
2049 void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2051 rStrm << mnBarDist;
2054 // ----------------------------------------------------------------------------
2056 XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2057 XclExpChGroupBase( EXC_ID_CHTYPEGROUP, 20 ),
2058 XclExpChRoot( rRoot ),
2059 maType( rRoot ),
2060 maTypeInfo( maType.GetTypeInfo() )
2062 maData.mnGroupIdx = nGroupIdx;
2065 void XclExpChTypeGroup::ConvertType(
2066 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2067 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2069 // chart type settings
2070 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2072 // spline - TODO: get from single series (#i66858#)
2073 ScfPropertySet aTypeProp( xChartType );
2074 ::com::sun::star::chart2::CurveStyle eCurveStyle;
2075 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
2076 (eCurveStyle != ::com::sun::star::chart2::CurveStyle_LINES);
2078 // extended type info
2079 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2081 // 3d chart settings
2082 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2084 mxChart3d.reset( new XclExpChChart3d );
2085 ScfPropertySet aDiaProp( xDiagram );
2086 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2090 void XclExpChTypeGroup::ConvertSeries(
2091 Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
2092 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2094 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2095 if( xSeriesCont.is() )
2097 typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
2098 XDataSeriesVec aSeriesVec;
2100 // copy data series attached to the current axes set to the vector
2101 Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2102 const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
2103 const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
2104 for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
2106 ScfPropertySet aSeriesProp( *pIt );
2107 sal_Int32 nSeriesAxesSetIdx(0);
2108 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2109 aSeriesVec.push_back( *pIt );
2112 // Are there any series in the current axes set?
2113 if( !aSeriesVec.empty() )
2115 // stacking direction (stacked/percent/deep 3d) from first series
2116 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2117 namespace cssc = ::com::sun::star::chart2;
2118 cssc::StackingDirection eStacking;
2119 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
2120 eStacking = cssc::StackingDirection_NO_STACKING;
2122 // stacked or percent chart
2123 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc::StackingDirection_Y_STACKING) )
2125 // percent overrides simple stacking
2126 maType.SetStacked( bPercent );
2128 // connected data points (only in stacked bar charts)
2129 if( bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
2130 maChartLines[ EXC_CHCHARTLINE_CONNECT ].reset( new XclExpChLineFormat( GetChRoot() ) );
2132 else
2134 // reverse series order for some unstacked 2D chart types
2135 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2136 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2139 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2140 if( (eStacking == cssc::StackingDirection_NO_STACKING) && Is3dWallChart() )
2141 mxChart3d->SetClustered();
2143 // varied point colors
2144 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
2146 // process all series
2147 for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
2149 // create Excel series object, stock charts need special processing
2150 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2151 CreateAllStockSeries( xChartType, *aIt );
2152 else
2153 CreateDataSeries( xDiagram, *aIt );
2159 void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
2161 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2162 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2165 void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2167 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
2169 mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
2170 mxLegend->Convert( rPropSet );
2174 void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2176 maType.Save( rStrm );
2177 lclSaveRecord( rStrm, mxChart3d );
2178 lclSaveRecord( rStrm, mxLegend );
2179 lclSaveRecord( rStrm, mxUpBar );
2180 lclSaveRecord( rStrm, mxDownBar );
2181 for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
2182 lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
2185 sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2187 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2190 void XclExpChTypeGroup::CreateDataSeries(
2191 Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
2193 // let chart create series object with correct series index
2194 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2195 if( xSeries.is() )
2197 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2198 maSeries.AppendRecord( xSeries );
2199 else
2200 GetChartData().RemoveLastSeries();
2204 void XclExpChTypeGroup::CreateAllStockSeries(
2205 Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
2207 // create existing series objects
2208 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
2209 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
2210 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
2211 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
2213 // formatting of special stock chart elements
2214 ScfPropertySet aTypeProp( xChartType );
2215 // hi-lo lines
2216 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
2218 ScfPropertySet aSeriesProp( xDataSeries );
2219 XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
2220 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2221 maChartLines[ EXC_CHCHARTLINE_HILO ] = xLineFmt;
2223 // dropbars
2224 if( bHasOpen && bHasClose )
2226 // dropbar type is dependent on position in the file - always create both
2227 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2228 // white dropbar format
2229 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
2230 ScfPropertySet aWhiteProp( xWhitePropSet );
2231 mxUpBar.reset( new XclExpChDropBar( EXC_CHOBJTYPE_WHITEDROPBAR ) );
2232 mxUpBar->Convert( GetChRoot(), aWhiteProp );
2233 // black dropbar format
2234 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
2235 ScfPropertySet aBlackProp( xBlackPropSet );
2236 mxDownBar.reset( new XclExpChDropBar( EXC_CHOBJTYPE_BLACKDROPBAR ) );
2237 mxDownBar->Convert( GetChRoot(), aBlackProp );
2241 bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
2242 const OUString& rValueRole, bool bCloseSymbol )
2244 bool bOk = false;
2245 // let chart create series object with correct series index
2246 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2247 if( xSeries.is() )
2249 bOk = xSeries->ConvertStockSeries( xDataSeries,
2250 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2251 if( bOk )
2252 maSeries.AppendRecord( xSeries );
2253 else
2254 GetChartData().RemoveLastSeries();
2256 return bOk;
2259 void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2261 rStrm << maData.maRect << maData.mnFlags << maData.mnGroupIdx;
2264 // Axes =======================================================================
2266 XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2267 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2268 XclExpChRoot( rRoot )
2272 void XclExpChLabelRange::Convert( const ScaleData& rScaleData, bool bMirrorOrient )
2274 // origin
2275 double fOrigin = 0.0;
2276 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin, false ) )
2277 maData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 32767 );
2279 // reverse order
2280 if( (rScaleData.Orientation == ::com::sun::star::chart2::AxisOrientation_REVERSE) != bMirrorOrient )
2282 ::set_flag( maData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2283 SwapAxisMaxCross();
2287 void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2289 rStrm << maData.mnCross << maData.mnLabelFreq << maData.mnTickFreq << maData.mnFlags;
2292 // ----------------------------------------------------------------------------
2294 XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2295 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2296 XclExpChRoot( rRoot )
2300 void XclExpChValueRange::Convert( const ScaleData& rScaleData, bool bPercent )
2302 // scaling algorithm
2303 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == SERVICE_CHART2_LOGSCALING;
2304 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2305 Reference< XScaling > xLogScaling;
2306 if( bLogScale )
2307 xLogScaling = rScaleData.Scaling;
2309 // min/max
2310 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, xLogScaling, bPercent );
2311 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2312 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, xLogScaling, bPercent );
2313 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2315 // origin
2316 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, xLogScaling, bPercent );
2317 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2319 // major increment
2320 const IncrementData& rIncrementData = rScaleData.IncrementData;
2321 bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance, bPercent ) || (maData.mfMajorStep <= 0.0);
2322 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2323 // minor increment
2324 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2325 sal_Int32 nCount = 0;
2326 bool bAutoMinor = bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
2327 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount, false ) || (nCount < 1);
2328 if( !bAutoMinor )
2329 maData.mfMinorStep = maData.mfMajorStep / nCount;
2330 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2332 // reverse order
2333 namespace cssc = ::com::sun::star::chart2;
2334 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc::AxisOrientation_REVERSE );
2337 void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2339 rStrm << maData.mfMin
2340 << maData.mfMax
2341 << maData.mfMajorStep
2342 << maData.mfMinorStep
2343 << maData.mfCross
2344 << maData.mnFlags;
2347 // ----------------------------------------------------------------------------
2349 namespace {
2351 sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2353 using namespace ::com::sun::star::chart2::TickmarkStyle;
2354 sal_uInt8 nXclTickPos = 0;
2355 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2356 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2357 return nXclTickPos;
2360 } // namespace
2362 XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2363 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2364 XclExpChRoot( rRoot ),
2365 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2369 void XclExpChTick::Convert( const ScfPropertySet& rPropSet )
2371 // tick mark style
2372 sal_Int32 nApiTickmarks(0);
2373 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
2374 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2375 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
2376 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2379 void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2381 maData.maTextColor = rColor;
2382 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2383 mnTextColorId = nColorId;
2386 void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2388 maData.mnRotation = nRotation;
2389 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2390 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2393 void XclExpChTick::WriteBody( XclExpStream& rStrm )
2395 rStrm << maData.mnMajor
2396 << maData.mnMinor
2397 << maData.mnLabelPos
2398 << maData.mnBackMode
2399 << maData.maRect
2400 << maData.maTextColor
2401 << maData.mnFlags;
2402 if( GetBiff() == EXC_BIFF8 )
2403 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2406 // ----------------------------------------------------------------------------
2408 namespace {
2410 /** Returns an API axis object from the passed coordinate system. */
2411 Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
2412 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2414 Reference< XAxis > xAxis;
2417 if( xCoordSystem.is() )
2418 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2420 catch( Exception& )
2423 return xAxis;
2426 } // namespace
2428 XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2429 XclExpChGroupBase( EXC_ID_CHAXIS, 18 ),
2430 XclExpChRoot( rRoot ),
2431 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2433 maData.mnType = nAxisType;
2436 void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2438 mxFont = xFont;
2439 if( mxTick.is() )
2440 mxTick->SetFontColor( rColor, nColorId );
2443 void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2445 if( mxTick.is() )
2446 mxTick->SetRotation( nRotation );
2449 void XclExpChAxis::Convert( Reference< XAxis > xAxis, const XclChExtTypeInfo& rTypeInfo, sal_Int32 nApiAxesSetIdx,
2450 bool bPercent )
2452 ScfPropertySet aAxisProp( xAxis );
2453 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2455 // axis line format -------------------------------------------------------
2457 mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
2458 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2459 // #i58688# axis enabled
2460 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
2462 // axis scaling and increment ---------------------------------------------
2464 if( bCategoryAxis )
2466 mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
2467 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2468 if( xAxis.is() )
2469 // #i71684# radar charts have reversed rotation direction
2470 mxLabelRange->Convert( xAxis->getScaleData(), (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2471 // swap max-cross flag for secondary X axis to have the secondary Y axis at right side
2472 if( (GetAxisType() == EXC_CHAXIS_X) && (nApiAxesSetIdx == EXC_CHAXESSET_SECONDARY) )
2473 mxLabelRange->SwapAxisMaxCross();
2475 else
2477 mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
2478 if( xAxis.is() )
2479 mxValueRange->Convert( xAxis->getScaleData(), bPercent );
2482 // axis caption text ------------------------------------------------------
2484 // axis ticks properties
2485 mxTick.reset( new XclExpChTick( GetChRoot() ) );
2486 mxTick->Convert( aAxisProp );
2488 // existence and position of axis labels
2489 sal_uInt8 nLabelPos = EXC_CHTICK_NOLABEL;
2490 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR )
2491 /* Radar charts disable their category labels via chart type, not via
2492 axis, and axis labels are always 'near axis' in Chart2. */
2493 nLabelPos = EXC_CHTICK_NEXT;
2494 else if( aAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
2495 /* #i85862# Axis labels in other chart types always have position 'low'
2496 in Chart2, but Excel expects 'near axis' at Y axes in 3D charts. */
2497 nLabelPos = (rTypeInfo.mb3dChart && (GetAxisType() == EXC_CHAXIS_Y)) ? EXC_CHTICK_NEXT : EXC_CHTICK_LOW;
2498 mxTick->SetLabelPos( nLabelPos );
2500 // axis label formatting and rotation
2501 ConvertFontBase( GetChRoot(), aAxisProp );
2502 ConvertRotationBase( GetChRoot(), aAxisProp );
2504 // axis number format
2505 sal_Int32 nApiNumFmt = 0;
2506 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
2507 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
2509 // grid -------------------------------------------------------------------
2511 if( xAxis.is() )
2513 // main grid
2514 ScfPropertySet aGridProp( xAxis->getGridProperties() );
2515 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2516 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
2517 // sub grid
2518 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
2519 if( aSubGridPropSeq.hasElements() )
2521 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
2522 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
2523 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
2528 void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
2530 if( xDiagram.is() ) switch( GetAxisType() )
2532 case EXC_CHAXIS_X:
2534 ScfPropertySet aWallProp( xDiagram->getWall() );
2535 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
2537 break;
2538 case EXC_CHAXIS_Y:
2540 ScfPropertySet aFloorProp( xDiagram->getFloor() );
2541 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
2543 break;
2544 default:
2545 mxWallFrame.reset();
2549 void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
2551 lclSaveRecord( rStrm, mxLabelRange );
2552 lclSaveRecord( rStrm, mxValueRange );
2553 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
2554 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
2555 lclSaveRecord( rStrm, mxTick );
2556 lclSaveRecord( rStrm, mxFont );
2557 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
2558 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
2559 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
2560 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
2563 void XclExpChAxis::WriteBody( XclExpStream& rStrm )
2565 rStrm << maData.mnType << maData.maRect;
2568 // ----------------------------------------------------------------------------
2570 XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
2571 XclExpChGroupBase( EXC_ID_CHAXESSET, 18 ),
2572 XclExpChRoot( rRoot )
2574 maData.mnAxesSetId = nAxesSetId;
2577 sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
2579 /* First unused chart type group index is passed to be able to continue
2580 counting of chart type groups for secondary axes set. */
2581 sal_uInt16 nGroupIdx = nFirstGroupIdx;
2582 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
2583 if( xCoordSysCont.is() )
2585 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
2586 if( aCoordSysSeq.getLength() > 0 )
2588 /* Process first coordinate system only. Import filter puts all
2589 chart types into one coordinate system. */
2590 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
2591 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2593 // 3d mode
2594 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
2596 // percent charts
2597 namespace ApiAxisType = ::com::sun::star::chart2::AxisType;
2598 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
2599 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
2601 // connector lines in bar charts
2602 ScfPropertySet aDiaProp( xDiagram );
2603 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
2605 // swapped axes sets
2606 ScfPropertySet aCoordSysProp( xCoordSystem );
2607 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
2609 // X axis for later use
2610 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
2611 // X axis labels
2612 ScfPropertySet aXAxisProp( xApiXAxis );
2613 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
2615 // process chart types
2616 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
2617 if( xChartTypeCont.is() )
2619 Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
2620 const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
2621 const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
2622 for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
2624 XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
2625 xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
2626 /* If new chart type group cannot be inserted into a combination
2627 chart with existing type groups, insert all series into last
2628 contained chart type group instead of creating a new group. */
2629 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
2630 if( xLastGroup.is() && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
2632 xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2634 else
2636 xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
2637 if( xTypeGroup->IsValidGroup() )
2639 maTypeGroups.AppendRecord( xTypeGroup );
2640 ++nGroupIdx;
2646 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
2648 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
2650 // create axes according to chart type (no axes for pie and donut charts)
2651 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
2653 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, bPercent );
2654 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, bPercent );
2655 if( pGroup->Is3dDeepChart() )
2656 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, bPercent );
2659 // X axis category ranges
2660 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
2662 const ScaleData aScaleData = xApiXAxis->getScaleData();
2663 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
2664 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
2667 // legend
2668 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2670 Reference< XLegend > xLegend = xDiagram->getLegend();
2671 if( xLegend.is() )
2673 ScfPropertySet aLegendProp( xLegend );
2674 pGroup->ConvertLegend( aLegendProp );
2681 // wall/floor/diagram frame formatting
2682 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
2684 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2685 if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() )
2687 // wall/floor formatting (3D charts)
2688 if( mxXAxis.is() )
2689 mxXAxis->ConvertWall( xDiagram );
2690 if( mxYAxis.is() )
2691 mxYAxis->ConvertWall( xDiagram );
2693 else
2695 // diagram background formatting
2696 ScfPropertySet aWallProp( xDiagram->getWall() );
2697 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
2701 // return first unused chart type group index for next axes set
2702 return nGroupIdx;
2705 bool XclExpChAxesSet::Is3dChart() const
2707 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
2708 return xTypeGroup.is() && xTypeGroup->Is3dChart();
2711 void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
2713 lclSaveRecord( rStrm, mxXAxis );
2714 lclSaveRecord( rStrm, mxYAxis );
2715 lclSaveRecord( rStrm, mxZAxis );
2716 lclSaveRecord( rStrm, mxXAxisTitle );
2717 lclSaveRecord( rStrm, mxYAxisTitle );
2718 lclSaveRecord( rStrm, mxZAxisTitle );
2719 if( mxPlotFrame.is() )
2721 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
2722 mxPlotFrame->Save( rStrm );
2724 maTypeGroups.Save( rStrm );
2727 XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
2729 return maTypeGroups.GetFirstRecord();
2732 XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
2734 return maTypeGroups.GetLastRecord();
2737 void XclExpChAxesSet::ConvertAxis(
2738 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
2739 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
2740 Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
2741 bool bPercent )
2743 // create and convert axis object
2744 rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
2745 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
2746 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
2747 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
2748 rxChAxis->Convert( xAxis, rTypeInfo, nApiAxesSetIdx, bPercent );
2750 // create and convert axis title
2751 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
2752 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
2755 void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
2757 rStrm << maData.mnAxesSetId << maData.maRect;
2760 // The chart object ===========================================================
2762 static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
2763 String& rSubTitle)
2765 Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
2766 if (!xChartDoc1.is())
2767 return;
2769 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
2770 if (!xProp.is())
2771 return;
2773 OUString aTitle;
2774 Any any = xProp->getPropertyValue( OUString::createFromAscii("String") );
2775 if (any >>= aTitle)
2776 rSubTitle = aTitle;
2779 XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
2780 Reference< XChartDocument > xChartDoc, const Size& rSize ) :
2781 XclExpChGroupBase( EXC_ID_CHCHART, 16 ),
2782 XclExpChRoot( rRoot, this )
2784 Size aPtSize = OutputDevice::LogicToLogic( rSize, MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
2785 // rectangle is stored in 16.16 fixed-point format
2786 maRect.mnX = maRect.mnY = 0;
2787 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
2788 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
2790 // global chart properties (default values)
2791 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANSERIES );
2792 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISCELLS, false );
2793 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
2795 // always create both axes set objects
2796 mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
2797 mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
2799 if( xChartDoc.is() )
2801 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
2803 // global chart properties (only 'include hidden cells' attribute for now)
2804 ScfPropertySet aDiagramProp( xDiagram );
2805 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
2806 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISCELLS, !bIncludeHidden );
2808 // initialize API conversion (remembers xChartDoc internally)
2809 InitConversion( xChartDoc );
2811 // chart frame
2812 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
2813 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
2815 // chart title
2816 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
2817 String aSubTitle;
2818 lcl_getChartSubTitle(xChartDoc, aSubTitle);
2819 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
2820 aSubTitle.Len() ? &aSubTitle : NULL );
2822 // diagrams (axes sets)
2823 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
2824 if( !mxPrimAxesSet->Is3dChart() )
2825 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
2827 // finish API conversion
2828 FinishConversion();
2832 XclExpChSeriesRef XclExpChChart::CreateSeries()
2834 XclExpChSeriesRef xSeries;
2835 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
2836 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
2838 xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
2839 maSeries.AppendRecord( xSeries );
2841 return xSeries;
2844 void XclExpChChart::RemoveLastSeries()
2846 if( !maSeries.IsEmpty() )
2847 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
2850 void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
2852 if( xText.is() )
2853 maLabels.AppendRecord( xText );
2856 void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
2858 // background format
2859 lclSaveRecord( rStrm, mxFrame );
2861 // data series
2862 maSeries.Save( rStrm );
2864 // CHPROPERTIES record
2865 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
2866 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
2867 rStrm.EndRecord();
2869 // axes sets (always save primary axes set)
2870 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
2871 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
2872 mxPrimAxesSet->Save( rStrm );
2873 if( mxSecnAxesSet->IsValidAxesSet() )
2874 mxSecnAxesSet->Save( rStrm );
2876 // chart title and data labels
2877 lclSaveRecord( rStrm, mxTitle );
2878 maLabels.Save( rStrm );
2881 void XclExpChChart::WriteBody( XclExpStream& rStrm )
2883 rStrm << maRect;
2886 // ----------------------------------------------------------------------------
2888 XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Size& rSize ) :
2889 XclExpSubStream( EXC_BOF_CHART ),
2890 XclExpRoot( rRoot )
2892 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
2893 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
2894 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
2896 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
2897 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rSize ) );
2900 // ============================================================================