Quellverzeichnis seriesconverter.cxx
Sprache: unbekannt
|
|
Columbo aufrufen.cxx zum Wurzelverzeichnis wechselnUnknown {[0] [0] [0]}Datei anzeigen
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#include <drawingml/chart/seriesconverter.hxx>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
#include <com/sun/star/chart2/RelativePosition.hpp>
#include <com/sun/star/chart2/RelativeSize.hpp>
#include <com/sun/star/chart/ErrorBarStyle.hpp>
#include <com/sun/star/chart2/DataPointLabel.hpp>
#include <com/sun/star/drawing/Hatch.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
#include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
#include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
#include <com/sun/star/chart2/XDataSeries.hpp>
#include <com/sun/star/chart2/XRegressionCurve.hpp>
#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
#include <com/sun/star/chart2/data/XDataSink.hpp>
#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <comphelper/sequence.hxx>
#include <osl/diagnose.h>
#include <drawingml/chart/datasourceconverter.hxx>
#include <drawingml/chart/seriesmodel.hxx>
#include <drawingml/chart/titleconverter.hxx>
#include <drawingml/chart/typegroupconverter.hxx>
#include <drawingml/chart/typegroupmodel.hxx>
#include <drawingml/fillproperties.hxx>
#include <oox/core/xmlfilterbase.hxx>
#include <oox/helper/modelobjecthelper.hxx>
#include <oox/token/properties.hxx>
#include <oox/token/tokens.hxx>
#include <drawingml/lineproperties.hxx>
#include <drawingml/textparagraph.hxx>
#include <drawingml/textrun.hxx>
#include <drawingml/textfield.hxx>
#include <drawingml/textbody.hxx>
#include <drawingml/hatchmap.hxx>
namespace oox::drawingml::chart {
using namespace com::sun::star;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::chart2;
using namespace ::com::sun::star::chart2::data;
using namespace ::com::sun::star::uno;
namespace {
Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
const ConverterRoot& rParent,
DataSourceModel* pValues, const OUString& rRole,
TextModel* pTitle = nullptr )
{
// create data sequence for values
Reference< XDataSequence > xValueSeq;
if( pValues )
{
DataSourceConverter aSourceConv( rParent, *pValues );
xValueSeq = aSourceConv.createDataSequence( rRole );
}
// create data sequence for title
Reference< XDataSequence > xTitleSeq;
if( pTitle )
{
TextConverter aTextConv( rParent, *pTitle );
xTitleSeq = aTextConv.createDataSequence( u"label"_ustr );
}
// create the labeled data sequence, if values or title are present
Reference< XLabeledDataSequence > xLabeledSeq;
if( xValueSeq.is() || xTitleSeq.is() )
{
xLabeledSeq = LabeledDataSequence::create(rParent.getComponentContext());
if( xLabeledSeq.is() )
{
xLabeledSeq->setValues( xValueSeq );
xLabeledSeq->setLabel( xTitleSeq );
}
}
return xLabeledSeq;
}
void convertTextProperty(PropertySet& rPropSet, ObjectFormatter& rFormatter,
DataLabelModelBase::TextBodyRef xTextProps)
{
rFormatter.convertTextFormatting( rPropSet, xTextProps, OBJECTTYPE_DATALABEL );
ObjectFormatter::convertTextRotation( rPropSet, xTextProps, false );
ObjectFormatter::convertTextWrap( rPropSet, xTextProps );
}
void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rForm atter,
DataLabelModelBase& rDataLabel, const TypeGroupConverter& rTypeGroup,
bool bDataSeriesLabel, bool bCustomLabelField, bool bHasInternalData, bool bMSO2007Doc )
{
const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
/* Excel 2007 does not change the series setting for a single data point,
if none of some specific elements occur. But only one existing element
in a data point will reset most other of these elements from the series
(e.g.: series has <c:showVal>, data point has <c:showCatName>, this
will reset <c:showVal> for this point, unless <c:showVal> is repeated
in the data point). The elements <c:layout>, <c:numberFormat>,
<c:spPr>, <c:tx>, and <c:txPr> are not affected at all. */
bool bHasAnyElement = true;
if (bMSO2007Doc)
{
bHasAnyElement = rDataLabel.moaSeparator.has_value() || rDataLabel.monLabelPos.has_value() ||
rDataLabel.mobShowCatName.has_value() || rDataLabel.mobShowLegendKey.has_value() ||
rDataLabel.mobShowPercent.has_value() || rDataLabel.mobShowSerName.has_value() ||
rDataLabel.mobShowVal.has_value();
}
bool bShowValue = !rDataLabel.mbDeleted && rDataLabel.mobShowVal.value_or( !bMSO2007Doc );
bool bShowPercent = !rDataLabel.mbDeleted && rDataLabel.mobShowPercent.value_or( !bMSO2007Doc ) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE);
bool bShowCateg = !rDataLabel.mbDeleted && rDataLabel.mobShowCatName.value_or( !bMSO2007Doc );
bool bShowSerName = !rDataLabel.mbDeleted && rDataLabel.mobShowSerName.value_or( !bMSO2007Doc );
bool bShowSymbol = !rDataLabel.mbDeleted && rDataLabel.mobShowLegendKey.value_or( !bMSO2007Doc );
// tdf#132174, tdf#136650: the inner data table has no own cell number format.
if( bHasInternalData && bShowValue && !bShowPercent )
rDataLabel.maNumberFormat.mbSourceLinked = false;
// type of attached label
if( bHasAnyElement || rDataLabel.mbDeleted )
{
DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol, bCustomLabelField, bShowSerName );
rPropSet.setProperty( PROP_Label, aPointLabel );
}
if( rDataLabel.mbDeleted )
return;
// data label number format (percentage format wins over value format)
rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, false, bShowPercent );
// data label text formatting (frame formatting not supported by Chart2)
if( bDataSeriesLabel || (rDataLabel.mxTextProp.is() && !rDataLabel.mxTextProp->getParagraphs().empty()) )
convertTextProperty(rPropSet, rFormatter, rDataLabel.mxTextProp);
// data label separator (do not overwrite series separator, if no explicit point separator is present)
// Set the data label separator to "new line" if the value is shown as percentage with a category name,
// just like in MS-Office. In any other case the default separator will be a semicolon.
if( bShowPercent && !bShowValue && ( bDataSeriesLabel || rDataLabel.moaSeparator.has_value() ) )
rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.value_or( "\n" ) );
else if( bDataSeriesLabel || rDataLabel.moaSeparator.has_value() )
rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.value_or( "; " ) );
// data label placement (do not overwrite series placement, if no explicit point placement is present)
if( !(bDataSeriesLabel || rDataLabel.monLabelPos.has_value()) )
return;
namespace csscd = css::chart::DataLabelPlacement;
sal_Int32 nPlacement = -1;
switch( rDataLabel.monLabelPos.value_or( XML_TOKEN_INVALID ) )
{
case XML_outEnd: nPlacement = csscd::OUTSIDE; break;
case XML_inEnd: nPlacement = csscd::INSIDE; break;
case XML_ctr: nPlacement = csscd::CENTER; break;
case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break;
case XML_t: nPlacement = csscd::TOP; break;
case XML_b: nPlacement = csscd::BOTTOM; break;
case XML_l: nPlacement = csscd::LEFT; break;
case XML_r: nPlacement = csscd::RIGHT; break;
case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break;
}
if( !bDataSeriesLabel && nPlacement == -1 )
return;
if( nPlacement == -1 )
nPlacement = rTypeInfo.mnDefLabelPos;
rPropSet.setProperty( PROP_LabelPlacement, nPlacement );
}
void importBorderProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper )
{
LineProperties& rLP = rShape.getLineProperties();
// no fill has the same effect as no border so skip it
if (rLP.maLineFill.moFillType.has_value() && rLP.maLineFill.moFillType.value() == XML_noFill)
return;
if (rLP.moLineWidth.has_value())
{
sal_Int32 nWidth = convertEmuToHmm(rLP.moLineWidth.value());
rPropSet.setProperty(PROP_LabelBorderWidth, uno::Any(nWidth));
rPropSet.setProperty(PROP_LabelBorderStyle, uno::Any(drawing::LineStyle_SOLID));
}
const Color& aColor = rLP.maLineFill.maFillColor;
::Color nColor = aColor.getColor(rGraphicHelper);
rPropSet.setProperty(PROP_LabelBorderColor, uno::Any(nColor));
}
void lcl_ImportLeaderLineProperties(PropertySet& rPropSet, Shape& rShape,
const GraphicHelper& rGraphicHelper)
{
LineProperties& rLP = rShape.getLineProperties();
// no fill has the same effect as no line so skip it
if (rLP.maLineFill.moFillType.has_value() && rLP.maLineFill.moFillType.value() == XML_noFill)
return;
if (rLP.moLineWidth.has_value())
{
sal_Int32 nWidth = convertEmuToHmm(rLP.moLineWidth.value());
rPropSet.setProperty(PROP_LineWidth, uno::Any(nWidth));
}
if (rLP.maLineFill.moFillType.has_value() && rLP.maLineFill.moFillType.value() == XML_solidFill)
{
const Color& aColor = rLP.maLineFill.maFillColor;
::Color nColor = aColor.getColor(rGraphicHelper);
rPropSet.setProperty(PROP_LineColor, uno::Any(nColor));
}
}
void importFillProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper, ModelObjectHelper& rModelObjHelper )
{
FillProperties& rFP = rShape.getFillProperties();
if (rFP.moFillType.has_value() && rFP.moFillType.value() == XML_solidFill)
{
rPropSet.setProperty(PROP_LabelFillStyle, drawing::FillStyle_SOLID);
const Color& aColor = rFP.maFillColor;
::Color nColor = aColor.getColor(rGraphicHelper);
rPropSet.setProperty(PROP_LabelFillColor, uno::Any(nColor));
}
else if(rFP.moFillType.has_value() && rFP.moFillType.value() == XML_pattFill)
{
rPropSet.setProperty(PROP_LabelFillStyle, drawing::FillStyle_HATCH);
rPropSet.setProperty(PROP_LabelFillBackground, true);
Color aHatchColor( rFP.maPatternProps.maPattFgColor );
drawing::Hatch aHatch = createHatch(rFP.maPatternProps.moPattPreset.value(), aHatchColor.getColor(rGraphicHelper, 0));
OUString sHatchName = rModelObjHelper.insertFillHatch(aHatch);
rPropSet.setProperty(PROP_LabelFillHatchName, sHatchName);
const Color& aColor = rFP.maPatternProps.maPattBgColor;
::Color nColor = aColor.getColor(rGraphicHelper);
rPropSet.setProperty(PROP_LabelFillColor, uno::Any(nColor));
}
}
DataPointCustomLabelFieldType lcl_ConvertFieldNameToFieldEnum( std::u16string_view rField )
{
if (rField == u"VALUE")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_VALUE;
else if (rField == u"SERIESNAME")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_SERIESNAME;
else if (rField == u"CATEGORYNAME")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CATEGORYNAME;
else if (rField == u"CELLREF")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLREF;
else if (rField == u"CELLRANGE")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE;
else if (rField == u"PERCENTAGE")
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_PERCENTAGE;
else
return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT;
}
} // namespace
DataLabelConverter::DataLabelConverter( const ConverterRoot& rParent, DataLabelModel& rModel ) :
ConverterBase< DataLabelModel >( rParent, rModel )
{
}
DataLabelConverter::~DataLabelConverter()
{
}
void DataLabelConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup )
{
if (!rxDataSeries.is())
return;
try
{
bool bMSO2007Doc = getFilter().isMSO2007Document();
bool bHasInternalData = getChartDocument()->hasInternalDataProvider();
bool bCustomLabelField = mrModel.mxText && mrModel.mxText->mxTextBody && !mrModel.mxText->mxTextBody->getParagraphs().empty();
PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false, bCustomLabelField, bHasInternalData, bMSO2007Doc );
const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout )
{
RelativePosition aPos(mrModel.mxLayout->mfX, mrModel.mxLayout->mfY, css::drawing::Alignment_TOP_LEFT);
aPropSet.setProperty(PROP_CustomLabelPosition, aPos);
const RelativeSize aSize(mrModel.mxLayout->mfW, mrModel.mxLayout->mfH);
aPropSet.setProperty(PROP_CustomLabelSize, aSize);
sal_Int32 nPlacement = -1;
if (bIsPie && aPropSet.getProperty(nPlacement, PROP_LabelPlacement)
&& nPlacement == css::chart::DataLabelPlacement::AVOID_OVERLAP)
aPropSet.setProperty(PROP_LabelPlacement, css::chart::DataLabelPlacement::CUSTOM);
}
if (mrModel.mxShapeProp)
{
importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
uno::Reference<lang::XMultiServiceFactory> xFactory(getChartDocument(), uno::UNO_QUERY);
ModelObjectHelper& rHelper = getFilter().getModelObjectHelperForModel(xFactory);
importFillProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper(),
rHelper);
}
if( bCustomLabelField )
{
css::uno::Reference< XComponentContext > xContext = getComponentContext();
auto& rParagraphs = mrModel.mxText->mxTextBody->getParagraphs();
int nSequenceSize = 0;
for( auto& pParagraph : rParagraphs )
nSequenceSize += pParagraph->getRuns().size();
int nParagraphs = rParagraphs.size();
if( nParagraphs > 1 )
nSequenceSize += nParagraphs - 1;
std::optional< OUString > oaLabelText;
std::optional< OUString > oaCellRange;
if (mrModel.mobShowDataLabelsRange.value_or(false))
{
const DataSourceModel* pLabelSource = mrModel.mrParent.mpLabelsSource;
if (pLabelSource && pLabelSource->mxDataSeq.is())
{
oaCellRange = pLabelSource->mxDataSeq->maFormula;
const auto& rLabelMap = pLabelSource->mxDataSeq->maData;
const auto aKV = rLabelMap.find(mrModel.mnIndex);
if (aKV != rLabelMap.end())
{
oaLabelText.emplace();
aKV->second >>= *oaLabelText;
}
}
}
uno::Sequence< css::uno::Reference< XDataPointCustomLabelField > > aSequence( nSequenceSize );
auto aSequenceRange = asNonConstRange(aSequence);
int nPos = 0;
for( auto& pParagraph : rParagraphs )
{
for( auto& pRun : pParagraph->getRuns() )
{
css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
// Store properties
oox::PropertySet aPropertySet( xCustomLabel );
convertTextProperty( aPropertySet, getFormatter(), mrModel.mxText->mxTextBody );
pRun->getTextCharacterProperties().pushToPropSet( aPropertySet, getFilter() );
if (TextField* pField = dynamic_cast<TextField*>(pRun.get()))
{
DataPointCustomLabelFieldType eType = lcl_ConvertFieldNameToFieldEnum( pField->getType() );
if (eType == DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE && oaCellRange.has_value())
{
xCustomLabel->setCellRange( oaCellRange.value() );
xCustomLabel->setString( oaLabelText.value_or("") );
xCustomLabel->setDataLabelsRange( true );
}
else
xCustomLabel->setString( pField->getText() );
xCustomLabel->setFieldType( eType );
xCustomLabel->setGuid( pField->getUuid() );
}
else
{
xCustomLabel->setString( pRun->getText() );
xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT );
}
aSequenceRange[ nPos++ ] = std::move(xCustomLabel);
}
if( nParagraphs > 1 && nPos < nSequenceSize )
{
css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_NEWLINE );
xCustomLabel->setString(u"\n"_ustr);
aSequenceRange[ nPos++ ] = std::move(xCustomLabel);
}
}
aPropSet.setProperty( PROP_CustomLabelFields, Any( aSequence ) );
convertTextProperty(aPropSet, getFormatter(), mrModel.mxText->mxTextBody);
}
}
catch( Exception& )
{
}
}
DataLabelsConverter::DataLabelsConverter( const ConverterRoot& rParent, DataLabelsModel& rModel ) :
ConverterBase< DataLabelsModel >( rParent, rModel )
{
}
DataLabelsConverter::~DataLabelsConverter()
{
}
namespace
{
/// Inherit <c:dLbl> text props (if not set) from <c:dLbls> text props (if set).
void InheritFromDataLabelsTextProps(const DataLabelsModel& rLabels, const DataLabelModel& rLabel)
{
// See if <c:dLbls> contains text properties to inherit.
if (!rLabels.mxTextProp.is() || rLabels.mxTextProp->getParagraphs().empty())
{
return;
}
const std::shared_ptr<TextParagraph>& rLabelsParagraph = rLabels.mxTextProp->getParagraphs()[0];
// See if <c:dLbl> lacks text properties.
if (rLabel.mxTextProp.is())
{
return;
}
if (!rLabel.mxText || !rLabel.mxText->mxTextBody
|| rLabel.mxText->mxTextBody->getParagraphs().empty())
{
return;
}
const std::shared_ptr<TextParagraph>& rLabelParagraph
= rLabel.mxText->mxTextBody->getParagraphs()[0];
// Inherit rLabel.mxText's char props from rLabels.mxTextProp's char props.
TextCharacterProperties aCharProps;
aCharProps.assignUsed(rLabelsParagraph->getProperties().getTextCharacterProperties());
aCharProps.assignUsed(rLabelParagraph->getProperties().getTextCharacterProperties());
rLabelParagraph->getProperties().getTextCharacterProperties().assignUsed(aCharProps);
}
}
void DataLabelsConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup )
{
PropertySet aPropSet( rxDataSeries );
if( !mrModel.mbDeleted )
{
bool bMSO2007Doc = getFilter().isMSO2007Document();
bool bHasInternalData = getChartDocument()->hasInternalDataProvider();
lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true, false, bHasInternalData, bMSO2007Doc );
if (mrModel.mxShapeProp)
{
// Import baseline border properties for these data labels.
importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
uno::Reference<lang::XMultiServiceFactory> xFactory(getChartDocument(), uno::UNO_QUERY);
ModelObjectHelper& rHelper = getFilter().getModelObjectHelperForModel(xFactory);
importFillProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper(),
rHelper);
}
}
// import leaderline of data labels
if( !mrModel.mbShowLeaderLines )
aPropSet.setProperty( PROP_ShowCustomLeaderLines, false );
if (mrModel.mxLeaderLines)
{
// Import leaderline properties (SolidFill color, and width)
lcl_ImportLeaderLineProperties(aPropSet, *mrModel.mxLeaderLines,
getFilter().getGraphicHelper());
}
// data point label settings
for (auto const& pointLabel : mrModel.maPointLabels)
{
if (pointLabel->maNumberFormat.maFormatCode.isEmpty())
pointLabel->maNumberFormat = mrModel.maNumberFormat;
InheritFromDataLabelsTextProps(mrModel, *pointLabel);
DataLabelConverter aLabelConv(*this, *pointLabel);
aLabelConv.convertFromModel( rxDataSeries, rTypeGroup );
}
}
ErrorBarConverter::ErrorBarConverter( const ConverterRoot& rParent, ErrorBarModel& rModel ) :
ConverterBase< ErrorBarModel >( rParent, rModel )
{
}
ErrorBarConverter::~ErrorBarConverter()
{
}
void ErrorBarConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
{
bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both);
bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both);
if( !(bShowPos || bShowNeg) )
return;
try
{
Reference< XPropertySet > xErrorBar( createInstance( u"com.sun.star.chart2.ErrorBar"_ustr ), UNO_QUERY_THROW );
PropertySet aBarProp( xErrorBar );
// plus/minus bars
aBarProp.setProperty( PROP_ShowPositiveError, bShowPos );
aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg );
// type of displayed error
namespace cssc = css::chart;
switch( mrModel.mnValueType )
{
case XML_cust:
{
// #i87806# manual error bars
aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA );
// attach data sequences to error 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( bShowPos )
{
Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::PLUS );
if( xValueSeq.is() )
aLabeledSeqVec.push_back( xValueSeq );
}
// add negative values
if( bShowNeg )
{
Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::MINUS );
if( xValueSeq.is() )
aLabeledSeqVec.push_back( xValueSeq );
}
// attach labeled data sequences to series
if( aLabeledSeqVec.empty() )
xErrorBar.clear();
else
xDataSink->setData( comphelper::containerToSequence( aLabeledSeqVec ) );
}
}
break;
case XML_fixedVal:
aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE );
aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
break;
case XML_percentage:
aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE );
aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
break;
case XML_stdDev:
aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION );
aBarProp.setProperty( PROP_Weight, mrModel.mfValue );
break;
case XML_stdErr:
aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR );
break;
default:
OSL_FAIL( "ErrorBarConverter::convertFromModel - unknown error bar type" );
xErrorBar.clear();
}
// error bar formatting
getFormatter().convertFrameFormatting( aBarProp, mrModel.mxShapeProp, OBJECTTYPE_ERRORBAR );
if( xErrorBar.is() )
{
PropertySet aSeriesProp( rxDataSeries );
switch( mrModel.mnDirection )
{
case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break;
case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break;
default: OSL_FAIL( "ErrorBarConverter::convertFromModel - invalid error bar direction" );
}
}
}
catch( Exception& )
{
OSL_FAIL( "ErrorBarConverter::convertFromModel - error while creating error bars" );
}
}
Reference< XLabeledDataSequence > ErrorBarConverter::createLabeledDataSequence( ErrorBarModel::SourceType eSourceType )
{
OUString aRole;
switch( eSourceType )
{
case ErrorBarModel::PLUS:
switch( mrModel.mnDirection )
{
case XML_x: aRole = "error-bars-x-positive"; break;
case XML_y: aRole = "error-bars-y-positive"; break;
}
break;
case ErrorBarModel::MINUS:
switch( mrModel.mnDirection )
{
case XML_x: aRole = "error-bars-x-negative"; break;
case XML_y: aRole = "error-bars-y-negative"; break;
}
break;
}
OSL_ENSURE( !aRole.isEmpty(), "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" );
return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole );
}
TrendlineLabelConverter::TrendlineLabelConverter( const ConverterRoot& rParent, TrendlineLabelModel& rModel ) :
ConverterBase< TrendlineLabelModel >( rParent, rModel )
{
}
TrendlineLabelConverter::~TrendlineLabelConverter()
{
}
void TrendlineLabelConverter::convertFromModel( PropertySet& rPropSet )
{
// formatting
getFormatter().convertFormatting( rPropSet, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_TRENDLINELABEL );
}
TrendlineConverter::TrendlineConverter( const ConverterRoot& rParent, TrendlineModel& rModel ) :
ConverterBase< TrendlineModel >( rParent, rModel )
{
}
TrendlineConverter::~TrendlineConverter()
{
}
void TrendlineConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries )
{
try
{
// trend line type
OUString aServiceName;
switch( mrModel.mnTypeId )
{
case XML_exp:
aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve";
break;
case XML_linear:
aServiceName = "com.sun.star.chart2.LinearRegressionCurve";
break;
case XML_log:
aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve";
break;
case XML_movingAvg:
aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve";
break;
case XML_poly:
aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve";
break;
case XML_power:
aServiceName = "com.sun.star.chart2.PotentialRegressionCurve";
break;
default:
OSL_FAIL( "TrendlineConverter::convertFromModel - unknown trendline type" );
}
if( !aServiceName.isEmpty() )
{
Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW );
PropertySet aPropSet( xRegCurve );
// Name
aPropSet.setProperty( PROP_CurveName, mrModel.maName );
aPropSet.setProperty( PROP_PolynomialDegree, mrModel.mnOrder );
aPropSet.setProperty( PROP_MovingAveragePeriod, mrModel.mnPeriod );
// Intercept
bool hasIntercept = mrModel.mfIntercept.has_value();
aPropSet.setProperty( PROP_ForceIntercept, hasIntercept);
if (hasIntercept)
aPropSet.setProperty( PROP_InterceptValue, mrModel.mfIntercept.value());
// Extrapolation
if (mrModel.mfForward.has_value())
aPropSet.setProperty( PROP_ExtrapolateForward, mrModel.mfForward.value() );
if (mrModel.mfBackward.has_value())
aPropSet.setProperty( PROP_ExtrapolateBackward, mrModel.mfBackward.value() );
// trendline formatting
getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_TRENDLINE );
// #i83100# show equation and correlation coefficient
PropertySet aLabelProp( xRegCurve->getEquationProperties() );
aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation );
aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared );
// #i83100# formatting of the equation text box
if( mrModel.mbDispEquation || mrModel.mbDispRSquared )
{
TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() );
aLabelConv.convertFromModel( aLabelProp );
}
// unsupported: #i5085# manual trendline size
// unsupported: #i34093# manual crossing point
Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW );
xRegCurveCont->addRegressionCurve( xRegCurve );
}
}
catch( Exception& )
{
OSL_FAIL( "TrendlineConverter::convertFromModel - error while creating trendline" );
}
}
DataPointConverter::DataPointConverter( const ConverterRoot& rParent, DataPointModel& rModel ) :
ConverterBase< DataPointModel >( rParent, rModel )
{
}
DataPointConverter::~DataPointConverter()
{
}
void DataPointConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries,
const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries )
{
bool bMSO2007Doc = getFilter().isMSO2007Document();
try
{
PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
// data point marker
if( ( mrModel.monMarkerSymbol.has_value() && mrModel.monMarkerSymbol.value() != rSeries.mnMarkerSymbol ) ||
( mrModel.monMarkerSize.has_value() && mrModel.monMarkerSize.value() != rSeries.mnMarkerSize ) )
rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.value_or( rSeries.mnMarkerSymbol ),
mrModel.monMarkerSize.value_or( rSeries.mnMarkerSize ), mrModel.mxMarkerProp );
// data point pie explosion
if( mrModel.monExplosion.has_value() && mrModel.monExplosion.value() != rSeries.mnExplosion )
rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.value() );
// data point invert negative
if( mrModel.mbInvertNeg != rSeries.mbInvertNeg ) {
aPropSet.setProperty( PROP_InvertNegative, mrModel.mbInvertNeg);
}
// point formatting
if( mrModel.mxShapeProp.is() )
{
if( rTypeGroup.getTypeInfo().mbPictureOptions )
getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
else
getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
}
else if (rSeries.mxShapeProp.is())
{
getFormatter().convertFrameFormatting( aPropSet, rSeries.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
}
}
catch( Exception& )
{
}
}
SeriesConverter::SeriesConverter( const ConverterRoot& rParent, SeriesModel& rModel ) :
ConverterBase< SeriesModel >( rParent, rModel )
{
}
SeriesConverter::~SeriesConverter()
{
}
Reference< XLabeledDataSequence > SeriesConverter::createCategorySequence( const OUString& rRole )
{
return createLabeledDataSequence(SeriesModel::CATEGORIES, rRole, false);
}
Reference< XLabeledDataSequence > SeriesConverter::createValueSequence( const OUString& rRole )
{
return createLabeledDataSequence( SeriesModel::VALUES, rRole, true );
}
Reference< XDataSeries > SeriesConverter::createDataSeries( const TypeGroupConverter& rTypeGroup, bool bVaryColorsByPoint )
{
const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
// create the data series object
Reference< XDataSeries > xDataSeries( createInstance( u"com.sun.star.chart2.DataSeries"_ustr ), UNO_QUERY );
PropertySet aSeriesProp( xDataSeries );
// attach data and title sequences to series
sal_Int32 nDataPointCount = 0;
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( u"values-y"_ustr );
if( xYValueSeq.is() )
{
aLabeledSeqVec.push_back( xYValueSeq );
Reference< XDataSequence > xValues = xYValueSeq->getValues();
if( xValues.is() )
nDataPointCount = xValues->getData().getLength();
if (!nDataPointCount)
// No values present. Don't create a data series.
return Reference<XDataSeries>();
}
// add X values of scatter and bubble charts
if( !rTypeInfo.mbCategoryAxis )
{
Reference< XLabeledDataSequence > xXValueSeq = createCategorySequence( u"values-x"_ustr );
if( xXValueSeq.is() )
aLabeledSeqVec.push_back( xXValueSeq );
// add size values of bubble charts
if( rTypeInfo.meTypeId == TYPEID_BUBBLE )
{
Reference< XLabeledDataSequence > xSizeValueSeq = createLabeledDataSequence( SeriesModel::POINTS, u"values-size"_ustr, true );
if( xSizeValueSeq.is() )
aLabeledSeqVec.push_back( xSizeValueSeq );
}
}
// attach labeled data sequences to series
if( !aLabeledSeqVec.empty() )
xDataSink->setData( comphelper::containerToSequence( aLabeledSeqVec ) );
}
// error bars
for (auto const& errorBar : mrModel.maErrorBars)
{
ErrorBarConverter aErrorBarConv(*this, *errorBar);
aErrorBarConv.convertFromModel( xDataSeries );
}
// trendlines
for (auto const& trendLine : mrModel.maTrendlines)
{
TrendlineConverter aTrendlineConv(*this, *trendLine);
aTrendlineConv.convertFromModel( xDataSeries );
}
// data point markers
rTypeGroup.convertMarker( aSeriesProp, mrModel.mnMarkerSymbol, mrModel.mnMarkerSize, mrModel.mxMarkerProp );
#if OOX_CHART_SMOOTHED_PER_SERIES
// #i66858# smoothed series lines
rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth );
#endif
// 3D bar style (not possible to set at chart type -> set at all series)
rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.value_or( rTypeGroup.getModel().mnShape ) );
// pie explosion (restricted to [0%,100%] in Chart2)
rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion );
// invert if negative
aSeriesProp.setProperty(PROP_InvertNegative, mrModel.mbInvertNeg);
// series formatting
ObjectFormatter& rFormatter = getFormatter();
ObjectType eObjType = rTypeGroup.getSeriesObjectType();
bool bMSO2007Doc = getFilter().isMSO2007Document();
if( rTypeInfo.mbPictureOptions )
rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), eObjType, mrModel.mnIndex );
else
rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex );
// set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts)
bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
aSeriesProp.setProperty( PROP_VaryColorsByPoint, bVaryColorsByPoint );
// own area formatting for every data point (TODO: varying line color not supported)
// #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting
if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) )
{
/* Set the series point number as color cycle size at the object
formatter to get correct start-shade/end-tint. TODO: in doughnut
charts, the sizes of the series may vary, need to use the maximum
point count of all series. */
sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex();
if( bVaryColorsByPoint )
rFormatter.setMaxSeriesIndex( nDataPointCount - 1 );
for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex )
{
try
{
PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) );
rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex );
}
catch( Exception& )
{
}
}
rFormatter.setMaxSeriesIndex( nOldMax );
}
// data point settings
for (auto const& point : mrModel.maPoints)
{
DataPointConverter aPointConv(*this, *point);
aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel );
}
/* Series data label settings. If and only if the series does not contain
a c:dLbls element, then the c:dLbls element of the parent chart type is
used (data label settings of the parent chart type are *not* merged
into own existing data label settings). */
ModelRef< DataLabelsModel > xLabels = mrModel.mxLabels.is() ? mrModel.mxLabels : rTypeGroup.getModel().mxLabels;
if( xLabels.is() )
{
if( xLabels->maNumberFormat.maFormatCode.isEmpty() )
{
// Use number format code from Value series
DataSourceModel* pValues = mrModel.maSources.get( SeriesModel::VALUES ).get();
if( pValues )
xLabels->maNumberFormat.maFormatCode = pValues->mxDataSeq->maFormatCode;
}
DataLabelsConverter aLabelsConv( *this, *xLabels );
aLabelsConv.convertFromModel( xDataSeries, rTypeGroup );
}
return xDataSeries;
}
// private --------------------------------------------------------------------
Reference< XLabeledDataSequence > SeriesConverter::createLabeledDataSequence(
SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel )
{
DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get();
TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : nullptr;
return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle );
}
} // namespace oox
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
[ Original von:0.64Diese Quellcodebibliothek enthält Beispiele in vielen Programmiersprachen.
Man kann per Verzeichnistruktur darin navigieren.
Der Code wird farblich markiert angezeigt.
]
|
2026-04-04
|