| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| #include "xichart.hxx" |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include <com/sun/star/frame/XModel.hpp> |
| #include <com/sun/star/drawing/Direction3D.hpp> |
| #include <com/sun/star/drawing/ProjectionMode.hpp> |
| #include <com/sun/star/drawing/ShadeMode.hpp> |
| #include <com/sun/star/drawing/XShape.hpp> |
| #include <com/sun/star/drawing/XDrawPageSupplier.hpp> |
| #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> |
| #include <com/sun/star/chart/ChartAxisLabelPosition.hpp> |
| #include <com/sun/star/chart/ChartAxisMarkPosition.hpp> |
| #include <com/sun/star/chart/ChartAxisPosition.hpp> |
| #include <com/sun/star/chart/ChartLegendExpansion.hpp> |
| #include <com/sun/star/chart/TimeInterval.hpp> |
| #include <com/sun/star/chart/TimeUnit.hpp> |
| #include <com/sun/star/chart/XChartDocument.hpp> |
| #include <com/sun/star/chart/XDiagramPositioning.hpp> |
| #include <com/sun/star/chart2/XChartDocument.hpp> |
| #include <com/sun/star/chart2/XDiagram.hpp> |
| #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> |
| #include <com/sun/star/chart2/XChartTypeContainer.hpp> |
| #include <com/sun/star/chart2/XDataSeriesContainer.hpp> |
| #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> |
| #include <com/sun/star/chart2/XTitled.hpp> |
| #include <com/sun/star/chart2/data/XDataProvider.hpp> |
| #include <com/sun/star/chart2/data/XDataReceiver.hpp> |
| #include <com/sun/star/chart2/data/XDataSink.hpp> |
| #include <com/sun/star/chart2/AxisType.hpp> |
| #include <com/sun/star/chart2/CurveStyle.hpp> |
| #include <com/sun/star/chart2/DataPointGeometry3D.hpp> |
| #include <com/sun/star/chart2/DataPointLabel.hpp> |
| #include <com/sun/star/chart2/LegendPosition.hpp> |
| #include <com/sun/star/chart2/StackingDirection.hpp> |
| #include <com/sun/star/chart2/TickmarkStyle.hpp> |
| #include <com/sun/star/chart2/RelativePosition.hpp> |
| #include <com/sun/star/chart2/RelativeSize.hpp> |
| #include <com/sun/star/chart/DataLabelPlacement.hpp> |
| #include <com/sun/star/chart/ErrorBarStyle.hpp> |
| #include <com/sun/star/chart/MissingValueTreatment.hpp> |
| |
| #include <sfx2/objsh.hxx> |
| #include <svx/svdpage.hxx> |
| #include <svx/unoapi.hxx> |
| |
| #include "document.hxx" |
| #include "drwlayer.hxx" |
| #include "rangeutl.hxx" |
| #include "tokenarray.hxx" |
| #include "token.hxx" |
| #include "compiler.hxx" |
| #include "reftokenhelper.hxx" |
| #include "chartlis.hxx" |
| #include "fprogressbar.hxx" |
| #include "xltracer.hxx" |
| #include "xistream.hxx" |
| #include "xiformula.hxx" |
| #include "xistyle.hxx" |
| #include "xipage.hxx" |
| #include "xiview.hxx" |
| |
| using ::rtl::OUString; |
| using ::rtl::OUStringBuffer; |
| using ::com::sun::star::uno::Any; |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::uno::UNO_QUERY; |
| using ::com::sun::star::uno::UNO_QUERY_THROW; |
| using ::com::sun::star::uno::UNO_SET_THROW; |
| using ::com::sun::star::uno::Exception; |
| using ::com::sun::star::beans::XPropertySet; |
| using ::com::sun::star::lang::XMultiServiceFactory; |
| using ::com::sun::star::frame::XModel; |
| using ::com::sun::star::util::XNumberFormatsSupplier; |
| using ::com::sun::star::drawing::XDrawPage; |
| using ::com::sun::star::drawing::XDrawPageSupplier; |
| using ::com::sun::star::drawing::XShape; |
| |
| using ::com::sun::star::chart2::IncrementData; |
| using ::com::sun::star::chart2::RelativePosition; |
| using ::com::sun::star::chart2::RelativeSize; |
| using ::com::sun::star::chart2::ScaleData; |
| using ::com::sun::star::chart2::SubIncrement; |
| using ::com::sun::star::chart2::XAxis; |
| using ::com::sun::star::chart2::XChartDocument; |
| using ::com::sun::star::chart2::XChartType; |
| using ::com::sun::star::chart2::XChartTypeContainer; |
| using ::com::sun::star::chart2::XCoordinateSystem; |
| using ::com::sun::star::chart2::XCoordinateSystemContainer; |
| using ::com::sun::star::chart2::XDataSeries; |
| using ::com::sun::star::chart2::XDataSeriesContainer; |
| using ::com::sun::star::chart2::XDiagram; |
| using ::com::sun::star::chart2::XFormattedString; |
| using ::com::sun::star::chart2::XLegend; |
| using ::com::sun::star::chart2::XRegressionCurve; |
| using ::com::sun::star::chart2::XRegressionCurveContainer; |
| using ::com::sun::star::chart2::XScaling; |
| using ::com::sun::star::chart2::XTitle; |
| using ::com::sun::star::chart2::XTitled; |
| |
| using ::com::sun::star::chart2::data::XDataProvider; |
| using ::com::sun::star::chart2::data::XDataReceiver; |
| using ::com::sun::star::chart2::data::XDataSequence; |
| using ::com::sun::star::chart2::data::XDataSink; |
| using ::com::sun::star::chart2::data::XLabeledDataSequence; |
| |
| using ::formula::FormulaToken; |
| using ::formula::StackVar; |
| |
| namespace cssc = ::com::sun::star::chart; |
| namespace cssc2 = ::com::sun::star::chart2; |
| |
| // Helpers ==================================================================== |
| |
| namespace { |
| |
| XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect ) |
| { |
| return rStrm >> rRect.mnX >> rRect.mnY >> rRect.mnWidth >> rRect.mnHeight; |
| } |
| |
| inline void lclSetValueOrClearAny( Any& rAny, double fValue, bool bClear ) |
| { |
| if( bClear ) |
| rAny.clear(); |
| else |
| rAny <<= fValue; |
| } |
| |
| void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear ) |
| { |
| if( !bClear && bLogScale ) |
| fValue = pow( 10.0, fValue ); |
| lclSetValueOrClearAny( rAny, fValue, bClear ); |
| } |
| |
| double lclGetSerialDay( const XclImpRoot& rRoot, sal_uInt16 nValue, sal_uInt16 nTimeUnit ) |
| { |
| switch( nTimeUnit ) |
| { |
| case EXC_CHDATERANGE_DAYS: |
| return nValue; |
| case EXC_CHDATERANGE_MONTHS: |
| return rRoot.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16 >( 1 + nValue % 12 ), static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue / 12 ) ) ); |
| case EXC_CHDATERANGE_YEARS: |
| return rRoot.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue ) ) ); |
| default: |
| OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" ); |
| } |
| return nValue; |
| } |
| |
| void lclConvertTimeValue( const XclImpRoot& rRoot, Any& rAny, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit ) |
| { |
| if( bAuto ) |
| rAny.clear(); |
| else |
| rAny <<= lclGetSerialDay( rRoot, nValue, nTimeUnit ); |
| } |
| |
| sal_Int32 lclGetApiTimeUnit( sal_uInt16 nTimeUnit ) |
| { |
| switch( nTimeUnit ) |
| { |
| case EXC_CHDATERANGE_DAYS: return cssc::TimeUnit::DAY; |
| case EXC_CHDATERANGE_MONTHS: return cssc::TimeUnit::MONTH; |
| case EXC_CHDATERANGE_YEARS: return cssc::TimeUnit::YEAR; |
| default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" ); |
| } |
| return cssc::TimeUnit::DAY; |
| } |
| |
| void lclConvertTimeInterval( Any& rInterval, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit ) |
| { |
| if( bAuto || (nValue == 0) ) |
| rInterval.clear(); |
| else |
| rInterval <<= cssc::TimeInterval( nValue, lclGetApiTimeUnit( nTimeUnit ) ); |
| } |
| |
| } // namespace |
| |
| // Common ===================================================================== |
| |
| /** Stores global data needed in various classes of the Chart import filter. */ |
| struct XclImpChRootData : public XclChRootData |
| { |
| XclImpChChart& mrChartData; /// The chart data object. |
| |
| inline explicit XclImpChRootData( XclImpChChart& rChartData ) : mrChartData( rChartData ) {} |
| }; |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart& rChartData ) : |
| XclImpRoot( rRoot ), |
| mxChData( new XclImpChRootData( rChartData ) ) |
| { |
| } |
| |
| XclImpChRoot::~XclImpChRoot() |
| { |
| } |
| |
| XclImpChChart& XclImpChRoot::GetChartData() const |
| { |
| return mxChData->mrChartData; |
| } |
| |
| const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const |
| { |
| return mxChData->mxTypeInfoProv->GetTypeInfo( eType ); |
| } |
| |
| const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const |
| { |
| return mxChData->mxTypeInfoProv->GetTypeInfoFromRecId( nRecId ); |
| } |
| |
| const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const |
| { |
| return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType ); |
| } |
| |
| Color XclImpChRoot::GetFontAutoColor() const |
| { |
| return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT ); |
| } |
| |
| Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const |
| { |
| return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) ); |
| } |
| |
| Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const |
| { |
| const XclImpPalette& rPal = GetPalette(); |
| Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) ); |
| sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx ); |
| return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans ); |
| } |
| |
| void XclImpChRoot::InitConversion( Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) const |
| { |
| // create formatting object tables |
| mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect ); |
| |
| // lock the model to suppress any internal updates |
| Reference< XModel > xModel( xChartDoc, UNO_QUERY ); |
| if( xModel.is() ) |
| xModel->lockControllers(); |
| |
| SfxObjectShell* pDocShell = GetDocShell(); |
| Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY ); |
| if( pDocShell && xDataRec.is() ) |
| { |
| // create and register a data provider |
| Reference< XDataProvider > xDataProv( |
| ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY ); |
| if( xDataProv.is() ) |
| xDataRec->attachDataProvider( xDataProv ); |
| // attach the number formatter |
| Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY ); |
| if( xNumFmtSupp.is() ) |
| xDataRec->attachNumberFormatsSupplier( xNumFmtSupp ); |
| } |
| } |
| |
| void XclImpChRoot::FinishConversion( XclImpDffConverter& rDffConv ) const |
| { |
| rDffConv.Progress( EXC_CHART_PROGRESS_SIZE ); |
| // unlock the model |
| Reference< XModel > xModel( mxChData->mxChartDoc, UNO_QUERY ); |
| if( xModel.is() ) |
| xModel->unlockControllers(); |
| rDffConv.Progress( EXC_CHART_PROGRESS_SIZE ); |
| |
| mxChData->FinishConversion(); |
| } |
| |
| Reference< XDataProvider > XclImpChRoot::GetDataProvider() const |
| { |
| return mxChData->mxChartDoc->getDataProvider(); |
| } |
| |
| Reference< XShape > XclImpChRoot::GetTitleShape( const XclChTextKey& rTitleKey ) const |
| { |
| return mxChData->GetTitleShape( rTitleKey ); |
| } |
| |
| sal_Int32 XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX ) const |
| { |
| return static_cast< sal_Int32 >( mxChData->mfUnitSizeX * nPosX + mxChData->mnBorderGapX + 0.5 ); |
| } |
| |
| sal_Int32 XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY ) const |
| { |
| return static_cast< sal_Int32 >( mxChData->mfUnitSizeY * nPosY + mxChData->mnBorderGapY + 0.5 ); |
| } |
| |
| ::com::sun::star::awt::Rectangle XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle& rRect ) const |
| { |
| return ::com::sun::star::awt::Rectangle( |
| CalcHmmFromChartX( rRect.mnX ), |
| CalcHmmFromChartY( rRect.mnY ), |
| CalcHmmFromChartX( rRect.mnWidth ), |
| CalcHmmFromChartY( rRect.mnHeight ) ); |
| } |
| |
| double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX ) const |
| { |
| return static_cast< double >( nPosX ) / mxChData->maChartRect.GetWidth(); |
| } |
| |
| double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY ) const |
| { |
| return static_cast< double >( nPosY ) / mxChData->maChartRect.GetHeight(); |
| } |
| |
| double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX ) const |
| { |
| return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX ) ); |
| } |
| |
| double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY ) const |
| { |
| return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY ) ); |
| } |
| |
| void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet, |
| const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const |
| { |
| GetChartPropSetHelper().WriteLineProperties( |
| rPropSet, *mxChData->mxLineDashTable, rLineFmt, ePropMode ); |
| } |
| |
| void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet, |
| const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const |
| { |
| GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode ); |
| } |
| |
| void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet, |
| const XclChEscherFormat& rEscherFmt, const XclChPicFormat* pPicFmt, |
| sal_uInt32 nDffFillType, XclChPropertyMode ePropMode ) const |
| { |
| GetChartPropSetHelper().WriteEscherProperties( rPropSet, |
| *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, |
| rEscherFmt, pPicFmt, nDffFillType, ePropMode ); |
| } |
| |
| void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet, |
| sal_uInt16 nFontIdx, const Color* pFontColor ) const |
| { |
| GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor ); |
| } |
| |
| void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle ) |
| { |
| sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360; |
| rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChGroupBase::~XclImpChGroupBase() |
| { |
| } |
| |
| void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm ) |
| { |
| // read contents of the header record |
| ReadHeaderRecord( rStrm ); |
| |
| // only read sub records, if the next record is a CHBEGIN |
| if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN ) |
| { |
| // read the CHBEGIN record, may be used for special initial processing |
| rStrm.StartNextRecord(); |
| ReadSubRecord( rStrm ); |
| |
| // read the nested records |
| bool bLoop = true; |
| while( bLoop && rStrm.StartNextRecord() ) |
| { |
| sal_uInt16 nRecId = rStrm.GetRecId(); |
| bLoop = nRecId != EXC_ID_CHEND; |
| // skip unsupported nested blocks |
| if( nRecId == EXC_ID_CHBEGIN ) |
| SkipBlock( rStrm ); |
| else |
| ReadSubRecord( rStrm ); |
| } |
| } |
| /* Returns with current CHEND record or unchanged stream, if no record |
| group present. In every case another call to StartNextRecord() will go |
| to next record of interest. */ |
| } |
| |
| void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm ) |
| { |
| DBG_ASSERT( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" ); |
| // do nothing if current record is not CHBEGIN |
| bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN; |
| while( bLoop && rStrm.StartNextRecord() ) |
| { |
| sal_uInt16 nRecId = rStrm.GetRecId(); |
| bLoop = nRecId != EXC_ID_CHEND; |
| // skip nested record groups |
| if( nRecId == EXC_ID_CHBEGIN ) |
| SkipBlock( rStrm ); |
| } |
| } |
| |
| // Frame formatting =========================================================== |
| |
| void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnTLMode >> maData.mnBRMode; |
| /* According to the spec, the upper 16 bits of all members in the |
| rectangle are unused and may contain garbage. */ |
| maData.maRect.mnX = rStrm.ReadInt16(); rStrm.Ignore( 2 ); |
| maData.maRect.mnY = rStrm.ReadInt16(); rStrm.Ignore( 2 ); |
| maData.maRect.mnWidth = rStrm.ReadInt16(); rStrm.Ignore( 2 ); |
| maData.maRect.mnHeight = rStrm.ReadInt16(); rStrm.Ignore( 2 ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.maColor >> maData.mnPattern >> maData.mnWeight >> maData.mnFlags; |
| |
| const XclImpRoot& rRoot = rStrm.GetRoot(); |
| if( rRoot.GetBiff() == EXC_BIFF8 ) |
| // #116397# BIFF8: index into palette used instead of RGB data |
| maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() ); |
| } |
| |
| void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const |
| { |
| const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); |
| if( IsAuto() ) |
| { |
| XclChLineFormat aLineFmt; |
| aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ? |
| rRoot.GetSeriesLineAutoColor( nFormatIdx ) : |
| rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx ); |
| aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; |
| aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight; |
| rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode ); |
| } |
| else |
| { |
| rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode ); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.maPattColor >> maData.maBackColor >> maData.mnPattern >> maData.mnFlags; |
| |
| const XclImpRoot& rRoot = rStrm.GetRoot(); |
| if( rRoot.GetBiff() == EXC_BIFF8 ) |
| { |
| // #116397# BIFF8: index into palette used instead of RGB data |
| const XclImpPalette& rPal = rRoot.GetPalette(); |
| maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() ); |
| maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16()); |
| } |
| } |
| |
| void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const |
| { |
| const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); |
| if( IsAuto() ) |
| { |
| XclChAreaFormat aAreaFmt; |
| aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ? |
| rRoot.GetSeriesFillAutoColor( nFormatIdx ) : |
| rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx ); |
| aAreaFmt.mnPattern = EXC_PATT_SOLID; |
| rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode ); |
| } |
| else |
| { |
| rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode ); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot ) : |
| mnDffFillType( mso_fillSolid ) |
| { |
| maData.mxItemSet.reset( |
| new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) ); |
| } |
| |
| void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| // read from stream - CHESCHERFORMAT uses own ID for record continuation |
| XclImpDffPropSet aPropSet( rStrm.GetRoot() ); |
| rStrm.ResetRecord( true, rStrm.GetRecId() ); |
| rStrm >> aPropSet; |
| // get the data |
| aPropSet.FillToItemSet( *maData.mxItemSet ); |
| // get fill type from DFF property set |
| mnDffFillType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid ); |
| } |
| |
| void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHPICFORMAT: |
| rStrm >> maPicFmt.mnBmpMode; |
| rStrm.Ignore( 2 ); |
| rStrm >> maPicFmt.mnFlags >> maPicFmt.mfScale; |
| break; |
| } |
| } |
| |
| void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, bool bUsePicFmt ) const |
| { |
| const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); |
| rRoot.ConvertEscherFormat( rPropSet, maData, bUsePicFmt ? &maPicFmt : 0, mnDffFillType, rFmtInfo.mePropMode ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo ) |
| { |
| if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType ) |
| { |
| case EXC_CHFRAMETYPE_AUTO: |
| mxLineFmt.reset( new XclImpChLineFormat ); |
| if( rFmtInfo.mbIsFrame ) |
| mxAreaFmt.reset( new XclImpChAreaFormat ); |
| break; |
| case EXC_CHFRAMETYPE_INVISIBLE: |
| { |
| XclChLineFormat aLineFmt; |
| ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false ); |
| aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; |
| mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) ); |
| if( rFmtInfo.mbIsFrame ) |
| { |
| XclChAreaFormat aAreaFmt; |
| ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false ); |
| aAreaFmt.mnPattern = EXC_PATT_NONE; |
| mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) ); |
| } |
| } |
| break; |
| default: |
| DBG_ERRORFILE( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" ); |
| } |
| } |
| |
| void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHLINEFORMAT: |
| mxLineFmt.reset( new XclImpChLineFormat ); |
| mxLineFmt->ReadChLineFormat( rStrm ); |
| break; |
| case EXC_ID_CHAREAFORMAT: |
| mxAreaFmt.reset( new XclImpChAreaFormat ); |
| mxAreaFmt->ReadChAreaFormat( rStrm ); |
| break; |
| case EXC_ID_CHESCHERFORMAT: |
| mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) ); |
| mxEscherFmt->ReadRecordGroup( rStrm ); |
| break; |
| } |
| } |
| |
| void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const |
| { |
| if( mxLineFmt.is() ) |
| mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx ); |
| } |
| |
| void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const |
| { |
| if( rRoot.GetFormatInfo( eObjType ).mbIsFrame ) |
| { |
| // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto) |
| if( mxEscherFmt.is() ) |
| mxEscherFmt->Convert( rRoot, rPropSet, eObjType, bUsePicFmt ); |
| else if( mxAreaFmt.is() ) |
| mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx ); |
| } |
| } |
| |
| void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const |
| { |
| ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx ); |
| ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx, bUsePicFmt ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) : |
| XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ), |
| XclImpChRoot( rRoot ), |
| meObjType( eObjType ) |
| { |
| } |
| |
| void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnFormat >> maData.mnFlags; |
| } |
| |
| void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData ) |
| { |
| const XclImpPalette& rPal = GetPalette(); |
| |
| if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) ) |
| { |
| // line formatting |
| XclChLineFormat aLineFmt; |
| aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx ); |
| switch( rLineData.mnStyle ) |
| { |
| case EXC_OBJ_LINE_SOLID: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; break; |
| case EXC_OBJ_LINE_DASH: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH; break; |
| case EXC_OBJ_LINE_DOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT; break; |
| case EXC_OBJ_LINE_DASHDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT; break; |
| case EXC_OBJ_LINE_DASHDOTDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT; break; |
| case EXC_OBJ_LINE_MEDTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS; break; |
| case EXC_OBJ_LINE_DARKTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS; break; |
| case EXC_OBJ_LINE_LIGHTTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS; break; |
| case EXC_OBJ_LINE_NONE: aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; break; |
| default: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; |
| } |
| switch( rLineData.mnWidth ) |
| { |
| case EXC_OBJ_LINE_HAIR: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; break; |
| case EXC_OBJ_LINE_THIN: aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE; break; |
| case EXC_OBJ_LINE_MEDIUM: aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE; break; |
| case EXC_OBJ_LINE_THICK: aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE; break; |
| default: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; |
| } |
| ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() ); |
| mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) ); |
| } |
| |
| if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt ) |
| { |
| // area formatting |
| XclChAreaFormat aAreaFmt; |
| aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx ); |
| aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx ); |
| aAreaFmt.mnPattern = rFillData.mnPattern; |
| ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() ); |
| mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) ); |
| } |
| } |
| |
| void XclImpChFrame::Convert( ScfPropertySet& rPropSet, bool bUsePicFmt ) const |
| { |
| ConvertFrameBase( GetChRoot(), rPropSet, meObjType, EXC_CHDATAFORMAT_UNKNOWN, bUsePicFmt ); |
| } |
| |
| // Source links =============================================================== |
| |
| namespace { |
| |
| /** Creates a labeled data sequence object, adds link for series title if present. */ |
| Reference< XLabeledDataSequence > lclCreateLabeledDataSequence( |
| XclImpChSourceLinkRef xValueLink, const OUString& rValueRole, |
| const XclImpChSourceLink* pTitleLink = 0 ) |
| { |
| // create data sequence for values and title |
| Reference< XDataSequence > xValueSeq; |
| if( xValueLink.is() ) |
| xValueSeq = xValueLink->CreateDataSequence( rValueRole ); |
| Reference< XDataSequence > xTitleSeq; |
| if( pTitleLink ) |
| xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL ); |
| |
| // create the labeled data sequence, if values or title are present |
| Reference< XLabeledDataSequence > xLabeledSeq; |
| if( xValueSeq.is() || xTitleSeq.is() ) |
| xLabeledSeq.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LABELEDDATASEQ ), UNO_QUERY ); |
| if( xLabeledSeq.is() ) |
| { |
| if( xValueSeq.is() ) |
| xLabeledSeq->setValues( xValueSeq ); |
| if( xTitleSeq.is() ) |
| xLabeledSeq->setLabel( xTitleSeq ); |
| } |
| return xLabeledSeq; |
| } |
| |
| } // namespace |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| XclImpChSourceLink::~XclImpChSourceLink() |
| { |
| } |
| |
| void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnDestType |
| >> maData.mnLinkType |
| >> maData.mnFlags |
| >> maData.mnNumFmtIdx; |
| |
| mxTokenArray.reset(); |
| if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET ) |
| { |
| // read token array |
| XclTokenArray aXclTokArr; |
| rStrm >> aXclTokArr; |
| |
| // convert BIFF formula tokens to Calc token array |
| if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) ) |
| mxTokenArray.reset( pTokens->Clone() ); |
| } |
| |
| // try to read a following CHSTRING record |
| if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() ) |
| { |
| mxString.reset( new XclImpString ); |
| rStrm.Ignore( 2 ); |
| mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS ); |
| } |
| } |
| |
| void XclImpChSourceLink::SetString( const String& rString ) |
| { |
| if( !mxString ) |
| mxString.reset( new XclImpString ); |
| mxString->SetText( rString ); |
| } |
| |
| void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats ) |
| { |
| if( mxString.is() ) |
| mxString->SetFormats( rFormats ); |
| } |
| |
| sal_uInt16 XclImpChSourceLink::GetCellCount() const |
| { |
| sal_uInt32 nCellCount = 0; |
| if( mxTokenArray.is() ) |
| { |
| mxTokenArray->Reset(); |
| for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() ) |
| { |
| switch( pToken->GetType() ) |
| { |
| case ::formula::svSingleRef: |
| case ::formula::svExternalSingleRef: |
| // single cell |
| ++nCellCount; |
| break; |
| case ::formula::svDoubleRef: |
| case ::formula::svExternalDoubleRef: |
| { |
| // cell range |
| const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef(); |
| const ScSingleRefData& rRef1 = rComplexRef.Ref1; |
| const ScSingleRefData& rRef2 = rComplexRef.Ref2; |
| sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 ); |
| sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 ); |
| sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 ); |
| nCellCount += nCols * nRows * nTabs; |
| } |
| break; |
| default: ; |
| } |
| } |
| } |
| return limit_cast< sal_uInt16 >( nCellCount ); |
| } |
| |
| void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const |
| { |
| bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT ); |
| sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND; |
| OUString aPropName = bPercent ? EXC_CHPROP_PERCENTAGENUMFMT : EXC_CHPROP_NUMBERFORMAT; |
| if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND ) |
| rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) ); |
| else |
| // restore 'link to source' at data point (series may contain manual number format) |
| rPropSet.SetAnyProperty( aPropName, Any() ); |
| } |
| |
| Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const |
| { |
| Reference< XDataSequence > xDataSeq; |
| Reference< XDataProvider > xDataProv = GetDataProvider(); |
| if( xDataProv.is() && mxTokenArray.is() ) |
| { |
| ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray ); |
| aComp.SetGrammar( ::formula::FormulaGrammar::GRAM_ENGLISH ); |
| OUStringBuffer aRangeRep; |
| aComp.CreateStringFromTokenArray( aRangeRep ); |
| try |
| { |
| xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() ); |
| // set sequence role |
| ScfPropertySet aSeqProp( xDataSeq ); |
| aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole ); |
| } |
| catch( Exception& ) |
| { |
| // DBG_ERRORFILE( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" ); |
| } |
| } |
| return xDataSeq; |
| } |
| |
| Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence( |
| const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const |
| { |
| ::std::vector< Reference< XFormattedString > > aStringVec; |
| if( mxString.is() ) |
| { |
| for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt ) |
| { |
| Reference< XFormattedString > xFmtStr( |
| ScfApiHelper::CreateInstance( SERVICE_CHART2_FORMATTEDSTRING ), UNO_QUERY ); |
| if( xFmtStr.is() ) |
| { |
| // set text data |
| xFmtStr->setString( aIt.GetPortionText() ); |
| |
| // set font formatting and font color |
| ScfPropertySet aStringProp( xFmtStr ); |
| sal_uInt16 nFontIdx = aIt.GetPortionFont(); |
| if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) ) |
| // leading unformatted portion - use passed font settings |
| rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor ); |
| else |
| rRoot.ConvertFont( aStringProp, nFontIdx ); |
| |
| // add string to vector of strings |
| aStringVec.push_back( xFmtStr ); |
| } |
| } |
| } |
| return ScfApiHelper::VectorToSequence( aStringVec ); |
| } |
| |
| void XclImpChSourceLink::FillSourceLink( ::std::vector< ScSharedTokenRef >& rTokens ) const |
| { |
| if( !mxTokenArray.is() ) |
| // no links to fill. |
| return; |
| |
| mxTokenArray->Reset(); |
| for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next()) |
| { |
| ScSharedTokenRef pToken(static_cast<ScToken*>(p->Clone())); |
| if (ScRefTokenHelper::isRef(pToken)) |
| // This is a reference token. Store it. |
| ScRefTokenHelper::join(rTokens, pToken); |
| } |
| } |
| |
| // Text ======================================================================= |
| |
| XclImpChFontBase::~XclImpChFontBase() |
| { |
| } |
| |
| void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const |
| { |
| Color aFontColor = GetFontColor(); |
| rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor ); |
| } |
| |
| void XclImpChFontBase::ConvertRotationBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet, bool bSupportsStacked ) const |
| { |
| rRoot.GetChartPropSetHelper().WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChFont::XclImpChFont() : |
| mnFontIdx( EXC_FONT_NOTFOUND ) |
| { |
| } |
| |
| void XclImpChFont::ReadChFont( XclImpStream& rStrm ) |
| { |
| rStrm >> mnFontIdx; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnHAlign |
| >> maData.mnVAlign |
| >> maData.mnBackMode |
| >> maData.maTextColor |
| >> maData.maRect |
| >> maData.mnFlags; |
| |
| if( GetBiff() == EXC_BIFF8 ) |
| { |
| // #116397# BIFF8: index into palette used instead of RGB data |
| maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() ); |
| // placement and rotation |
| rStrm >> maData.mnFlags2 >> maData.mnRotation; |
| } |
| else |
| { |
| // BIFF2-BIFF7: get rotation from text orientation |
| sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 ); |
| maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient ); |
| } |
| } |
| |
| void XclImpChText::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHFRAMEPOS: |
| mxFramePos.reset( new XclImpChFramePos ); |
| mxFramePos->ReadChFramePos( rStrm ); |
| break; |
| case EXC_ID_CHFONT: |
| mxFont.reset( new XclImpChFont ); |
| mxFont->ReadChFont( rStrm ); |
| break; |
| case EXC_ID_CHFORMATRUNS: |
| if( GetBiff() == EXC_BIFF8 ) |
| XclImpString::ReadFormats( rStrm, maFormats ); |
| break; |
| case EXC_ID_CHSOURCELINK: |
| mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) ); |
| mxSrcLink->ReadChSourceLink( rStrm ); |
| break; |
| case EXC_ID_CHFRAME: |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) ); |
| mxFrame->ReadRecordGroup( rStrm ); |
| break; |
| case EXC_ID_CHOBJECTLINK: |
| rStrm >> maObjLink.mnTarget >> maObjLink.maPointPos.mnSeriesIdx >> maObjLink.maPointPos.mnPointIdx; |
| break; |
| case EXC_ID_CHFRLABELPROPS: |
| ReadChFrLabelProps( rStrm ); |
| break; |
| case EXC_ID_CHEND: |
| if( mxSrcLink.is() && !maFormats.empty() ) |
| mxSrcLink->SetTextFormats( maFormats ); |
| break; |
| } |
| } |
| |
| sal_uInt16 XclImpChText::GetFontIndex() const |
| { |
| return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND; |
| } |
| |
| Color XclImpChText::GetFontColor() const |
| { |
| return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor; |
| } |
| |
| sal_uInt16 XclImpChText::GetRotation() const |
| { |
| return maData.mnRotation; |
| } |
| |
| void XclImpChText::SetString( const String& rString ) |
| { |
| if( !mxSrcLink ) |
| mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) ); |
| mxSrcLink->SetString( rString ); |
| } |
| |
| void XclImpChText::UpdateText( const XclImpChText* pParentText ) |
| { |
| if( pParentText ) |
| { |
| // update missing members |
| if( !mxFrame ) |
| mxFrame = pParentText->mxFrame; |
| if( !mxFont ) |
| { |
| mxFont = pParentText->mxFont; |
| // text color is taken from CHTEXT record, not from font in CHFONT |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ); |
| maData.maTextColor = pParentText->maData.maTextColor; |
| } |
| } |
| } |
| |
| void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent ) |
| { |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bCateg ); |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bValue ); |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bPercent ); |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent ); |
| ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bCateg && !bValue && !bPercent ); |
| } |
| |
| void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const |
| { |
| ConvertFontBase( GetChRoot(), rPropSet ); |
| } |
| |
| void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const |
| { |
| ConvertRotationBase( GetChRoot(), rPropSet, bSupportsStacked ); |
| } |
| |
| void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const |
| { |
| if( mxFrame.is() ) |
| mxFrame->Convert( rPropSet ); |
| } |
| |
| void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const |
| { |
| if( mxSrcLink.is() ) |
| mxSrcLink->ConvertNumFmt( rPropSet, bPercent ); |
| } |
| |
| void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const |
| { |
| // existing CHFRLABELPROPS record wins over flags from CHTEXT |
| sal_uInt16 nShowFlags = mxLabelProps.is() ? mxLabelProps->mnFlags : maData.mnFlags; |
| sal_uInt16 SHOWANYCATEG = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG); |
| sal_uInt16 SHOWANYVALUE = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE; |
| sal_uInt16 SHOWANYPERCENT = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC); |
| sal_uInt16 SHOWANYBUBBLE = mxLabelProps.is() ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE; |
| |
| // get raw flags for label values |
| bool bShowNone = IsDeleted(); |
| bool bShowCateg = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG ); |
| bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT ); |
| bool bShowValue = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE ); |
| bool bShowBubble = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE ); |
| |
| // adjust to Chart2 behaviour |
| if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES ) |
| bShowValue = bShowBubble; // Chart2 bubble charts show bubble size if 'ShowValue' is set |
| |
| // other flags |
| bool bShowAny = bShowValue || bShowPercent || bShowCateg; |
| bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL ); |
| |
| // create API struct for label values, set API label separator |
| cssc2::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol ); |
| rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel ); |
| String aSep = mxLabelProps.is() ? mxLabelProps->maSeparator : String( sal_Unicode( '\n' ) ); |
| if( aSep.Len() == 0 ) |
| aSep = CREATE_STRING( "; " ); |
| rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep ); |
| |
| // text properties of attached label |
| if( bShowAny ) |
| { |
| ConvertFont( rPropSet ); |
| ConvertRotation( rPropSet, false ); |
| // label placement |
| using namespace cssc::DataLabelPlacement; |
| sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos; |
| switch( ::extract_value< sal_uInt16 >( maData.mnFlags2, 0, 4 ) ) |
| { |
| case EXC_CHTEXT_POS_DEFAULT: nPlacement = rTypeInfo.mnDefaultLabelPos; break; |
| case EXC_CHTEXT_POS_OUTSIDE: nPlacement = OUTSIDE; break; |
| case EXC_CHTEXT_POS_INSIDE: nPlacement = INSIDE; break; |
| case EXC_CHTEXT_POS_CENTER: nPlacement = CENTER; break; |
| case EXC_CHTEXT_POS_AXIS: nPlacement = NEAR_ORIGIN; break; |
| case EXC_CHTEXT_POS_ABOVE: nPlacement = TOP; break; |
| case EXC_CHTEXT_POS_BELOW: nPlacement = BOTTOM; break; |
| case EXC_CHTEXT_POS_LEFT: nPlacement = LEFT; break; |
| case EXC_CHTEXT_POS_RIGHT: nPlacement = RIGHT; break; |
| case EXC_CHTEXT_POS_AUTO: nPlacement = AVOID_OVERLAP; break; |
| } |
| rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement ); |
| // label number format (percentage format wins over value format) |
| if( bShowPercent || bShowValue ) |
| ConvertNumFmt( rPropSet, bShowPercent ); |
| } |
| } |
| |
| Reference< XTitle > XclImpChText::CreateTitle() const |
| { |
| Reference< XTitle > xTitle; |
| if( mxSrcLink.is() && mxSrcLink->HasString() ) |
| { |
| // create the formatted strings |
| Sequence< Reference< XFormattedString > > aStringSeq( |
| mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) ); |
| if( aStringSeq.hasElements() ) |
| { |
| // create the title object |
| xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY ); |
| if( xTitle.is() ) |
| { |
| // set the formatted strings |
| xTitle->setText( aStringSeq ); |
| // more title formatting properties |
| ScfPropertySet aTitleProp( xTitle ); |
| ConvertFrame( aTitleProp ); |
| ConvertRotation( aTitleProp, true ); |
| } |
| } |
| } |
| return xTitle; |
| } |
| |
| void XclImpChText::ConvertTitlePosition( const XclChTextKey& rTitleKey ) const |
| { |
| if( !mxFramePos ) return; |
| |
| const XclChFramePos& rPosData = mxFramePos->GetFramePosData(); |
| OSL_ENSURE( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rPosData.mnBRMode == EXC_CHFRAMEPOS_PARENT), |
| "XclImpChText::ConvertTitlePosition - unexpected frame position mode" ); |
| |
| /* Check if title is moved manually. To get the actual position of the |
| title, we do some kind of hack and use the values from the CHTEXT |
| record, effectively ignoring the contents of the CHFRAMEPOS record |
| which contains the position relative to the default title position |
| (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record). |
| Especially when it comes to axis titles, things would become very |
| complicated here, because the relative title position is stored in a |
| measurement unit that is dependent on the size of the inner plot area, |
| the interpretation of the X and Y coordinate is dependent on the |
| direction of the axis, and in 3D charts, and the title default |
| positions are dependent on the 3D view settings (rotation, elevation, |
| and perspective). Thus, it is easier to assume that the creator has |
| written out the correct absolute position and size of the title in the |
| CHTEXT record. This is assured by checking that the shape size stored |
| in the CHTEXT record is non-zero. */ |
| if( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && |
| ((rPosData.maRect.mnX != 0) || (rPosData.maRect.mnY != 0)) && |
| (maData.maRect.mnWidth > 0) && (maData.maRect.mnHeight > 0) ) try |
| { |
| Reference< XShape > xTitleShape( GetTitleShape( rTitleKey ), UNO_SET_THROW ); |
| // the call to XShape.getSize() may recalc the chart view |
| ::com::sun::star::awt::Size aTitleSize = xTitleShape->getSize(); |
| // rotated titles need special handling... |
| sal_Int32 nScRot = XclTools::GetScRotation( GetRotation(), 0 ); |
| double fRad = nScRot * F_PI18000; |
| double fSin = fabs( sin( fRad ) ); |
| double fCos = fabs( cos( fRad ) ); |
| ::com::sun::star::awt::Size aBoundSize( |
| static_cast< sal_Int32 >( fCos * aTitleSize.Width + fSin * aTitleSize.Height + 0.5 ), |
| static_cast< sal_Int32 >( fSin * aTitleSize.Width + fCos * aTitleSize.Height + 0.5 ) ); |
| // calculate the title position from the values in the CHTEXT record |
| ::com::sun::star::awt::Point aTitlePos( |
| CalcHmmFromChartX( maData.maRect.mnX ), |
| CalcHmmFromChartY( maData.maRect.mnY ) ); |
| // add part of height to X direction, if title is rotated down (clockwise) |
| if( nScRot > 18000 ) |
| aTitlePos.X += static_cast< sal_Int32 >( fSin * aTitleSize.Height + 0.5 ); |
| // add part of width to Y direction, if title is rotated up (counterclockwise) |
| else if( nScRot > 0 ) |
| aTitlePos.Y += static_cast< sal_Int32 >( fSin * aTitleSize.Width + 0.5 ); |
| // set the resulting position at the title shape |
| xTitleShape->setPosition( aTitlePos ); |
| } |
| catch( Exception& ) |
| { |
| } |
| } |
| |
| void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm ) |
| { |
| if( GetBiff() == EXC_BIFF8 ) |
| { |
| mxLabelProps.reset( new XclChFrLabelProps ); |
| sal_uInt16 nSepLen; |
| rStrm.Ignore( 12 ); |
| rStrm >> mxLabelProps->mnFlags >> nSepLen; |
| if( nSepLen > 0 ) |
| mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen ); |
| } |
| } |
| |
| namespace { |
| |
| void lclUpdateText( XclImpChTextRef& rxText, XclImpChTextRef xDefText ) |
| { |
| if( rxText.is() ) |
| rxText->UpdateText( xDefText.get() ); |
| else |
| rxText = xDefText; |
| } |
| |
| void lclFinalizeTitle( XclImpChTextRef& rxTitle, XclImpChTextRef xDefText, const String& rAutoTitle ) |
| { |
| /* Do not update a title, if it is not visible (if rxTitle is null). |
| Existing reference indicates enabled title. */ |
| if( rxTitle.is() ) |
| { |
| if( !rxTitle->HasString() ) |
| rxTitle->SetString( rAutoTitle ); |
| if( rxTitle->HasString() ) |
| rxTitle->UpdateText( xDefText.get() ); |
| else |
| rxTitle.reset(); |
| } |
| } |
| |
| } // namespace |
| |
| // Data series ================================================================ |
| |
| void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.maLineColor >> maData.maFillColor >> maData.mnMarkerType >> maData.mnFlags; |
| |
| const XclImpRoot& rRoot = rStrm.GetRoot(); |
| if( rRoot.GetBiff() == EXC_BIFF8 ) |
| { |
| // #116397# BIFF8: index into palette used instead of RGB data |
| const XclImpPalette& rPal = rRoot.GetPalette(); |
| maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() ); |
| maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() ); |
| // marker size |
| rStrm >> maData.mnMarkerSize; |
| } |
| } |
| |
| void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const |
| { |
| if( IsAuto() ) |
| { |
| XclChMarkerFormat aMarkerFmt; |
| // line and fill color of the symbol are equal to series line color |
| //! TODO: Excel sets no fill color for specific symbols (e.g. cross) |
| aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx ); |
| switch( nLineWeight ) |
| { |
| case EXC_CHLINEFORMAT_HAIR: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE; break; |
| case EXC_CHLINEFORMAT_SINGLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; break; |
| case EXC_CHLINEFORMAT_DOUBLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; break; |
| case EXC_CHLINEFORMAT_TRIPLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE; break; |
| default: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; |
| } |
| aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx ); |
| rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, aMarkerFmt ); |
| } |
| else |
| { |
| rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, maData ); |
| } |
| } |
| |
| void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot, |
| ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const |
| { |
| Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor; |
| rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChPieFormat::XclImpChPieFormat() : |
| mnPieDist( 0 ) |
| { |
| } |
| |
| void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> mnPieDist; |
| } |
| |
| void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const |
| { |
| double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 ); |
| rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChSeriesFormat::XclImpChSeriesFormat() : |
| mnFlags( 0 ) |
| { |
| } |
| |
| void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> mnFlags; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnBase >> maData.mnTop; |
| } |
| |
| void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const |
| { |
| using namespace ::com::sun::star::chart2::DataPointGeometry3D; |
| sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ? |
| ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) : |
| ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE); |
| rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ), |
| mnFlags( 0 ) |
| { |
| } |
| |
| void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm ) |
| { |
| rStrm >> mnFlags; |
| } |
| |
| XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( XclImpChTextRef xParent ) const |
| { |
| const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE; |
| const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC; |
| const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC; |
| |
| XclImpChTextRef xLabel( xParent.is() ? new XclImpChText( *xParent ) : new XclImpChText( GetChRoot() ) ); |
| xLabel->UpdateDataLabel( |
| ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ), |
| ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ), |
| ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) ); |
| return xLabel; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.maPointPos.mnPointIdx |
| >> maData.maPointPos.mnSeriesIdx |
| >> maData.mnFormatIdx |
| >> maData.mnFlags; |
| } |
| |
| void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHMARKERFORMAT: |
| mxMarkerFmt.reset( new XclImpChMarkerFormat ); |
| mxMarkerFmt->ReadChMarkerFormat( rStrm ); |
| break; |
| case EXC_ID_CHPIEFORMAT: |
| mxPieFmt.reset( new XclImpChPieFormat ); |
| mxPieFmt->ReadChPieFormat( rStrm ); |
| break; |
| case EXC_ID_CHSERIESFORMAT: |
| mxSeriesFmt.reset( new XclImpChSeriesFormat ); |
| mxSeriesFmt->ReadChSeriesFormat( rStrm ); |
| break; |
| case EXC_ID_CH3DDATAFORMAT: |
| mx3dDataFmt.reset( new XclImpCh3dDataFormat ); |
| mx3dDataFmt->ReadCh3dDataFormat( rStrm ); |
| break; |
| case EXC_ID_CHATTACHEDLABEL: |
| mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) ); |
| mxAttLabel->ReadChAttachedLabel( rStrm ); |
| break; |
| default: |
| XclImpChFrameBase::ReadSubRecord( rStrm ); |
| } |
| } |
| |
| void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) |
| { |
| maData.maPointPos = rPointPos; |
| maData.mnFormatIdx = nFormatIdx; |
| } |
| |
| void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo ) |
| { |
| // remove formats not used for the current chart type |
| RemoveUnusedFormats( rTypeInfo ); |
| } |
| |
| void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt ) |
| { |
| // update missing formats from passed chart type group format |
| if( pGroupFmt ) |
| { |
| if( !mxLineFmt ) |
| mxLineFmt = pGroupFmt->mxLineFmt; |
| if( !mxAreaFmt && !mxEscherFmt ) |
| { |
| mxAreaFmt = pGroupFmt->mxAreaFmt; |
| mxEscherFmt = pGroupFmt->mxEscherFmt; |
| } |
| if( !mxMarkerFmt ) |
| mxMarkerFmt = pGroupFmt->mxMarkerFmt; |
| if( !mxPieFmt ) |
| mxPieFmt = pGroupFmt->mxPieFmt; |
| if( !mxSeriesFmt ) |
| mxSeriesFmt = pGroupFmt->mxSeriesFmt; |
| if( !mx3dDataFmt ) |
| mx3dDataFmt = pGroupFmt->mx3dDataFmt; |
| if( !mxAttLabel ) |
| mxAttLabel = pGroupFmt->mxAttLabel; |
| } |
| |
| /* Create missing but required formats. Existing line, area, and marker |
| format objects are needed to create automatic series formatting. */ |
| if( !mxLineFmt ) |
| mxLineFmt.reset( new XclImpChLineFormat ); |
| if( !mxAreaFmt && !mxEscherFmt ) |
| mxAreaFmt.reset( new XclImpChAreaFormat ); |
| if( !mxMarkerFmt ) |
| mxMarkerFmt.reset( new XclImpChMarkerFormat ); |
| |
| // remove formats not used for the current chart type |
| RemoveUnusedFormats( rTypeInfo ); |
| // update data label |
| UpdateDataLabel( pGroupFmt ); |
| } |
| |
| void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt ) |
| { |
| // remove formats if they are automatic in this and in the passed series format |
| if( pSeriesFmt ) |
| { |
| if( IsAutoLine() && pSeriesFmt->IsAutoLine() ) |
| mxLineFmt.reset(); |
| if( IsAutoArea() && pSeriesFmt->IsAutoArea() ) |
| mxAreaFmt.reset(); |
| if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() ) |
| mxMarkerFmt.reset(); |
| mxSeriesFmt.reset(); |
| } |
| |
| // Excel ignores 3D bar format for single data points |
| mx3dDataFmt.reset(); |
| // remove point line formats for linear chart types, TODO: implement in OOChart |
| if( !rTypeInfo.IsSeriesFrameFormat() ) |
| mxLineFmt.reset(); |
| |
| // remove formats not used for the current chart type |
| RemoveUnusedFormats( rTypeInfo ); |
| // update data label |
| UpdateDataLabel( pSeriesFmt ); |
| } |
| |
| void XclImpChDataFormat::UpdateTrendLineFormat() |
| { |
| if( !mxLineFmt ) |
| mxLineFmt.reset( new XclImpChLineFormat ); |
| mxAreaFmt.reset(); |
| mxEscherFmt.reset(); |
| mxMarkerFmt.reset(); |
| mxPieFmt.reset(); |
| mxSeriesFmt.reset(); |
| mx3dDataFmt.reset(); |
| mxAttLabel.reset(); |
| // update data label |
| UpdateDataLabel( 0 ); |
| } |
| |
| void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const |
| { |
| /* Line and area format. |
| #i71810# If the data points are filled with bitmaps, textures, or |
| patterns, then only bar charts will use the CHPICFORMAT record to |
| determine stacking/streching mode. All other chart types ignore this |
| record and always use the property 'fill-type' from the DFF property |
| set (streched for bitmaps, and stacked for textures and patterns). */ |
| bool bUsePicFmt = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR; |
| ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx, bUsePicFmt ); |
| |
| #if EXC_CHART2_3DBAR_HAIRLINES_ONLY |
| // #i83151# only hair lines in 3D charts with filled data points |
| if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt.is() && mxLineFmt->HasLine() ) |
| rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "BorderWidth" ), 0 ); |
| #endif |
| |
| // other formatting |
| if( mxMarkerFmt.is() ) |
| mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() ); |
| if( mxPieFmt.is() ) |
| mxPieFmt->Convert( rPropSet ); |
| if( mx3dDataFmt.is() ) |
| mx3dDataFmt->Convert( rPropSet ); |
| if( mxLabel.is() ) |
| mxLabel->ConvertDataLabel( rPropSet, rTypeInfo ); |
| |
| // 3D settings |
| rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 ); |
| |
| /* Special case: set marker color as line color, if series line is not |
| visible. This makes the color visible in the marker area. |
| TODO: remove this if OOChart supports own colors in markers. */ |
| if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt.is() ) |
| mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx ); |
| } |
| |
| void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const |
| { |
| ConvertLineBase( GetChRoot(), rPropSet, eObjType ); |
| } |
| |
| void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, bool bUsePicFmt ) const |
| { |
| ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx, bUsePicFmt ); |
| } |
| |
| void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo ) |
| { |
| // data point marker only in linear 2D charts |
| if( rTypeInfo.IsSeriesFrameFormat() ) |
| mxMarkerFmt.reset(); |
| // pie format only in pie/donut charts |
| if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE ) |
| mxPieFmt.reset(); |
| // 3D format only in 3D bar charts |
| if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) ) |
| mx3dDataFmt.reset(); |
| } |
| |
| void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt ) |
| { |
| /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL |
| records. Only if there is a CHATTACHEDLABEL record without a CHTEXT |
| group, the contents of the CHATTACHEDLABEL record are used. In this |
| case a new CHTEXT group is created and filled with the settings from |
| the CHATTACHEDLABEL record. */ |
| XclImpChTextRef xDefText; |
| if( pParentFmt ) |
| xDefText = pParentFmt->GetDataLabel(); |
| if( !xDefText ) |
| xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL ); |
| if( mxLabel.is() ) |
| mxLabel->UpdateText( xDefText.get() ); |
| else if( mxAttLabel.is() ) |
| mxLabel = mxAttLabel->CreateDataLabel( xDefText ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnLineType |
| >> maData.mnOrder |
| >> maData.mfIntercept |
| >> maData.mnShowEquation |
| >> maData.mnShowRSquared |
| >> maData.mfForecastFor |
| >> maData.mfForecastBack; |
| } |
| |
| Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const |
| { |
| // trend line type |
| OUString aService; |
| switch( maData.mnLineType ) |
| { |
| case EXC_CHSERTREND_POLYNOMIAL: |
| // TODO: only linear trend lines are supported by OOChart (#i20819#) |
| if( maData.mnOrder == 1 ) |
| aService = SERVICE_CHART2_LINEARREGCURVE; |
| break; |
| case EXC_CHSERTREND_EXPONENTIAL: |
| aService = SERVICE_CHART2_EXPREGCURVE; |
| break; |
| case EXC_CHSERTREND_LOGARITHMIC: |
| aService = SERVICE_CHART2_LOGREGCURVE; |
| break; |
| case EXC_CHSERTREND_POWER: |
| aService = SERVICE_CHART2_POTREGCURVE; |
| break; |
| } |
| Reference< XRegressionCurve > xRegCurve; |
| if( aService.getLength() > 0 ) |
| xRegCurve.set( ScfApiHelper::CreateInstance( aService ), UNO_QUERY ); |
| |
| // trend line formatting |
| if( xRegCurve.is() && mxDataFmt.is() ) |
| { |
| ScfPropertySet aPropSet( xRegCurve ); |
| mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE ); |
| |
| // #i83100# show equation and correlation coefficient |
| ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() ); |
| aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 ); |
| aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 ); |
| |
| // #i83100# formatting of the equation text box |
| if( const XclImpChText* pLabel = mxDataFmt->GetDataLabel().get() ) |
| { |
| pLabel->ConvertFont( aLabelProp ); |
| pLabel->ConvertFrame( aLabelProp ); |
| pLabel->ConvertNumFmt( aLabelProp, false ); |
| } |
| } |
| |
| // missing features |
| // #i20819# polynomial trend lines |
| // #i66819# moving average trend lines |
| // #i5085# manual trend line size |
| // #i34093# manual crossing point |
| |
| return xRegCurve; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnBarType >> maData.mnSourceType >> maData.mnLineEnd; |
| rStrm.Ignore( 1 ); |
| rStrm >> maData.mfValue >> maData.mnValueCount; |
| } |
| |
| void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef xValueLink, XclImpChDataFormatRef xDataFmt ) |
| { |
| mxValueLink = xValueLink; |
| mxDataFmt = xDataFmt; |
| } |
| |
| Reference< XLabeledDataSequence > XclImpChSerErrorBar::CreateValueSequence() const |
| { |
| return lclCreateLabeledDataSequence( mxValueLink, XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ) ); |
| } |
| |
| Reference< XPropertySet > XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar* pPosBar, const XclImpChSerErrorBar* pNegBar ) |
| { |
| Reference< XPropertySet > xErrorBar; |
| |
| if( const XclImpChSerErrorBar* pPrimaryBar = pPosBar ? pPosBar : pNegBar ) |
| { |
| xErrorBar.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR ), UNO_QUERY ); |
| ScfPropertySet aBarProp( xErrorBar ); |
| |
| // plus/minus bars visible? |
| aBarProp.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR, pPosBar != 0 ); |
| aBarProp.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR, pNegBar != 0 ); |
| |
| // type of displayed error |
| switch( pPrimaryBar->maData.mnSourceType ) |
| { |
| case EXC_CHSERERR_PERCENT: |
| aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::RELATIVE ); |
| aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue ); |
| aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue ); |
| break; |
| case EXC_CHSERERR_FIXED: |
| aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::ABSOLUTE ); |
| aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue ); |
| aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue ); |
| break; |
| case EXC_CHSERERR_STDDEV: |
| aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_DEVIATION ); |
| aBarProp.SetProperty( EXC_CHPROP_WEIGHT, pPrimaryBar->maData.mfValue ); |
| break; |
| case EXC_CHSERERR_STDERR: |
| aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_ERROR ); |
| break; |
| case EXC_CHSERERR_CUSTOM: |
| { |
| aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::FROM_DATA ); |
| // attach data sequences to erorr bar |
| Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY ); |
| if( xDataSink.is() ) |
| { |
| // create vector of all value sequences |
| ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; |
| // add positive values |
| if( pPosBar ) |
| { |
| Reference< XLabeledDataSequence > xValueSeq = pPosBar->CreateValueSequence(); |
| if( xValueSeq.is() ) |
| aLabeledSeqVec.push_back( xValueSeq ); |
| } |
| // add negative values |
| if( pNegBar ) |
| { |
| Reference< XLabeledDataSequence > xValueSeq = pNegBar->CreateValueSequence(); |
| if( xValueSeq.is() ) |
| aLabeledSeqVec.push_back( xValueSeq ); |
| } |
| // attach labeled data sequences to series |
| if( aLabeledSeqVec.empty() ) |
| xErrorBar.clear(); |
| else |
| xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) ); |
| } |
| } |
| break; |
| default: |
| xErrorBar.clear(); |
| } |
| |
| // error bar formatting |
| if( pPrimaryBar->mxDataFmt.is() && xErrorBar.is() ) |
| pPrimaryBar->mxDataFmt->ConvertLine( aBarProp, EXC_CHOBJTYPE_ERRORBAR ); |
| } |
| |
| return xErrorBar; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) : |
| XclImpChRoot( rRoot ), |
| mnGroupIdx( EXC_CHSERGROUP_NONE ), |
| mnSeriesIdx( nSeriesIdx ), |
| mnParentIdx( EXC_CHSERIES_INVALID ) |
| { |
| } |
| |
| void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnCategType >> maData.mnValueType >> maData.mnCategCount >> maData.mnValueCount; |
| if( GetBiff() == EXC_BIFF8 ) |
| rStrm >> maData.mnBubbleType >> maData.mnBubbleCount; |
| } |
| |
| void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHSOURCELINK: |
| ReadChSourceLink( rStrm ); |
| break; |
| case EXC_ID_CHDATAFORMAT: |
| ReadChDataFormat( rStrm ); |
| break; |
| case EXC_ID_CHSERGROUP: |
| rStrm >> mnGroupIdx; |
| break; |
| case EXC_ID_CHSERPARENT: |
| ReadChSerParent( rStrm ); |
| break; |
| case EXC_ID_CHSERTRENDLINE: |
| ReadChSerTrendLine( rStrm ); |
| break; |
| case EXC_ID_CHSERERRORBAR: |
| ReadChSerErrorBar( rStrm ); |
| break; |
| } |
| } |
| |
| void XclImpChSeries::SetDataFormat( XclImpChDataFormatRef xDataFmt ) |
| { |
| if( xDataFmt.is() ) |
| { |
| XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( xDataFmt->GetPointPos().mnPointIdx ); |
| // do not overwrite existing data format |
| if( pxDataFmt && !*pxDataFmt ) |
| { |
| *pxDataFmt = xDataFmt; |
| // #i51639# register series format index at chart type group |
| if( (pxDataFmt == &mxSeriesFmt) && !HasParentSeries() ) |
| if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() ) |
| pTypeGroup->SetUsedFormatIndex( xDataFmt->GetFormatIdx() ); |
| } |
| } |
| } |
| |
| void XclImpChSeries::SetDataLabel( XclImpChTextRef xLabel ) |
| { |
| if( xLabel.is() ) |
| { |
| XclImpChTextRef* pxLabel = GetDataLabelRef( xLabel->GetPointPos().mnPointIdx ); |
| if( pxLabel && !*pxLabel ) |
| *pxLabel = xLabel; |
| } |
| } |
| |
| void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries ) |
| { |
| DBG_ASSERT( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" ); |
| |
| /* In Excel, trend lines and error bars are stored as own series. In Calc, |
| these are properties of the parent series. This function adds the |
| settings of the passed series to this series. */ |
| maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() ); |
| maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() ); |
| } |
| |
| void XclImpChSeries::FinalizeDataFormats() |
| { |
| if( HasParentSeries() ) |
| { |
| // *** series is a child series, e.g. trend line or error bar *** |
| |
| // create missing series format |
| if( !mxSeriesFmt ) |
| mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 ); |
| |
| if( mxSeriesFmt.is() ) |
| { |
| // #i83100# set text label format, e.g. for trend line equations |
| mxSeriesFmt->SetDataLabel( maLabels.get( EXC_CHDATAFORMAT_ALLPOINTS ) ); |
| // create missing automatic formats |
| mxSeriesFmt->UpdateTrendLineFormat(); |
| } |
| |
| // copy series formatting to child objects |
| for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt ) |
| (*aLIt)->SetDataFormat( mxSeriesFmt ); |
| for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt ) |
| aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt ); |
| } |
| else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() ) |
| { |
| // *** series is a regular data series *** |
| |
| // create missing series format |
| if( !mxSeriesFmt ) |
| { |
| // #i51639# use a new unused format index to create series default format |
| sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex(); |
| mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx ); |
| } |
| |
| // set text labels to data formats |
| for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt ) |
| { |
| if( XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( aTIt->first ) ) |
| { |
| if( !*pxDataFmt ) |
| *pxDataFmt = CreateDataFormat( aTIt->first, EXC_CHDATAFORMAT_DEFAULT ); |
| (*pxDataFmt)->SetDataLabel( aTIt->second ); |
| } |
| } |
| |
| // update series format (copy missing formatting from group default format) |
| if( mxSeriesFmt.is() ) |
| mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() ); |
| |
| // update data point formats (removes unchanged automatic formatting) |
| for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt ) |
| aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() ); |
| } |
| } |
| |
| namespace { |
| |
| /** Returns the property set of the specified data point. */ |
| ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx ) |
| { |
| ScfPropertySet aPropSet; |
| try |
| { |
| aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" ); |
| } |
| return aPropSet; |
| } |
| |
| } // namespace |
| |
| Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const |
| { |
| return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() ); |
| } |
| |
| Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const |
| { |
| return lclCreateLabeledDataSequence( mxCategLink, rCategRole ); |
| } |
| |
| Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const |
| { |
| Reference< XDataSeries > xDataSeries; |
| if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() ) |
| { |
| const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo(); |
| |
| // create the data series object |
| xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY ); |
| |
| // attach data and title sequences to series |
| Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY ); |
| if( xDataSink.is() ) |
| { |
| // create vector of all value sequences |
| ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; |
| // add Y values |
| Reference< XLabeledDataSequence > xYValueSeq = |
| CreateValueSequence( EXC_CHPROP_ROLE_YVALUES ); |
| if( xYValueSeq.is() ) |
| aLabeledSeqVec.push_back( xYValueSeq ); |
| // add X values |
| if( !rTypeInfo.mbCategoryAxis ) |
| { |
| Reference< XLabeledDataSequence > xXValueSeq = |
| CreateCategSequence( EXC_CHPROP_ROLE_XVALUES ); |
| if( xXValueSeq.is() ) |
| aLabeledSeqVec.push_back( xXValueSeq ); |
| // add size values of bubble charts |
| if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES ) |
| { |
| Reference< XLabeledDataSequence > xSizeValueSeq = |
| lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() ); |
| if( xSizeValueSeq.is() ) |
| aLabeledSeqVec.push_back( xSizeValueSeq ); |
| } |
| } |
| // attach labeled data sequences to series |
| if( !aLabeledSeqVec.empty() ) |
| xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) ); |
| } |
| |
| // series formatting |
| ScfPropertySet aSeriesProp( xDataSeries ); |
| if( mxSeriesFmt.is() ) |
| mxSeriesFmt->Convert( aSeriesProp, rTypeInfo ); |
| |
| // trend lines |
| ConvertTrendLines( xDataSeries ); |
| |
| // error bars |
| Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS ); |
| if( xErrorBarX.is() ) |
| aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX ); |
| Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS ); |
| if( xErrorBarY.is() ) |
| aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY ); |
| |
| // own area formatting for every data point (TODO: varying line color not supported) |
| bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat(); |
| #if EXC_CHART2_VARYCOLORSBY_PROP |
| aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt ); |
| #else |
| aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE ); |
| #endif |
| // #i91271# always set area formatting for every point in pie/doughnut charts |
| if( mxSeriesFmt.is() && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)) ) |
| { |
| for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx ) |
| { |
| ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx ); |
| mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx, false ); |
| } |
| } |
| |
| // data point formatting |
| for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt ) |
| { |
| ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first ); |
| aIt->second->Convert( aPointProp, rTypeInfo ); |
| } |
| } |
| return xDataSeries; |
| } |
| |
| void XclImpChSeries::FillAllSourceLinks( ::std::vector< ScSharedTokenRef >& rTokens ) const |
| { |
| if( mxValueLink.is() ) |
| mxValueLink->FillSourceLink( rTokens ); |
| if( mxCategLink.is() ) |
| mxCategLink->FillSourceLink( rTokens ); |
| if( mxTitleLink.is() ) |
| mxTitleLink->FillSourceLink( rTokens ); |
| if( mxBubbleLink.is() ) |
| mxBubbleLink->FillSourceLink( rTokens ); |
| } |
| |
| void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm ) |
| { |
| XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) ); |
| xSrcLink->ReadChSourceLink( rStrm ); |
| switch( xSrcLink->GetDestType() ) |
| { |
| case EXC_CHSRCLINK_TITLE: mxTitleLink = xSrcLink; break; |
| case EXC_CHSRCLINK_VALUES: mxValueLink = xSrcLink; break; |
| case EXC_CHSRCLINK_CATEGORY: mxCategLink = xSrcLink; break; |
| case EXC_CHSRCLINK_BUBBLES: mxBubbleLink = xSrcLink; break; |
| } |
| } |
| |
| void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm ) |
| { |
| // #i51639# chart stores all data formats and assigns them later to the series |
| GetChartData().ReadChDataFormat( rStrm ); |
| } |
| |
| void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm ) |
| { |
| rStrm >> mnParentIdx; |
| // index to parent series is 1-based, convert it to 0-based |
| if( mnParentIdx > 0 ) |
| --mnParentIdx; |
| else |
| mnParentIdx = EXC_CHSERIES_INVALID; |
| } |
| |
| void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm ) |
| { |
| XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) ); |
| xTrendLine->ReadChSerTrendLine( rStrm ); |
| maTrendLines.push_back( xTrendLine ); |
| } |
| |
| void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm ) |
| { |
| XclImpChSerErrorBarRef xErrorBar( new XclImpChSerErrorBar( GetChRoot() ) ); |
| xErrorBar->ReadChSerErrorBar( rStrm ); |
| maErrorBars[ xErrorBar->GetBarType() ] = xErrorBar; |
| } |
| |
| XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx ) |
| { |
| XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) ); |
| xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx ); |
| return xDataFmt; |
| } |
| |
| XclImpChDataFormatRef* XclImpChSeries::GetDataFormatRef( sal_uInt16 nPointIdx ) |
| { |
| if( nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS ) |
| return &mxSeriesFmt; |
| if( nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT ) |
| return &maPointFmts[ nPointIdx ]; |
| return 0; |
| } |
| |
| XclImpChTextRef* XclImpChSeries::GetDataLabelRef( sal_uInt16 nPointIdx ) |
| { |
| if( (nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS) || (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT) ) |
| return &maLabels[ nPointIdx ]; |
| return 0; |
| } |
| |
| void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const |
| { |
| Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY ); |
| if( xRegCurveCont.is() ) |
| { |
| for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt ) |
| { |
| try |
| { |
| Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve(); |
| if( xRegCurve.is() ) |
| xRegCurveCont->addRegressionCurve( xRegCurve ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" ); |
| } |
| } |
| } |
| } |
| |
| Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const |
| { |
| return XclImpChSerErrorBar::CreateErrorBar( maErrorBars.get( nPosBarId ).get(), maErrorBars.get( nNegBarId ).get() ); |
| } |
| |
| // Chart type groups ========================================================== |
| |
| XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ), |
| mnRecId( EXC_ID_CHUNKNOWN ), |
| maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) ) |
| { |
| } |
| |
| void XclImpChType::ReadChType( XclImpStream& rStrm ) |
| { |
| sal_uInt16 nRecId = rStrm.GetRecId(); |
| bool bKnownType = true; |
| |
| switch( nRecId ) |
| { |
| case EXC_ID_CHBAR: |
| rStrm >> maData.mnOverlap >> maData.mnGap >> maData.mnFlags; |
| break; |
| |
| case EXC_ID_CHLINE: |
| case EXC_ID_CHAREA: |
| case EXC_ID_CHRADARLINE: |
| case EXC_ID_CHRADARAREA: |
| rStrm >> maData.mnFlags; |
| break; |
| |
| case EXC_ID_CHPIE: |
| rStrm >> maData.mnRotation >> maData.mnPieHole; |
| if( GetBiff() == EXC_BIFF8 ) |
| rStrm >> maData.mnFlags; |
| else |
| maData.mnFlags = 0; |
| break; |
| |
| case EXC_ID_CHPIEEXT: |
| maData.mnRotation = 0; |
| maData.mnPieHole = 0; |
| maData.mnFlags = 0; |
| break; |
| |
| case EXC_ID_CHSCATTER: |
| if( GetBiff() == EXC_BIFF8 ) |
| rStrm >> maData.mnBubbleSize >> maData.mnBubbleType >> maData.mnFlags; |
| else |
| maData.mnFlags = 0; |
| break; |
| |
| case EXC_ID_CHSURFACE: |
| rStrm >> maData.mnFlags; |
| break; |
| |
| default: |
| bKnownType = false; |
| } |
| |
| if( bKnownType ) |
| mnRecId = nRecId; |
| } |
| |
| void XclImpChType::Finalize( bool bStockChart ) |
| { |
| switch( mnRecId ) |
| { |
| case EXC_ID_CHLINE: |
| maTypeInfo = GetChartTypeInfo( bStockChart ? |
| EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE ); |
| break; |
| case EXC_ID_CHBAR: |
| maTypeInfo = GetChartTypeInfo( ::get_flagvalue( |
| maData.mnFlags, EXC_CHBAR_HORIZONTAL, |
| EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) ); |
| break; |
| case EXC_ID_CHPIE: |
| maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ? |
| EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE ); |
| break; |
| case EXC_ID_CHSCATTER: |
| maTypeInfo = GetChartTypeInfo( ::get_flagvalue( |
| maData.mnFlags, EXC_CHSCATTER_BUBBLES, |
| EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) ); |
| break; |
| default: |
| maTypeInfo = GetChartTypeInfo( mnRecId ); |
| } |
| |
| switch( maTypeInfo.meTypeId ) |
| { |
| case EXC_CHTYPEID_PIEEXT: |
| case EXC_CHTYPEID_BUBBLES: |
| case EXC_CHTYPEID_SURFACE: |
| case EXC_CHTYPEID_UNKNOWN: |
| GetTracer().TraceChartUnKnownType(); |
| break; |
| default:; |
| } |
| } |
| |
| bool XclImpChType::IsStacked() const |
| { |
| bool bStacked = false; |
| if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg ) |
| { |
| case EXC_CHTYPECATEG_LINE: |
| bStacked = |
| ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) && |
| !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT ); |
| break; |
| case EXC_CHTYPECATEG_BAR: |
| bStacked = |
| ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) && |
| !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT ); |
| break; |
| default:; |
| } |
| return bStacked; |
| } |
| |
| bool XclImpChType::IsPercent() const |
| { |
| bool bPercent = false; |
| if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg ) |
| { |
| case EXC_CHTYPECATEG_LINE: |
| bPercent = |
| ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) && |
| ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT ); |
| break; |
| case EXC_CHTYPECATEG_BAR: |
| bPercent = |
| ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) && |
| ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT ); |
| break; |
| default:; |
| } |
| return bPercent; |
| } |
| |
| bool XclImpChType::HasCategoryLabels() const |
| { |
| // radar charts disable category labels in chart type, not in CHTICK of X axis |
| return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS ); |
| } |
| |
| Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const |
| { |
| // service name |
| OUString aCoordSysService; |
| if( maTypeInfo.mbPolarCoordSystem ) |
| { |
| if( b3dChart ) |
| aCoordSysService = SERVICE_CHART2_POLARCOORDSYS3D; |
| else |
| aCoordSysService = SERVICE_CHART2_POLARCOORDSYS2D; |
| } |
| else |
| { |
| if( b3dChart ) |
| aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS3D; |
| else |
| aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS2D; |
| } |
| |
| // create the coordinate system object |
| Reference< XCoordinateSystem > xCoordSystem( ScfApiHelper::CreateInstance( aCoordSysService ), UNO_QUERY ); |
| |
| // swap X and Y axis |
| if( maTypeInfo.mbSwappedAxesSet ) |
| { |
| ScfPropertySet aCoordSysProp( xCoordSystem ); |
| aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true ); |
| } |
| |
| return xCoordSystem; |
| } |
| |
| Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const |
| { |
| OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName ); |
| Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY ); |
| |
| // additional properties |
| switch( maTypeInfo.meTypeCateg ) |
| { |
| case EXC_CHTYPECATEG_BAR: |
| { |
| ScfPropertySet aTypeProp( xChartType ); |
| Sequence< sal_Int32 > aInt32Seq( 2 ); |
| aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap; |
| aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq ); |
| aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap; |
| aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq ); |
| } |
| break; |
| case EXC_CHTYPECATEG_PIE: |
| { |
| ScfPropertySet aTypeProp( xChartType ); |
| aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT ); |
| /* #i85166# starting angle of first pie slice. 3D pie charts use Y |
| rotation setting in view3D element. Of-pie charts do not |
| support pie rotation. */ |
| if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) ) |
| { |
| ScfPropertySet aDiaProp( xDiagram ); |
| XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation ); |
| } |
| } |
| break; |
| default:; |
| } |
| |
| return xChartType; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnRotation |
| >> maData.mnElevation |
| >> maData.mnEyeDist |
| >> maData.mnRelHeight |
| >> maData.mnRelDepth |
| >> maData.mnDepthGap |
| >> maData.mnFlags; |
| } |
| |
| void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const |
| { |
| namespace cssd = ::com::sun::star::drawing; |
| |
| // #i104057# do not assert this, written by broken external generators |
| // DBG_ASSERT( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" ); |
| |
| sal_Int32 nRotationY = 0; |
| sal_Int32 nRotationX = 0; |
| sal_Int32 nPerspective = 15; |
| bool bRightAngled = false; |
| cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE; |
| Color aAmbientColor, aLightColor; |
| |
| if( b3dWallChart ) |
| { |
| // Y rotation (Excel [0..359], Chart2 [-179,180]) |
| nRotationY = maData.mnRotation % 360; |
| if( nRotationY > 180 ) nRotationY -= 360; |
| // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180]) |
| nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 ); |
| // perspective (Excel and Chart2 [0,100]) |
| nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 ); |
| // right-angled axes |
| bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D ); |
| // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%) |
| bool bParallel = bRightAngled || (nPerspective == 0); |
| eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE; |
| // ambient color (Gray 20%) |
| aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) ); |
| // light color (Gray 60%) |
| aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) ); |
| } |
| else |
| { |
| // Y rotation not used in pie charts, but 'first pie slice angle' |
| nRotationY = 0; |
| XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation ); |
| // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10]) |
| nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90; |
| // perspective (Excel and Chart2 [0,100]) |
| nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 ); |
| // no right-angled axes in pie charts, but parallel projection |
| bRightAngled = false; |
| eProjMode = cssd::ProjectionMode_PARALLEL; |
| // ambient color (Gray 30%) |
| aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) ); |
| // light color (Gray 70%) |
| aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) ); |
| } |
| |
| // properties |
| rPropSet.SetProperty( EXC_CHPROP_3DRELATIVEHEIGHT, (sal_Int32)(maData.mnRelHeight / 2)); // seems to be 200%, cange to 100% |
| rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY ); |
| rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX ); |
| rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective ); |
| rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled ); |
| rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode ); |
| |
| // light settings |
| rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT ); |
| rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor ); |
| rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false ); |
| rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true ); |
| rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor ); |
| rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.maRect >> maData.mnDockMode >> maData.mnSpacing >> maData.mnFlags; |
| |
| // trace unsupported features |
| if( GetTracer().IsEnabled() ) |
| { |
| if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED ) |
| GetTracer().TraceChartLegendPosition(); |
| if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) ) |
| GetTracer().TraceChartDataTable(); |
| } |
| } |
| |
| void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHFRAMEPOS: |
| mxFramePos.reset( new XclImpChFramePos ); |
| mxFramePos->ReadChFramePos( rStrm ); |
| break; |
| case EXC_ID_CHTEXT: |
| mxText.reset( new XclImpChText( GetChRoot() ) ); |
| mxText->ReadRecordGroup( rStrm ); |
| break; |
| case EXC_ID_CHFRAME: |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) ); |
| mxFrame->ReadRecordGroup( rStrm ); |
| break; |
| } |
| } |
| |
| void XclImpChLegend::Finalize() |
| { |
| // legend default formatting differs in OOChart and Excel, missing frame means automatic |
| if( !mxFrame ) |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) ); |
| // Update text formatting. If mxText is empty, the passed default text is used. |
| lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) ); |
| } |
| |
| Reference< XLegend > XclImpChLegend::CreateLegend() const |
| { |
| Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY ); |
| if( xLegend.is() ) |
| { |
| ScfPropertySet aLegendProp( xLegend ); |
| aLegendProp.SetBoolProperty( EXC_CHPROP_SHOW, true ); |
| |
| // frame properties |
| if( mxFrame.is() ) |
| mxFrame->Convert( aLegendProp ); |
| // text properties |
| if( mxText.is() ) |
| mxText->ConvertFont( aLegendProp ); |
| |
| /* Legend position and size. Default positions are used only if the |
| plot area is positioned automatically (Excel sets the plot area to |
| manual mode, if the legend is moved or resized). With manual plot |
| areas, Excel ignores the value in maData.mnDockMode completely. */ |
| cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM; |
| cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM; |
| if( !GetChartData().IsManualPlotArea() ) switch( maData.mnDockMode ) |
| { |
| case EXC_CHLEGEND_LEFT: |
| eApiPos = cssc2::LegendPosition_LINE_START; |
| eApiExpand = cssc::ChartLegendExpansion_HIGH; |
| break; |
| case EXC_CHLEGEND_RIGHT: |
| // top-right not supported |
| case EXC_CHLEGEND_CORNER: |
| eApiPos = cssc2::LegendPosition_LINE_END; |
| eApiExpand = cssc::ChartLegendExpansion_HIGH; |
| break; |
| case EXC_CHLEGEND_TOP: |
| eApiPos = cssc2::LegendPosition_PAGE_START; |
| eApiExpand = cssc::ChartLegendExpansion_WIDE; |
| break; |
| case EXC_CHLEGEND_BOTTOM: |
| eApiPos = cssc2::LegendPosition_PAGE_END; |
| eApiExpand = cssc::ChartLegendExpansion_WIDE; |
| break; |
| } |
| |
| // no automatic position/size: try to find the correct position and size |
| if( eApiPos == cssc2::LegendPosition_CUSTOM ) |
| { |
| const XclChFramePos* pFramePos = mxFramePos.is() ? &mxFramePos->GetFramePosData() : 0; |
| |
| /* Legend position. Only the settings from the CHFRAMEPOS record |
| are used by Excel, the position in the CHLEGEND record will be |
| ignored. */ |
| if( pFramePos ) |
| { |
| RelativePosition aRelPos( |
| CalcRelativeFromChartX( pFramePos->maRect.mnX ), |
| CalcRelativeFromChartY( pFramePos->maRect.mnY ), |
| ::com::sun::star::drawing::Alignment_TOP_LEFT ); |
| aLegendProp.SetProperty( EXC_CHPROP_RELATIVEPOSITION, aRelPos ); |
| } |
| else |
| { |
| // no manual position/size found, just go for the default |
| eApiPos = cssc2::LegendPosition_LINE_END; |
| } |
| |
| /* Legend size. The member mnBRMode specifies whether size is |
| automatic or changes manually. Manual size is given in points, |
| not in chart units. */ |
| if( pFramePos && (pFramePos->mnBRMode == EXC_CHFRAMEPOS_ABSSIZE_POINTS) && |
| (pFramePos->maRect.mnWidth > 0) && (pFramePos->maRect.mnHeight > 0) ) |
| { |
| eApiExpand = cssc::ChartLegendExpansion_CUSTOM; |
| sal_Int32 nWidthHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnWidth / EXC_POINTS_PER_HMM ); |
| sal_Int32 nHeightHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnHeight / EXC_POINTS_PER_HMM ); |
| RelativeSize aRelSize( CalcRelativeFromHmmX( nWidthHmm ), CalcRelativeFromHmmY( nHeightHmm ) ); |
| aLegendProp.SetProperty( EXC_CHPROP_RELATIVESIZE, aRelSize ); |
| } |
| else |
| { |
| // automatic size: determine entry direction from flags |
| eApiExpand = ::get_flagvalue( maData.mnFlags, EXC_CHLEGEND_STACKED, |
| cssc::ChartLegendExpansion_HIGH, cssc::ChartLegendExpansion_WIDE ); |
| } |
| } |
| aLegendProp.SetProperty( EXC_CHPROP_ANCHORPOSITION, eApiPos ); |
| aLegendProp.SetProperty( EXC_CHPROP_EXPANSION, eApiExpand ); |
| } |
| return xLegend; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) : |
| mnDropBar( nDropBar ), |
| mnBarDist( 0 ) |
| { |
| } |
| |
| void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> mnBarDist; |
| } |
| |
| void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const |
| { |
| XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND; |
| switch( mnDropBar ) |
| { |
| case EXC_CHDROPBAR_UP: eObjType = EXC_CHOBJTYPE_WHITEDROPBAR; break; |
| case EXC_CHDROPBAR_DOWN: eObjType = EXC_CHOBJTYPE_BLACKDROPBAR; break; |
| } |
| ConvertFrameBase( rRoot, rPropSet, eObjType ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ), |
| maType( rRoot ), |
| maTypeInfo( maType.GetTypeInfo() ) |
| { |
| // Initialize unused format indexes set. At this time, all formats are unused. |
| for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx ) |
| maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx ); |
| } |
| |
| void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm.Ignore( 16 ); |
| rStrm >> maData.mnFlags >> maData.mnGroupIdx; |
| } |
| |
| void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHCHART3D: |
| mxChart3d.reset( new XclImpChChart3d ); |
| mxChart3d->ReadChChart3d( rStrm ); |
| break; |
| case EXC_ID_CHLEGEND: |
| mxLegend.reset( new XclImpChLegend( GetChRoot() ) ); |
| mxLegend->ReadRecordGroup( rStrm ); |
| break; |
| case EXC_ID_CHDEFAULTTEXT: |
| GetChartData().ReadChDefaultText( rStrm ); |
| break; |
| case EXC_ID_CHDROPBAR: |
| ReadChDropBar( rStrm ); |
| break; |
| case EXC_ID_CHCHARTLINE: |
| ReadChChartLine( rStrm ); |
| break; |
| case EXC_ID_CHDATAFORMAT: |
| ReadChDataFormat( rStrm ); |
| break; |
| default: |
| maType.ReadChType( rStrm ); |
| } |
| } |
| |
| void XclImpChTypeGroup::Finalize() |
| { |
| // check and set valid chart type |
| bool bStockChart = |
| (maType.GetRecId() == EXC_ID_CHLINE) && // must be a line chart |
| !mxChart3d && // must be a 2d chart |
| HasHiLoLine() && // must contain hi-lo lines |
| (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3)); // correct series count |
| maType.Finalize( bStockChart ); |
| |
| // extended type info |
| maTypeInfo.Set( maType.GetTypeInfo(), mxChart3d.is(), false ); |
| |
| // reverse series order for some unstacked 2D chart types |
| if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() ) |
| ::std::reverse( maSeries.begin(), maSeries.end() ); |
| |
| // update chart type group format, may depend on chart type finalized above |
| if( mxGroupFmt.is() ) |
| mxGroupFmt->UpdateGroupFormat( maTypeInfo ); |
| } |
| |
| void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries ) |
| { |
| if( xSeries.is() ) |
| maSeries.push_back( xSeries ); |
| // store first inserted series separately, series order may be reversed later |
| if( !mxFirstSeries ) |
| mxFirstSeries = xSeries; |
| } |
| |
| void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx ) |
| { |
| maUnusedFormats.erase( nFormatIdx ); |
| } |
| |
| sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex() |
| { |
| DBG_ASSERT( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" ); |
| sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin(); |
| SetUsedFormatIndex( nFormatIdx ); |
| return nFormatIdx; |
| } |
| |
| bool XclImpChTypeGroup::HasVarPointFormat() const |
| { |
| return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) && |
| ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) || // multiple series allowed |
| ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) && // or exactly 1 series? |
| (maSeries.size() == 1))); |
| } |
| |
| bool XclImpChTypeGroup::HasConnectorLines() const |
| { |
| // existence of connector lines (only in stacked bar charts) |
| bool bAnyStacked = maType.IsStacked() || maType.IsPercent(); |
| XclImpChLineFormatRef xConnLine = maChartLines.get( EXC_CHCHARTLINE_CONNECT ); |
| return bAnyStacked && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) && xConnLine.is() && xConnLine->HasLine(); |
| } |
| |
| const String& XclImpChTypeGroup::GetSingleSeriesTitle() const |
| { |
| // no automatic title for series with trendlines or error bars |
| // pie charts always show an automatic title, even if more series exist |
| return (mxFirstSeries.is() && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ? |
| mxFirstSeries->GetTitle() : String::EmptyString(); |
| } |
| |
| void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const |
| { |
| if( mxChart3d.is() ) |
| mxChart3d->Convert( rPropSet, Is3dWallChart() ); |
| } |
| |
| Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const |
| { |
| return maType.CreateCoordSystem( Is3dChart() ); |
| } |
| |
| Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const |
| { |
| DBG_ASSERT( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" ); |
| |
| // create the chart type object |
| Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() ); |
| |
| // bar chart connector lines |
| if( HasConnectorLines() ) |
| { |
| ScfPropertySet aDiaProp( xDiagram ); |
| aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true ); |
| } |
| |
| /* Stock chart needs special processing. Create one 'big' series with |
| data sequences of different roles. */ |
| if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK ) |
| CreateStockSeries( xChartType, nApiAxesSetIdx ); |
| else |
| CreateDataSeries( xChartType, nApiAxesSetIdx ); |
| |
| return xChartType; |
| } |
| |
| Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const |
| { |
| Reference< XLabeledDataSequence > xLabeledSeq; |
| // create category sequence from first visible series |
| if( mxFirstSeries.is() ) |
| xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG ); |
| return xLabeledSeq; |
| } |
| |
| void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm ) |
| { |
| sal_uInt16 nDropBar = EXC_CHDROPBAR_NONE; |
| if( !maDropBars.has( EXC_CHDROPBAR_UP ) ) |
| nDropBar = EXC_CHDROPBAR_UP; |
| else if( !maDropBars.has( EXC_CHDROPBAR_DOWN ) ) |
| nDropBar = EXC_CHDROPBAR_DOWN; |
| |
| if( nDropBar != EXC_CHDROPBAR_NONE ) |
| { |
| XclImpChDropBarRef xDropBar( new XclImpChDropBar( nDropBar ) ); |
| xDropBar->ReadRecordGroup( rStrm ); |
| maDropBars[ nDropBar ] = xDropBar; |
| } |
| } |
| |
| void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm ) |
| { |
| sal_uInt16 nLineId = rStrm.ReaduInt16(); |
| if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() ) |
| { |
| XclImpChLineFormatRef xLineFmt( new XclImpChLineFormat ); |
| xLineFmt->ReadChLineFormat( rStrm ); |
| maChartLines[ nLineId ] = xLineFmt; |
| } |
| } |
| |
| void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm ) |
| { |
| // global series and data point format |
| XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) ); |
| xDataFmt->ReadRecordGroup( rStrm ); |
| const XclChDataPointPos& rPos = xDataFmt->GetPointPos(); |
| if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) && |
| (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) ) |
| mxGroupFmt = xDataFmt; |
| } |
| |
| |
| void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType, |
| Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const |
| { |
| Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY ); |
| if( xSeriesCont.is() && xSeries.is() ) |
| { |
| // series stacking mode |
| cssc2::StackingDirection eStacking = cssc2::StackingDirection_NO_STACKING; |
| // stacked overrides deep-3d |
| if( maType.IsStacked() || maType.IsPercent() ) |
| eStacking = cssc2::StackingDirection_Y_STACKING; |
| else if( Is3dDeepChart() ) |
| eStacking = cssc2::StackingDirection_Z_STACKING; |
| |
| // additional series properties |
| ScfPropertySet aSeriesProp( xSeries ); |
| aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking ); |
| aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx ); |
| |
| // insert series into container |
| try |
| { |
| xSeriesCont->addDataSeries( xSeries ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" ); |
| } |
| } |
| } |
| |
| void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const |
| { |
| bool bSpline = false; |
| for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt ) |
| { |
| Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries(); |
| InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx ); |
| bSpline |= (*aIt)->HasSpline(); |
| } |
| // spline - TODO: set at single series (#i66858#) |
| if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) ) |
| { |
| ScfPropertySet aTypeProp( xChartType ); |
| aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES ); |
| } |
| } |
| |
| void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const |
| { |
| // create the data series object |
| Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY ); |
| Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY ); |
| if( xDataSink.is() ) |
| { |
| // create a list of data sequences from all series |
| ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; |
| DBG_ASSERT( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" ); |
| int nRoleIdx = (maSeries.size() == 3) ? 1 : 0; |
| for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); |
| (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt ) |
| { |
| // create a data sequence with a specific role |
| OUString aRole; |
| switch( nRoleIdx ) |
| { |
| case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES; break; |
| case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES; break; |
| case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES; break; |
| case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES; break; |
| } |
| Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole ); |
| if( xDataSeq.is() ) |
| aLabeledSeqVec.push_back( xDataSeq ); |
| } |
| |
| // attach labeled data sequences to series and insert series into chart type |
| xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) ); |
| |
| // formatting of special stock chart elements |
| ScfPropertySet aTypeProp( xChartType ); |
| aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() ); |
| aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() ); |
| aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true ); |
| // hi-lo line format |
| XclImpChLineFormatRef xHiLoLine = maChartLines.get( EXC_CHCHARTLINE_HILO ); |
| if( xHiLoLine.is() ) |
| { |
| ScfPropertySet aSeriesProp( xDataSeries ); |
| xHiLoLine->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE ); |
| } |
| // white dropbar format |
| XclImpChDropBarRef xUpBar = maDropBars.get( EXC_CHDROPBAR_UP ); |
| Reference< XPropertySet > xWhitePropSet; |
| if( xUpBar.is() && aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY ) ) |
| { |
| ScfPropertySet aBarProp( xWhitePropSet ); |
| xUpBar->Convert( GetChRoot(), aBarProp ); |
| } |
| // black dropbar format |
| XclImpChDropBarRef xDownBar = maDropBars.get( EXC_CHDROPBAR_DOWN ); |
| Reference< XPropertySet > xBlackPropSet; |
| if( xDownBar.is() && aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY ) ) |
| { |
| ScfPropertySet aBarProp( xBlackPropSet ); |
| xDownBar->Convert( GetChRoot(), aBarProp ); |
| } |
| |
| // insert the series into the chart type object |
| InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx ); |
| } |
| } |
| |
| // Axes ======================================================================= |
| |
| XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm ) |
| { |
| rStrm >> maLabelData.mnCross >> maLabelData.mnLabelFreq >> maLabelData.mnTickFreq >> maLabelData.mnFlags; |
| } |
| |
| void XclImpChLabelRange::ReadChDateRange( XclImpStream& rStrm ) |
| { |
| rStrm >> maDateData.mnMinDate |
| >> maDateData.mnMaxDate |
| >> maDateData.mnMajorStep |
| >> maDateData.mnMajorUnit |
| >> maDateData.mnMinorStep |
| >> maDateData.mnMinorUnit |
| >> maDateData.mnBaseUnit |
| >> maDateData.mnCross |
| >> maDateData.mnFlags; |
| } |
| |
| void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const |
| { |
| // automatic axis type detection |
| rScaleData.AutoDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE ); |
| |
| // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis |
| if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) ) |
| { |
| /* Chart2 requires axis type CATEGORY for automatic category/date axis |
| (even if it is a date axis currently). */ |
| rScaleData.AxisType = rScaleData.AutoDateAxis ? cssc2::AxisType::CATEGORY : cssc2::AxisType::DATE; |
| rScaleData.Scaling.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LINEARSCALING ), UNO_QUERY ); |
| /* Min/max values depend on base time unit, they specify the number of |
| days, months, or years starting from null date. */ |
| lclConvertTimeValue( GetRoot(), rScaleData.Minimum, maDateData.mnMinDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN ), maDateData.mnBaseUnit ); |
| lclConvertTimeValue( GetRoot(), rScaleData.Maximum, maDateData.mnMaxDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX ), maDateData.mnBaseUnit ); |
| // increment |
| cssc::TimeIncrement& rTimeIncrement = rScaleData.TimeIncrement; |
| lclConvertTimeInterval( rTimeIncrement.MajorTimeInterval, maDateData.mnMajorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR ), maDateData.mnMajorUnit ); |
| lclConvertTimeInterval( rTimeIncrement.MinorTimeInterval, maDateData.mnMinorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR ), maDateData.mnMinorUnit ); |
| // base unit |
| if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE ) ) |
| rTimeIncrement.TimeResolution.clear(); |
| else |
| rTimeIncrement.TimeResolution <<= lclGetApiTimeUnit( maDateData.mnBaseUnit ); |
| } |
| else |
| { |
| // do not overlap text unless all labels are visible |
| rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maLabelData.mnLabelFreq == 1 ); |
| // do not break text into several lines unless all labels are visible |
| rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maLabelData.mnLabelFreq == 1 ); |
| // do not stagger labels in two lines |
| rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE ); |
| } |
| |
| // reverse order |
| bool bReverse = ::get_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient; |
| rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL; |
| |
| //! TODO #i58731# show n-th category |
| } |
| |
| void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const |
| { |
| /* Crossing mode (max-cross flag overrides other crossing settings). Excel |
| does not move the Y axis in 3D charts, regardless of actual settings. |
| But: the Y axis has to be moved to "end", if the X axis is mirrored, |
| to keep it at the left end of the chart. */ |
| bool bMaxCross = ::get_flag( maLabelData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS ); |
| cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE; |
| rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos ); |
| |
| // crossing position (depending on axis type text/date) |
| if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) ) |
| { |
| bool bAutoCross = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS ); |
| /* Crossing position value depends on base time unit, it specifies the |
| number of days, months, or years from null date. Note that Excel |
| 2007/2010 write broken BIFF8 files, they always stores the number |
| of days cregardless of the base time unit (and they are reading it |
| the same way, thus wrongly displaying files written by Excel |
| 97-2003). This filter sticks to the correct behaviour of Excel |
| 97-2003. */ |
| double fCrossingPos = bAutoCross ? 1.0 : lclGetSerialDay( GetRoot(), maDateData.mnCross, maDateData.mnBaseUnit ); |
| rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos ); |
| } |
| else |
| { |
| double fCrossingPos = b3dChart ? 1.0 : maLabelData.mnCross; |
| rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos ); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mfMin |
| >> maData.mfMax |
| >> maData.mfMajorStep |
| >> maData.mfMinorStep |
| >> maData.mfCross |
| >> maData.mnFlags; |
| } |
| |
| void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const |
| { |
| // scaling algorithm |
| bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE ); |
| OUString aScalingService = bLogScale ? SERVICE_CHART2_LOGSCALING : SERVICE_CHART2_LINEARSCALING; |
| rScaleData.Scaling.set( ScfApiHelper::CreateInstance( aScalingService ), UNO_QUERY ); |
| |
| // min/max |
| lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) ); |
| lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) ); |
| |
| // increment |
| bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR ); |
| bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR ); |
| // major increment |
| IncrementData& rIncrementData = rScaleData.IncrementData; |
| lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor ); |
| // minor increment |
| Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements; |
| rSubIncrementSeq.realloc( 1 ); |
| Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount; |
| rIntervalCount.clear(); |
| if( bLogScale ) |
| { |
| if( !bAutoMinor ) |
| rIntervalCount <<= sal_Int32( 9 ); |
| } |
| else |
| { |
| if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) ) |
| { |
| double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5; |
| if( (1.0 <= fCount) && (fCount < 1001.0) ) |
| rIntervalCount <<= static_cast< sal_Int32 >( fCount ); |
| } |
| } |
| |
| // reverse order |
| bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient; |
| rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL; |
| } |
| |
| void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const |
| { |
| bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS ); |
| bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS ); |
| bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE ); |
| |
| // crossing mode (max-cross flag overrides other crossing settings) |
| cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE; |
| rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos ); |
| |
| // crossing position |
| double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross; |
| if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos ); |
| rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| namespace { |
| |
| sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos ) |
| { |
| using namespace ::com::sun::star::chart2::TickmarkStyle; |
| sal_Int32 nApiTickmarks = NONE; |
| ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) ); |
| ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) ); |
| return nApiTickmarks; |
| } |
| |
| cssc::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos ) |
| { |
| using namespace ::com::sun::star::chart; |
| switch( nXclLabelPos ) |
| { |
| case EXC_CHTICK_LOW: return ChartAxisLabelPosition_OUTSIDE_START; |
| case EXC_CHTICK_HIGH: return ChartAxisLabelPosition_OUTSIDE_END; |
| case EXC_CHTICK_NEXT: return ChartAxisLabelPosition_NEAR_AXIS; |
| } |
| return ChartAxisLabelPosition_NEAR_AXIS; |
| } |
| |
| } // namespace |
| |
| XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) : |
| XclImpChRoot( rRoot ) |
| { |
| } |
| |
| void XclImpChTick::ReadChTick( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnMajor |
| >> maData.mnMinor |
| >> maData.mnLabelPos |
| >> maData.mnBackMode; |
| rStrm.Ignore( 16 ); |
| rStrm >> maData.maTextColor |
| >> maData.mnFlags; |
| |
| if( GetBiff() == EXC_BIFF8 ) |
| { |
| // #116397# BIFF8: index into palette used instead of RGB data |
| maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() ); |
| // rotation |
| rStrm >> maData.mnRotation; |
| } |
| else |
| { |
| // BIFF2-BIFF7: get rotation from text orientation |
| sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 ); |
| maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient ); |
| } |
| } |
| |
| Color XclImpChTick::GetFontColor() const |
| { |
| return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor; |
| } |
| |
| sal_uInt16 XclImpChTick::GetRotation() const |
| { |
| return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation; |
| } |
| |
| void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const |
| { |
| rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) ); |
| rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) ); |
| rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) ); |
| rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, cssc::ChartAxisMarkPosition_AT_AXIS ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) : |
| XclImpChRoot( rRoot ), |
| mnNumFmtIdx( EXC_FORMAT_NOTFOUND ) |
| { |
| maData.mnType = nAxisType; |
| } |
| |
| void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnType; |
| } |
| |
| void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHLABELRANGE: |
| mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) ); |
| mxLabelRange->ReadChLabelRange( rStrm ); |
| break; |
| case EXC_ID_CHDATERANGE: |
| if( !mxLabelRange ) |
| mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) ); |
| mxLabelRange->ReadChDateRange( rStrm ); |
| break; |
| case EXC_ID_CHVALUERANGE: |
| mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) ); |
| mxValueRange->ReadChValueRange( rStrm ); |
| break; |
| case EXC_ID_CHFORMAT: |
| rStrm >> mnNumFmtIdx; |
| break; |
| case EXC_ID_CHTICK: |
| mxTick.reset( new XclImpChTick( GetChRoot() ) ); |
| mxTick->ReadChTick( rStrm ); |
| break; |
| case EXC_ID_CHFONT: |
| mxFont.reset( new XclImpChFont ); |
| mxFont->ReadChFont( rStrm ); |
| break; |
| case EXC_ID_CHAXISLINE: |
| ReadChAxisLine( rStrm ); |
| break; |
| } |
| } |
| |
| void XclImpChAxis::Finalize() |
| { |
| // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts |
| if( !mxLabelRange ) |
| mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) ); |
| if( !mxValueRange ) |
| mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) ); |
| // remove invisible grid lines completely |
| if( mxMajorGrid.is() && !mxMajorGrid->HasLine() ) |
| mxMajorGrid.reset(); |
| if( mxMinorGrid.is() && !mxMinorGrid->HasLine() ) |
| mxMinorGrid.reset(); |
| // default tick settings different in OOChart and Excel |
| if( !mxTick ) |
| mxTick.reset( new XclImpChTick( GetChRoot() ) ); |
| // #i4140# different default axis line color |
| if( !mxAxisLine ) |
| { |
| XclChLineFormat aLineFmt; |
| // set "show axis" flag, default if line format record is missing |
| ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS ); |
| mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) ); |
| } |
| // add wall/floor frame for 3d charts |
| if( !mxWallFrame ) |
| CreateWallFrame(); |
| } |
| |
| sal_uInt16 XclImpChAxis::GetFontIndex() const |
| { |
| return mxFont.is() ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND; |
| } |
| |
| Color XclImpChAxis::GetFontColor() const |
| { |
| return mxTick.is() ? mxTick->GetFontColor() : GetFontAutoColor(); |
| } |
| |
| sal_uInt16 XclImpChAxis::GetRotation() const |
| { |
| return mxTick.is() ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION; |
| } |
| |
| Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const |
| { |
| // create the axis object (always) |
| Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY ); |
| if( xAxis.is() ) |
| { |
| ScfPropertySet aAxisProp( xAxis ); |
| // #i58688# axis enabled |
| aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() ); |
| |
| // axis line properties |
| if( mxAxisLine.is() ) |
| mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE ); |
| // axis ticks properties |
| if( mxTick.is() ) |
| mxTick->Convert( aAxisProp ); |
| |
| // axis caption text -------------------------------------------------- |
| |
| // radar charts disable their category labels via chart type, not via axis |
| bool bHasLabels = HasLabels() && |
| ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels()); |
| aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels ); |
| if( bHasLabels ) |
| { |
| // font settings from CHFONT record or from default text |
| if( mxFont.is() ) |
| ConvertFontBase( GetChRoot(), aAxisProp ); |
| else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ).get() ) |
| pDefText->ConvertFont( aAxisProp ); |
| // label text rotation |
| ConvertRotationBase( GetChRoot(), aAxisProp, true ); |
| // number format |
| sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx ); |
| if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND ) |
| aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) ); |
| } |
| |
| // axis scaling and increment ----------------------------------------- |
| |
| const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo(); |
| ScaleData aScaleData = xAxis->getScaleData(); |
| // set axis type |
| switch( GetAxisType() ) |
| { |
| case EXC_CHAXIS_X: |
| if( rTypeInfo.mbCategoryAxis ) |
| { |
| aScaleData.AxisType = cssc2::AxisType::CATEGORY; |
| aScaleData.Categories = rTypeGroup.CreateCategSequence(); |
| } |
| else |
| aScaleData.AxisType = cssc2::AxisType::REALNUMBER; |
| break; |
| case EXC_CHAXIS_Y: |
| aScaleData.AxisType = rTypeGroup.IsPercent() ? |
| cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER; |
| break; |
| case EXC_CHAXIS_Z: |
| aScaleData.AxisType = cssc2::AxisType::SERIES; |
| break; |
| } |
| // axis scaling settings, dependent on axis type |
| switch( aScaleData.AxisType ) |
| { |
| case cssc2::AxisType::CATEGORY: |
| case cssc2::AxisType::SERIES: |
| // #i71684# radar charts have reversed rotation direction |
| mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR ); |
| break; |
| case cssc2::AxisType::REALNUMBER: |
| case cssc2::AxisType::PERCENT: |
| // #i85167# pie/donut charts have reversed rotation direction (at Y axis!) |
| mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE ); |
| break; |
| default: |
| DBG_ERRORFILE( "XclImpChAxis::CreateAxis - unknown axis type" ); |
| } |
| |
| /* Do not set a value to the Origin member anymore (will be done via |
| new axis properties 'CrossoverPosition' and 'CrossoverValue'). */ |
| aScaleData.Origin.clear(); |
| |
| // write back |
| xAxis->setScaleData( aScaleData ); |
| |
| // grid --------------------------------------------------------------- |
| |
| // main grid |
| ScfPropertySet aGridProp( xAxis->getGridProperties() ); |
| aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() ); |
| if( mxMajorGrid.is() ) |
| mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE ); |
| // sub grid |
| Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties(); |
| if( aSubGridPropSeq.hasElements() ) |
| { |
| ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] ); |
| aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() ); |
| if( mxMinorGrid.is() ) |
| mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE ); |
| } |
| |
| // position of crossing axis ------------------------------------------ |
| |
| if( pCrossingAxis ) |
| pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup ); |
| } |
| return xAxis; |
| } |
| |
| void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const |
| { |
| // #i71810# walls and floor in 3D charts use the CHPICFORMAT record for bitmap mode |
| if( mxWallFrame.is() ) |
| mxWallFrame->Convert( rPropSet, true ); |
| } |
| |
| void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const |
| { |
| if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) ) |
| mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() ); |
| else |
| mxValueRange->ConvertAxisPosition( rPropSet ); |
| } |
| |
| void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm ) |
| { |
| XclImpChLineFormatRef* pxLineFmt = 0; |
| bool bWallFrame = false; |
| switch( rStrm.ReaduInt16() ) |
| { |
| case EXC_CHAXISLINE_AXISLINE: pxLineFmt = &mxAxisLine; break; |
| case EXC_CHAXISLINE_MAJORGRID: pxLineFmt = &mxMajorGrid; break; |
| case EXC_CHAXISLINE_MINORGRID: pxLineFmt = &mxMinorGrid; break; |
| case EXC_CHAXISLINE_WALLS: bWallFrame = true; break; |
| } |
| if( bWallFrame ) |
| CreateWallFrame(); |
| |
| bool bLoop = pxLineFmt || bWallFrame; |
| while( bLoop ) |
| { |
| sal_uInt16 nRecId = rStrm.GetNextRecId(); |
| bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) || |
| (nRecId == EXC_ID_CHAREAFORMAT) || |
| (nRecId == EXC_ID_CHESCHERFORMAT)) |
| && rStrm.StartNextRecord(); |
| if( bLoop ) |
| { |
| if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) ) |
| { |
| pxLineFmt->reset( new XclImpChLineFormat ); |
| (*pxLineFmt)->ReadChLineFormat( rStrm ); |
| } |
| else if( bWallFrame && mxWallFrame.is() ) |
| { |
| mxWallFrame->ReadSubRecord( rStrm ); |
| } |
| } |
| } |
| } |
| |
| void XclImpChAxis::CreateWallFrame() |
| { |
| switch( GetAxisType() ) |
| { |
| case EXC_CHAXIS_X: |
| mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) ); |
| break; |
| case EXC_CHAXIS_Y: |
| mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) ); |
| break; |
| default: |
| mxWallFrame.reset(); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) : |
| XclImpChRoot( rRoot ) |
| { |
| maData.mnAxesSetId = nAxesSetId; |
| } |
| |
| void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| rStrm >> maData.mnAxesSetId >> maData.maRect; |
| } |
| |
| void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHFRAMEPOS: |
| mxFramePos.reset( new XclImpChFramePos ); |
| mxFramePos->ReadChFramePos( rStrm ); |
| break; |
| case EXC_ID_CHAXIS: |
| ReadChAxis( rStrm ); |
| break; |
| case EXC_ID_CHTEXT: |
| ReadChText( rStrm ); |
| break; |
| case EXC_ID_CHPLOTFRAME: |
| ReadChPlotFrame( rStrm ); |
| break; |
| case EXC_ID_CHTYPEGROUP: |
| ReadChTypeGroup( rStrm ); |
| break; |
| } |
| } |
| |
| void XclImpChAxesSet::Finalize() |
| { |
| if( IsValidAxesSet() ) |
| { |
| // finalize chart type groups, erase empty groups without series |
| XclImpChTypeGroupMap aValidGroups; |
| for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt ) |
| { |
| XclImpChTypeGroupRef xTypeGroup = aIt->second; |
| xTypeGroup->Finalize(); |
| if( xTypeGroup->IsValidGroup() ) |
| aValidGroups[ aIt->first ] = xTypeGroup; |
| } |
| maTypeGroups.swap( aValidGroups ); |
| } |
| |
| // invalid chart type groups are deleted now, check again with IsValidAxesSet() |
| if( IsValidAxesSet() ) |
| { |
| // always create missing axis objects |
| if( !mxXAxis ) |
| mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) ); |
| if( !mxYAxis ) |
| mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) ); |
| if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() ) |
| mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) ); |
| |
| // finalize axes |
| if( mxXAxis.is() ) mxXAxis->Finalize(); |
| if( mxYAxis.is() ) mxYAxis->Finalize(); |
| if( mxZAxis.is() ) mxZAxis->Finalize(); |
| |
| // finalize axis titles |
| XclImpChTextRef xDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE ); |
| String aAutoTitle = CREATE_STRING( "Axis Title" ); |
| lclFinalizeTitle( mxXAxisTitle, xDefText, aAutoTitle ); |
| lclFinalizeTitle( mxYAxisTitle, xDefText, aAutoTitle ); |
| lclFinalizeTitle( mxZAxisTitle, xDefText, aAutoTitle ); |
| |
| // #i47745# missing plot frame -> invisible border and area |
| if( !mxPlotFrame ) |
| mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) ); |
| } |
| } |
| |
| XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const |
| { |
| XclImpChTypeGroupRef xTypeGroup; |
| if( !maTypeGroups.empty() ) |
| xTypeGroup = maTypeGroups.begin()->second; |
| return xTypeGroup; |
| } |
| |
| XclImpChLegendRef XclImpChAxesSet::GetLegend() const |
| { |
| XclImpChLegendRef xLegend; |
| for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt ) |
| xLegend = aIt->second->GetLegend(); |
| return xLegend; |
| } |
| |
| const String& XclImpChAxesSet::GetSingleSeriesTitle() const |
| { |
| return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : String::EmptyString(); |
| } |
| |
| void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const |
| { |
| if( IsValidAxesSet() && xDiagram.is() ) |
| { |
| // diagram background formatting |
| if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY ) |
| ConvertBackground( xDiagram ); |
| |
| // create the coordinate system, this inserts all chart types and series |
| Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram ); |
| if( xCoordSystem.is() ) |
| { |
| // insert coordinate system, if not already done |
| try |
| { |
| Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW ); |
| Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems(); |
| if( aCoordSystems.getLength() == 0 ) |
| xCoordSystemCont->addCoordinateSystem( xCoordSystem ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChAxesSet::Convert - cannot insert coordinate system" ); |
| } |
| |
| // create the axes with grids and axis titles and insert them into the diagram |
| ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() ); |
| ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() ); |
| ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 ); |
| } |
| } |
| } |
| |
| void XclImpChAxesSet::ConvertTitlePositions() const |
| { |
| if( mxXAxisTitle.is() ) |
| mxXAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_X ) ); |
| if( mxYAxisTitle.is() ) |
| mxYAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Y ) ); |
| if( mxZAxisTitle.is() ) |
| mxZAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Z ) ); |
| } |
| |
| void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm ) |
| { |
| XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) ); |
| xAxis->ReadRecordGroup( rStrm ); |
| |
| switch( xAxis->GetAxisType() ) |
| { |
| case EXC_CHAXIS_X: mxXAxis = xAxis; break; |
| case EXC_CHAXIS_Y: mxYAxis = xAxis; break; |
| case EXC_CHAXIS_Z: mxZAxis = xAxis; break; |
| } |
| } |
| |
| void XclImpChAxesSet::ReadChText( XclImpStream& rStrm ) |
| { |
| XclImpChTextRef xText( new XclImpChText( GetChRoot() ) ); |
| xText->ReadRecordGroup( rStrm ); |
| |
| switch( xText->GetLinkTarget() ) |
| { |
| case EXC_CHOBJLINK_XAXIS: mxXAxisTitle = xText; break; |
| case EXC_CHOBJLINK_YAXIS: mxYAxisTitle = xText; break; |
| case EXC_CHOBJLINK_ZAXIS: mxZAxisTitle = xText; break; |
| } |
| } |
| |
| void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm ) |
| { |
| if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() ) |
| { |
| mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) ); |
| mxPlotFrame->ReadRecordGroup( rStrm ); |
| } |
| } |
| |
| void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm ) |
| { |
| XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) ); |
| xTypeGroup->ReadRecordGroup( rStrm ); |
| maTypeGroups[ xTypeGroup->GetGroupIdx() ] = xTypeGroup; |
| } |
| |
| Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const |
| { |
| Reference< XCoordinateSystem > xCoordSystem; |
| |
| /* Try to get existing ccordinate system. For now, all series from primary |
| and secondary axes sets are inserted into one coordinate system. Later, |
| this should be changed to use one coordinate system for each axes set. */ |
| Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY ); |
| if( xCoordSystemCont.is() ) |
| { |
| Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems(); |
| DBG_ASSERT( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" ); |
| if( aCoordSystems.getLength() > 0 ) |
| xCoordSystem = aCoordSystems[ 0 ]; |
| } |
| |
| // create the coordinate system according to the first chart type |
| if( !xCoordSystem.is() ) |
| { |
| XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup(); |
| if( xTypeGroup.is() ) |
| { |
| xCoordSystem = xTypeGroup->CreateCoordSystem(); |
| // convert 3d chart settings |
| ScfPropertySet aDiaProp( xDiagram ); |
| xTypeGroup->ConvertChart3d( aDiaProp ); |
| } |
| } |
| |
| /* Create XChartType objects for all chart type groups. Each group will |
| add its series to the data provider attached to the chart document. */ |
| Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY ); |
| if( xChartTypeCont.is() ) |
| { |
| sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex(); |
| for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt ) |
| { |
| try |
| { |
| Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx ); |
| if( xChartType.is() ) |
| xChartTypeCont->addChartType( xChartType ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" ); |
| } |
| } |
| } |
| |
| return xCoordSystem; |
| } |
| |
| void XclImpChAxesSet::ConvertAxis( |
| XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle, |
| Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const |
| { |
| if( xChAxis.is() ) |
| { |
| // create and attach the axis object |
| Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis ); |
| if( xAxis.is() ) |
| { |
| // create and attach the axis title |
| if( xChAxisTitle.is() ) try |
| { |
| Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW ); |
| Reference< XTitle > xTitle( xChAxisTitle->CreateTitle(), UNO_SET_THROW ); |
| xTitled->setTitleObject( xTitle ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis title" ); |
| } |
| |
| // insert axis into coordinate system |
| try |
| { |
| sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension(); |
| sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex(); |
| xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx ); |
| } |
| catch( Exception& ) |
| { |
| DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis" ); |
| } |
| } |
| } |
| } |
| |
| Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const |
| { |
| Reference< XAxis > xAxis; |
| if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() ) |
| xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis ); |
| return xAxis; |
| } |
| |
| void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const |
| { |
| XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup(); |
| if( xTypeGroup.is() && xTypeGroup->Is3dWallChart() ) |
| { |
| // wall/floor formatting (3D charts) |
| if( mxXAxis.is() ) |
| { |
| ScfPropertySet aWallProp( xDiagram->getWall() ); |
| mxXAxis->ConvertWall( aWallProp ); |
| } |
| if( mxYAxis.is() ) |
| { |
| ScfPropertySet aFloorProp( xDiagram->getFloor() ); |
| mxYAxis->ConvertWall( aFloorProp ); |
| } |
| } |
| else if( mxPlotFrame.is() ) |
| { |
| // diagram background formatting |
| ScfPropertySet aWallProp( xDiagram->getWall() ); |
| mxPlotFrame->Convert( aWallProp ); |
| } |
| } |
| |
| // The chart object =========================================================== |
| |
| XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) : |
| XclImpChRoot( rRoot, *this ) |
| { |
| mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) ); |
| mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) ); |
| } |
| |
| XclImpChChart::~XclImpChChart() |
| { |
| } |
| |
| void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm ) |
| { |
| // coordinates are stored as 16.16 fixed point |
| rStrm >> maRect; |
| } |
| |
| void XclImpChChart::ReadSubRecord( XclImpStream& rStrm ) |
| { |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_CHFRAME: |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) ); |
| mxFrame->ReadRecordGroup( rStrm ); |
| break; |
| case EXC_ID_CHSERIES: |
| ReadChSeries( rStrm ); |
| break; |
| case EXC_ID_CHPROPERTIES: |
| ReadChProperties( rStrm ); |
| break; |
| case EXC_ID_CHDEFAULTTEXT: |
| ReadChDefaultText( rStrm ); |
| break; |
| case EXC_ID_CHAXESSET: |
| ReadChAxesSet( rStrm ); |
| break; |
| case EXC_ID_CHTEXT: |
| ReadChText( rStrm ); |
| break; |
| case EXC_ID_CHEND: |
| Finalize(); // finalize the entire chart object |
| break; |
| } |
| } |
| |
| void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm ) |
| { |
| sal_uInt16 nTextId = rStrm.ReaduInt16(); |
| if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() ) |
| { |
| XclImpChTextRef xText( new XclImpChText( GetChRoot() ) ); |
| xText->ReadRecordGroup( rStrm ); |
| maDefTexts[ nTextId ] = xText; |
| } |
| } |
| |
| void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm ) |
| { |
| XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) ); |
| xDataFmt->ReadRecordGroup( rStrm ); |
| if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES ) |
| { |
| XclImpChDataFormatRef& rxMapFmt = maDataFmts[ xDataFmt->GetPointPos() ]; |
| /* Do not overwrite existing data format group, Excel always uses the |
| first data format group occuring in any CHSERIES group. */ |
| if( !rxMapFmt ) |
| rxMapFmt = xDataFmt; |
| } |
| } |
| |
| void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData ) |
| { |
| if( !mxFrame ) |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) ); |
| mxFrame->UpdateObjFrame( rLineData, rFillData ); |
| } |
| |
| XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const |
| { |
| XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx ); |
| if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx ); |
| if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup(); |
| return xTypeGroup; |
| } |
| |
| XclImpChTextRef XclImpChChart::GetDefaultText( XclChTextType eTextType ) const |
| { |
| sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL; |
| bool bBiff8 = GetBiff() == EXC_BIFF8; |
| switch( eTextType ) |
| { |
| case EXC_CHTEXTTYPE_TITLE: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break; |
| case EXC_CHTEXTTYPE_LEGEND: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break; |
| case EXC_CHTEXTTYPE_AXISTITLE: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break; |
| case EXC_CHTEXTTYPE_AXISLABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break; |
| case EXC_CHTEXTTYPE_DATALABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break; |
| } |
| return maDefTexts.get( nDefTextId ); |
| } |
| |
| bool XclImpChChart::IsManualPlotArea() const |
| { |
| // there is no real automatic mode in BIFF5 charts |
| return (GetBiff() <= EXC_BIFF5) || ::get_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA ); |
| } |
| |
| void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc, |
| XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const |
| { |
| // initialize conversion (locks the model to suppress any internal updates) |
| InitConversion( xChartDoc, rChartRect ); |
| |
| // chart frame formatting |
| if( mxFrame.is() ) |
| { |
| ScfPropertySet aFrameProp( xChartDoc->getPageBackground() ); |
| mxFrame->Convert( aFrameProp ); |
| } |
| |
| // chart title |
| if( mxTitle.is() ) try |
| { |
| Reference< XTitled > xTitled( xChartDoc, UNO_QUERY_THROW ); |
| Reference< XTitle > xTitle( mxTitle->CreateTitle(), UNO_SET_THROW ); |
| xTitled->setTitleObject( xTitle ); |
| } |
| catch( Exception& ) |
| { |
| } |
| |
| /* Create the diagram object and attach it to the chart document. Currently, |
| one diagram is used to carry all coordinate systems and data series. */ |
| Reference< XDiagram > xDiagram = CreateDiagram(); |
| xChartDoc->setFirstDiagram( xDiagram ); |
| |
| // coordinate systems and chart types, convert axis settings |
| mxPrimAxesSet->Convert( xDiagram ); |
| mxSecnAxesSet->Convert( xDiagram ); |
| |
| // legend |
| if( xDiagram.is() && mxLegend.is() ) |
| xDiagram->setLegend( mxLegend->CreateLegend() ); |
| |
| /* Following all conversions needing the old Chart1 API that involves full |
| initialization of the chart view. */ |
| Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY ); |
| if( xChart1Doc.is() ) |
| { |
| Reference< cssc::XDiagram > xDiagram1 = xChart1Doc->getDiagram(); |
| |
| /* Set the 'IncludeHiddenCells' property via the old API as only this |
| ensures that the data provider and all created sequences get this |
| flag correctly. */ |
| ScfPropertySet aDiaProp( xDiagram1 ); |
| bool bShowVisCells = ::get_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY ); |
| aDiaProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells ); |
| |
| // plot area position and size (there is no real automatic mode in BIFF5 charts) |
| XclImpChFramePosRef xPlotAreaPos = mxPrimAxesSet->GetPlotAreaFramePos(); |
| if( IsManualPlotArea() && xPlotAreaPos.is() ) try |
| { |
| const XclChFramePos& rFramePos = xPlotAreaPos->GetFramePosData(); |
| if( (rFramePos.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rFramePos.mnBRMode == EXC_CHFRAMEPOS_PARENT) ) |
| { |
| Reference< cssc::XDiagramPositioning > xPositioning( xDiagram1, UNO_QUERY_THROW ); |
| ::com::sun::star::awt::Rectangle aDiagramRect = CalcHmmFromChartRect( rFramePos.maRect ); |
| // for pie charts, always set inner plot area size to exclude the data labels as Excel does |
| const XclImpChTypeGroup* pFirstTypeGroup = mxPrimAxesSet->GetFirstTypeGroup().get(); |
| if( pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE) ) |
| xPositioning->setDiagramPositionExcludingAxes( aDiagramRect ); |
| else if( pFirstTypeGroup && pFirstTypeGroup->Is3dChart() ) |
| xPositioning->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect ); |
| else |
| xPositioning->setDiagramPositionIncludingAxes( aDiagramRect ); |
| } |
| } |
| catch( Exception& ) |
| { |
| } |
| |
| // positions of all title objects |
| if( mxTitle.is() ) |
| mxTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE ) ); |
| mxPrimAxesSet->ConvertTitlePositions(); |
| mxSecnAxesSet->ConvertTitlePositions(); |
| } |
| |
| // unlock the model |
| FinishConversion( rDffConv ); |
| |
| // start listening to this chart |
| ScDocument& rDoc = GetRoot().GetDoc(); |
| if( ScChartListenerCollection* pChartCollection = rDoc.GetChartListenerCollection() ) |
| { |
| ::std::auto_ptr< ::std::vector< ScSharedTokenRef > > xRefTokens( new ::std::vector< ScSharedTokenRef > ); |
| for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt ) |
| (*aIt)->FillAllSourceLinks( *xRefTokens ); |
| if( !xRefTokens->empty() ) |
| { |
| ::std::auto_ptr< ScChartListener > xListener( new ScChartListener( rObjName, &rDoc, xRefTokens.release() ) ); |
| xListener->SetUsed( true ); |
| xListener->StartListeningTo(); |
| pChartCollection->Insert( xListener.release() ); |
| } |
| } |
| } |
| |
| void XclImpChChart::ReadChSeries( XclImpStream& rStrm ) |
| { |
| sal_uInt16 nNewSeriesIdx = static_cast< sal_uInt16 >( maSeries.size() ); |
| XclImpChSeriesRef xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx ) ); |
| xSeries->ReadRecordGroup( rStrm ); |
| maSeries.push_back( xSeries ); |
| } |
| |
| void XclImpChChart::ReadChProperties( XclImpStream& rStrm ) |
| { |
| rStrm >> maProps.mnFlags >> maProps.mnEmptyMode; |
| } |
| |
| void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm ) |
| { |
| XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) ); |
| xAxesSet->ReadRecordGroup( rStrm ); |
| switch( xAxesSet->GetAxesSetId() ) |
| { |
| case EXC_CHAXESSET_PRIMARY: mxPrimAxesSet = xAxesSet; break; |
| case EXC_CHAXESSET_SECONDARY: mxSecnAxesSet = xAxesSet; break; |
| } |
| } |
| |
| void XclImpChChart::ReadChText( XclImpStream& rStrm ) |
| { |
| XclImpChTextRef xText( new XclImpChText( GetChRoot() ) ); |
| xText->ReadRecordGroup( rStrm ); |
| switch( xText->GetLinkTarget() ) |
| { |
| case EXC_CHOBJLINK_TITLE: |
| mxTitle = xText; |
| break; |
| case EXC_CHOBJLINK_DATA: |
| { |
| sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx; |
| if( nSeriesIdx < maSeries.size() ) |
| maSeries[ nSeriesIdx ]->SetDataLabel( xText ); |
| } |
| break; |
| } |
| } |
| |
| void XclImpChChart::Finalize() |
| { |
| // finalize series (must be done first) |
| FinalizeSeries(); |
| // #i49218# legend may be attached to primary or secondary axes set |
| mxLegend = mxPrimAxesSet->GetLegend(); |
| if( !mxLegend ) |
| mxLegend = mxSecnAxesSet->GetLegend(); |
| if( mxLegend.is() ) |
| mxLegend->Finalize(); |
| // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats() |
| mxPrimAxesSet->Finalize(); |
| mxSecnAxesSet->Finalize(); |
| // formatting of all series |
| FinalizeDataFormats(); |
| // #i47745# missing frame -> invisible border and area |
| if( !mxFrame ) |
| mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) ); |
| // chart title |
| FinalizeTitle(); |
| } |
| |
| void XclImpChChart::FinalizeSeries() |
| { |
| for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt ) |
| { |
| XclImpChSeriesRef xSeries = *aSIt; |
| if( xSeries->HasParentSeries() ) |
| { |
| /* Process child series (trend lines and error bars). Data of |
| child series will be set at the connected parent series. */ |
| if( xSeries->GetParentIdx() < maSeries.size() ) |
| maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries ); |
| } |
| else |
| { |
| // insert the series into the related chart type group |
| if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() ) |
| pTypeGroup->AddSeries( xSeries ); |
| } |
| } |
| } |
| |
| void XclImpChChart::FinalizeDataFormats() |
| { |
| /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups. |
| Each CHDATAFORMAT group specifies the series and data point it is |
| assigned to. This makes it possible to have a data format that is |
| related to another series, e.g. a CHDATAFORMAT group for series 2 is |
| part of a CHSERIES group that describes series 1. Therefore the chart |
| itself has collected all CHDATAFORMAT groups to be able to store data |
| format groups for series that have not been imported at that time. This |
| loop finally assigns these groups to the related series. */ |
| for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt ) |
| { |
| sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx; |
| if( nSeriesIdx < maSeries.size() ) |
| maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second ); |
| } |
| |
| /* #i51639# (part 2): Finalize data formats of all series. This adds for |
| example missing CHDATAFORMAT groups for entire series that are needed |
| for automatic colors of lines and areas. */ |
| for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt ) |
| (*aVIt)->FinalizeDataFormats(); |
| } |
| |
| void XclImpChChart::FinalizeTitle() |
| { |
| // special handling for auto-generated title |
| String aAutoTitle; |
| if( !mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString()) ) |
| { |
| // automatic title from first series name (if there are no series on secondary axes set) |
| if( !mxSecnAxesSet->IsValidAxesSet() ) |
| aAutoTitle = mxPrimAxesSet->GetSingleSeriesTitle(); |
| if( mxTitle.is() || (aAutoTitle.Len() > 0) ) |
| { |
| if( !mxTitle ) |
| mxTitle.reset( new XclImpChText( GetChRoot() ) ); |
| if( aAutoTitle.Len() == 0 ) |
| aAutoTitle = CREATE_STRING( "Chart Title" ); |
| } |
| } |
| |
| // will reset mxTitle, if it does not contain a string and no auto title exists |
| lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ), aAutoTitle ); |
| } |
| |
| Reference< XDiagram > XclImpChChart::CreateDiagram() const |
| { |
| // create a diagram object |
| Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY ); |
| |
| // convert global chart settings |
| ScfPropertySet aDiaProp( xDiagram ); |
| |
| // treatment of missing values |
| using namespace cssc::MissingValueTreatment; |
| sal_Int32 nMissingValues = LEAVE_GAP; |
| switch( maProps.mnEmptyMode ) |
| { |
| case EXC_CHPROPS_EMPTY_SKIP: nMissingValues = LEAVE_GAP; break; |
| case EXC_CHPROPS_EMPTY_ZERO: nMissingValues = USE_ZERO; break; |
| case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE; break; |
| } |
| aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues ); |
| |
| return xDiagram; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot& rRoot, bool bOwnTab ) : |
| XclImpDrawing( rRoot, bOwnTab ), // sheet charts may contain OLE objects |
| mnScTab( rRoot.GetCurrScTab() ), |
| mbOwnTab( bOwnTab ) |
| { |
| } |
| |
| void XclImpChartDrawing::ConvertObjects( XclImpDffConverter& rDffConv, |
| const Reference< XModel >& rxModel, const Rectangle& rChartRect ) |
| { |
| maChartRect = rChartRect; // needed in CalcAnchorRect() callback |
| |
| SdrModel* pSdrModel = 0; |
| SdrPage* pSdrPage = 0; |
| if( mbOwnTab ) |
| { |
| // chart sheet: insert all shapes into the sheet, not into the chart object |
| pSdrModel = GetDoc().GetDrawLayer(); |
| pSdrPage = GetSdrPage( mnScTab ); |
| } |
| else |
| { |
| // embedded chart object: insert all shapes into the chart |
| try |
| { |
| Reference< XDrawPageSupplier > xDrawPageSupp( rxModel, UNO_QUERY_THROW ); |
| Reference< XDrawPage > xDrawPage( xDrawPageSupp->getDrawPage(), UNO_SET_THROW ); |
| pSdrPage = ::GetSdrPageFromXDrawPage( xDrawPage ); |
| pSdrModel = pSdrPage ? pSdrPage->GetModel() : 0; |
| } |
| catch( Exception& ) |
| { |
| } |
| } |
| |
| if( pSdrModel && pSdrPage ) |
| ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage ); |
| } |
| |
| Rectangle XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool bDffAnchor ) const |
| { |
| /* In objects with DFF client anchor, the position of the shape is stored |
| in the cell address components of the client anchor. In old BIFF3-BIFF5 |
| objects, the position is stored in the offset components of the anchor. */ |
| Rectangle aRect( |
| static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnCol : rAnchor.mnLX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ), |
| static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnRow : rAnchor.mnTY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ), |
| static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnCol : rAnchor.mnRX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ), |
| static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnRow : rAnchor.mnBY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ) ); |
| aRect.Justify(); |
| // move shapes into chart area for sheet charts |
| if( mbOwnTab ) |
| aRect.Move( maChartRect.Left(), maChartRect.Top() ); |
| return aRect; |
| } |
| |
| void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase& ) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) : |
| XclImpRoot( rRoot ), |
| mbOwnTab( bOwnTab ), |
| mbIsPivotChart( false ) |
| { |
| } |
| |
| XclImpChart::~XclImpChart() |
| { |
| } |
| |
| void XclImpChart::ReadChartSubStream( XclImpStream& rStrm ) |
| { |
| XclImpPageSettings& rPageSett = GetPageSettings(); |
| XclImpTabViewSettings& rTabViewSett = GetTabViewSettings(); |
| |
| bool bLoop = true; |
| while( bLoop && rStrm.StartNextRecord() ) |
| { |
| // page settings - only for charts in entire sheet |
| if( mbOwnTab ) switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_HORPAGEBREAKS: |
| case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( rStrm ); break; |
| case EXC_ID_HEADER: |
| case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( rStrm ); break; |
| case EXC_ID_LEFTMARGIN: |
| case EXC_ID_RIGHTMARGIN: |
| case EXC_ID_TOPMARGIN: |
| case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( rStrm ); break; |
| case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( rStrm ); break; |
| case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm ); break; |
| case EXC_ID_HCENTER: |
| case EXC_ID_VCENTER: rPageSett.ReadCenter( rStrm ); break; |
| case EXC_ID_SETUP: rPageSett.ReadSetup( rStrm ); break; |
| case EXC_ID8_IMGDATA: rPageSett.ReadImgData( rStrm ); break; |
| |
| case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( rStrm, true );break; |
| case EXC_ID_SCL: rTabViewSett.ReadScl( rStrm ); break; |
| |
| case EXC_ID_SHEETEXT: //0x0862 |
| { |
| // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root |
| XclImpPalette& rPal = GetPalette(); |
| rTabViewSett.ReadTabBgColor( rStrm, rPal); |
| } |
| break; |
| |
| case EXC_ID_CODENAME: ReadCodeName( rStrm, false ); break; |
| } |
| |
| // common records |
| switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_EOF: bLoop = false; break; |
| |
| // #i31882# ignore embedded chart objects |
| case EXC_ID2_BOF: |
| case EXC_ID3_BOF: |
| case EXC_ID4_BOF: |
| case EXC_ID5_BOF: XclTools::SkipSubStream( rStrm ); break; |
| |
| case EXC_ID_CHCHART: ReadChChart( rStrm ); break; |
| |
| case EXC_ID8_CHPIVOTREF: |
| GetTracer().TracePivotChartExists(); |
| mbIsPivotChart = true; |
| break; |
| |
| // BIFF specific records |
| default: switch( GetBiff() ) |
| { |
| case EXC_BIFF5: switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break; |
| } |
| break; |
| case EXC_BIFF8: switch( rStrm.GetRecId() ) |
| { |
| case EXC_ID_MSODRAWING: GetChartDrawing().ReadMsoDrawing( rStrm ); break; |
| // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format |
| case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break; |
| } |
| break; |
| default:; |
| } |
| } |
| } |
| } |
| |
| void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData ) |
| { |
| if( !mxChartData ) |
| mxChartData.reset( new XclImpChChart( GetRoot() ) ); |
| mxChartData->UpdateObjFrame( rLineData, rFillData ); |
| } |
| |
| sal_Size XclImpChart::GetProgressSize() const |
| { |
| return |
| (mxChartData.is() ? mxChartData->GetProgressSize() : 0) + |
| (mxChartDrawing.is() ? mxChartDrawing->GetProgressSize() : 0); |
| } |
| |
| void XclImpChart::Convert( Reference< XModel > xModel, XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const |
| { |
| Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY ); |
| if( xChartDoc.is() ) |
| { |
| if( mxChartData.is() ) |
| mxChartData->Convert( xChartDoc, rDffConv, rObjName, rChartRect ); |
| if( mxChartDrawing.is() ) |
| mxChartDrawing->ConvertObjects( rDffConv, xModel, rChartRect ); |
| } |
| } |
| |
| XclImpChartDrawing& XclImpChart::GetChartDrawing() |
| { |
| if( !mxChartDrawing ) |
| mxChartDrawing.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab ) ); |
| return *mxChartDrawing; |
| } |
| |
| void XclImpChart::ReadChChart( XclImpStream& rStrm ) |
| { |
| mxChartData.reset( new XclImpChChart( GetRoot() ) ); |
| mxChartData->ReadRecordGroup( rStrm ); |
| } |
| |
| // ============================================================================ |
| |