LibreOffice Module oox (master) 1
chartspaceconverter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include <com/sun/star/chart/MissingValueTreatment.hpp>
23#include <com/sun/star/chart/XChartDocument.hpp>
24#include <com/sun/star/chart2/XChartDocument.hpp>
25#include <com/sun/star/chart2/XChartType.hpp>
26#include <com/sun/star/chart2/XChartTypeContainer.hpp>
27#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
28#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
29#include <com/sun/star/chart2/XTitled.hpp>
30#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
33#include <oox/token/properties.hxx>
34#include <oox/token/tokens.hxx>
39#include <ooxresid.hxx>
40#include <strings.hrc>
41
42using namespace ::com::sun::star;
43using ::com::sun::star::uno::Reference;
44using ::com::sun::star::uno::Exception;
45using ::com::sun::star::uno::UNO_QUERY;
46using ::com::sun::star::uno::UNO_QUERY_THROW;
47using ::com::sun::star::uno::Any;
48using ::com::sun::star::drawing::XDrawPageSupplier;
49using ::com::sun::star::drawing::XShapes;
50using ::com::sun::star::chart2::XDiagram;
51using ::com::sun::star::chart2::XTitled;
52
53namespace oox::drawingml::chart {
54
55using namespace ::com::sun::star::awt;
56using namespace ::com::sun::star::chart2;
57using namespace ::com::sun::star::chart2::data;
58using namespace ::com::sun::star::drawing;
59using namespace ::com::sun::star::uno;
60using namespace ::com::sun::star::util;
61
63 ConverterBase< ChartSpaceModel >( rParent, rModel )
64{
65}
66
68{
69}
70
71// Formulas with no numeric values and strings are zeroes in OOXML line charts also in the mode DispBlanksAs=gap,
72// unlike in OpenDocument LEAVE_GAP mode. As a workaround, we will use the OpenDocument mode USE_ZERO, if the OOXML
73// line chart has got formulas with no numeric values and strings, but it doesn't have empty cells, showing the
74// same chart as in MSO. (Empty cells need gaps, so in that case, we cannot use this workaround).
76{
77 Reference <chart2::XDiagram > xDiagram = xChartDoc->getFirstDiagram();
78 if ( !xDiagram.is() )
79 return false;
80
81 Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, UNO_QUERY_THROW );
82
83 Sequence< Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
84 if ( !xCooSysSequence.hasElements() )
85 return false;
86
87 Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], UNO_QUERY_THROW );
88
89 Sequence< Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
90 if ( !xChartTypeSequence.hasElements() )
91 return false;
92
93 const Reference<chart2::XChartType>& xCT = xChartTypeSequence[0];
94
95 if ( xCT->getChartType() != "com.sun.star.chart2.LineChartType" )
96 return false;
97
98 Reference<chart2::XDataSeriesContainer> xDSCont(xCT, uno::UNO_QUERY);
99
100 if (!xDSCont.is())
101 return false;
102
103 const Sequence<uno::Reference<chart2::XDataSeries> > aDataSeriesSeq = xDSCont->getDataSeries();
104
105 bool bHasNoGapBlankValue = false;
106 bool bHasEmptyCell = false;
107
108 for (const auto& rDataSeries : aDataSeriesSeq)
109 {
110 uno::Reference<chart2::data::XDataSource> xDSrc(rDataSeries, uno::UNO_QUERY);
111 if (!xDSrc.is())
112 return false;
113
114 const uno::Sequence<Reference<chart2::data::XLabeledDataSequence> > aDataSeqs = xDSrc->getDataSequences();
115 for (const auto& rDataSeq : aDataSeqs)
116 {
117 Reference<chart2::data::XDataSequence> xValues = rDataSeq->getValues();
118 if(!xValues.is())
119 return false;
120 Reference<beans::XPropertySet> xPropSet(xValues, uno::UNO_QUERY);
121 if (!xPropSet.is())
122 continue;
123
124 OUString aRoleName;
125 xPropSet->getPropertyValue("Role") >>= aRoleName;
126 if (aRoleName == "values-y")
127 {
128 const uno::Sequence<uno::Any> aData = xValues->getData();
129 for (const auto& rVal : aData)
130 {
131 double fVal;
132 OUString sStr;
133 if (rVal >>= fVal)
134 continue;
135 else if (rVal >>= sStr)
136 bHasNoGapBlankValue = true;
137 else
138 bHasEmptyCell = true;
139 }
140 }
141 }
142 }
143
144 return bHasNoGapBlankValue && !bHasEmptyCell;
145}
146
147void ChartSpaceConverter::convertFromModel( const Reference< XShapes >& rxExternalPage, const awt::Point& rChartPos )
148{
149 /* create data provider (virtual function in the ChartConverter class,
150 derived converters may create an external data provider) */
152
153 // formatting of the chart background. The default fill style varies with applications.
154 PropertySet aBackPropSet( getChartDocument()->getPageBackground() );
156
157 bool bMSO2007Doc = getFilter().isMSO2007Document();
158 // convert plot area (container of all chart type groups)
159 PlotAreaConverter aPlotAreaConv( *this, mrModel.mxPlotArea.getOrCreate() );
160 aPlotAreaConv.convertFromModel( mrModel.mxView3D.getOrCreate(bMSO2007Doc) );
161
162 // plot area converter has created the diagram object
163 Reference< XDiagram > xDiagram = getChartDocument()->getFirstDiagram();
164
165 // convert wall and floor formatting in 3D charts
166 if( xDiagram.is() && aPlotAreaConv.isWall3dChart() )
167 {
168 WallFloorConverter aFloorConv( *this, mrModel.mxFloor.getOrCreate() );
169 aFloorConv.convertFromModel( xDiagram, OBJECTTYPE_FLOOR );
170
171 WallFloorConverter aWallConv( *this, mrModel.mxBackWall.getOrCreate() );
172 aWallConv.convertFromModel( xDiagram, OBJECTTYPE_WALL );
173 }
174
175 // chart title
176 /* tdf#119138 autoTitleDeleted might be omitted by generators other than Excel
177 while providing custom title. mbAutoTitleDel is set only based on the attribute value
178 and the default also varies on whether MSO 2007 or newer is the generator, see tdf#78080 */
179 if( !mrModel.mbAutoTitleDel || mrModel.mxTitle.is() ) try
180 {
181 /* If the title model is missing, but the chart shows exactly one
182 series, the series title is shown as chart title. */
183 OUString aAutoTitle = aPlotAreaConv.getAutomaticTitle();
184 if( mrModel.mxTitle.is() || !aAutoTitle.isEmpty() )
185 {
186 if( aAutoTitle.isEmpty() )
187 aAutoTitle = OoxResId(STR_DIAGRAM_TITLE);
188 Reference< XTitled > xTitled( getChartDocument(), UNO_QUERY_THROW );
189 TitleConverter aTitleConv( *this, mrModel.mxTitle.getOrCreate() );
190 aTitleConv.convertFromModel( xTitled, aAutoTitle, OBJECTTYPE_CHARTTITLE );
191 }
192 }
193 catch( Exception& )
194 {
195 }
196
197 // legend
198 if( xDiagram.is() && mrModel.mxLegend.is() )
199 {
200 LegendConverter aLegendConv( *this, *mrModel.mxLegend );
201 aLegendConv.convertFromModel( xDiagram );
202 }
203
204 // treatment of missing values
205 if( xDiagram.is() )
206 {
207 using namespace ::com::sun::star::chart::MissingValueTreatment;
208 sal_Int32 nMissingValues = LEAVE_GAP;
209
210 // tdf#134118 leave gap if the time unit is month
211 bool bIsMonthBasedTimeUnit = false;
212 if( mrModel.mxPlotArea.is() && mrModel.mxPlotArea->maAxes.size() > 0 &&
213 mrModel.mxPlotArea->maAxes[0]->monBaseTimeUnit.has_value() )
214 {
215 bIsMonthBasedTimeUnit = mrModel.mxPlotArea->maAxes[0]->monBaseTimeUnit.value() == XML_months;
216 }
217
218 if (!bIsMonthBasedTimeUnit) switch( mrModel.mnDispBlanksAs )
219 {
220 case XML_gap: nMissingValues = LEAVE_GAP; break;
221 case XML_zero: nMissingValues = USE_ZERO; break;
222 case XML_span: nMissingValues = CONTINUE; break;
223 }
224
225 // use a workaround, if it's possible for the difference of OOXML and OpenDocument
226 if ( nMissingValues == LEAVE_GAP && lcl_useWorkaroundForNoGapInOOXML(getChartDocument()) )
227 nMissingValues = USE_ZERO;
228
229 PropertySet aDiaProp( xDiagram );
230 aDiaProp.setProperty( PROP_MissingValueTreatment, nMissingValues );
231 }
232
233 /* Following all conversions needing the old Chart1 API that involves full
234 initialization of the chart view. */
235 namespace cssc = ::com::sun::star::chart;
236 Reference< cssc::XChartDocument > xChart1Doc( getChartDocument(), UNO_QUERY );
237 if( xChart1Doc.is() )
238 {
239 /* Set the IncludeHiddenCells property via the old API as only this
240 ensures that the data provider and all created sequences get this
241 flag correctly. */
242 PropertySet aDiaProp( xChart1Doc->getDiagram() );
244
245 // plot area position and size
246 aPlotAreaConv.convertPositionFromModel();
247
248 // positions of main title and all axis titles
250 }
251
252 // embedded drawing shapes
253 if( !mrModel.maDrawingPath.isEmpty() ) try
254 {
255 /* Get the internal draw page of the chart document, if no external
256 drawing page has been passed. */
257 Reference< XShapes > xShapes;
258 awt::Point aShapesOffset( 0, 0 );
259 if( rxExternalPage.is() )
260 {
261 xShapes = rxExternalPage;
262 // offset for embedded shapes to move them inside the chart area
263 aShapesOffset = rChartPos;
264 }
265 else
266 {
267 Reference< XDrawPageSupplier > xDrawPageSupp( getChartDocument(), UNO_QUERY_THROW );
268 xShapes.set( xDrawPageSupp->getDrawPage(), UNO_QUERY_THROW );
269 }
270
271 /* If an external drawing page is passed, all embedded shapes will be
272 inserted there (used e.g. with 'chart sheets' in spreadsheet
273 documents). In this case, all types of shapes including OLE objects
274 are supported. If the shapes are inserted into the internal chart
275 drawing page instead, it is not possible to embed OLE objects. */
276 bool bOleSupport = rxExternalPage.is();
277
278 awt::Size aChartSize = getChartSize();
279 if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
280 aChartSize = getDefaultPageSize();
281
282 // now, xShapes is not null anymore
284 getFilter(), mrModel.maDrawingPath, xShapes, aChartSize, aShapesOffset, bOleSupport ) );
285 }
286 catch( Exception& )
287 {
288 }
289
290 // pivot chart
291 if ( mrModel.mbPivotChart )
292 {
293 PropertySet aProps( getChartDocument() );
294 aProps.setProperty( PROP_DisableDataTableDialog , true );
295 aProps.setProperty( PROP_DisableComplexChartTypes , true );
296 }
297
298 if(!mrModel.maSheetPath.isEmpty() )
299 {
301 PropertySet aProps( xChartDoc->getDiagram() );
303 }
304}
305
306} // namespace oox::drawingml::chart
307
308/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
A wrapper for a UNO property set.
Definition: propertyset.hxx:58
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.
bool importFragment(const rtl::Reference< FragmentHandler > &rxHandler)
Imports a fragment using the passed fragment handler, which contains the full path to the fragment st...
virtual void createDataProvider(const css::uno::Reference< css::chart2::XChartDocument > &rxChartDoc)
Creates an internal data provider.
Handler for a chart drawing fragment (c:userShapes root element).
ChartSpaceConverter(const ConverterRoot &rParent, ChartSpaceModel &rModel)
void convertFromModel(const css::uno::Reference< css::drawing::XShapes > &rxExternalPage, const css::awt::Point &rChartPos)
Converts the contained OOXML chart model to a chart2 document.
Base class of all converter classes.
::oox::core::XmlFilterBase & getFilter() const
Returns the filter object of the imported/exported document.
css::uno::Reference< css::chart2::XChartDocument > const & getChartDocument() const
Returns the API chart document model.
ChartConverter & getChartConverter() const
Returns the chart converter.
const css::awt::Size & getChartSize() const
Returns the position and size of the chart shape in 1/100 mm.
void convertTitlePositions()
Converts the positions of the main title and all axis titles.
ObjectFormatter & getFormatter() const
Returns the object formatter.
static css::awt::Size getDefaultPageSize()
Returns the default position and size of the chart shape in 1/100 mm.
void convertFromModel(const css::uno::Reference< css::chart2::XDiagram > &rxDiagram)
Creates a legend object and attaches it at the passed diagram.
void convertFrameFormatting(PropertySet &rPropSet, const ModelRef< Shape > &rxShapeProp, ObjectType eObjType, sal_Int32 nSeriesIdx=-1)
Sets frame formatting properties to the passed property set.
bool isWall3dChart() const
Returns true, if chart type supports wall and floor format in 3D mode.
const OUString & getAutomaticTitle() const
Returns the automatic chart title if the chart contains only one series.
void convertFromModel(View3DModel &rView3DModel)
Converts the OOXML plot area model to a chart2 diagram.
void convertPositionFromModel()
Converts the manual plot area position and size, if set.
void convertFromModel(const css::uno::Reference< css::chart2::XTitled > &rxTitled, const OUString &rAutoTitle, ObjectType eObjType, sal_Int32 nMainIdx=-1, sal_Int32 nSubIdx=-1)
Creates a title text object and attaches it at the passed interface.
void convertFromModel(const css::uno::Reference< css::chart2::XDiagram > &rxDiagram, ObjectType eObjType)
Converts the OOXML wall/floor model to a chart2 diagram.
@ Exception
static bool lcl_useWorkaroundForNoGapInOOXML(Reference< chart2::XChartDocument > const &xChartDoc)
@ OBJECTTYPE_FLOOR
Background and side wall in 3D charts.
@ OBJECTTYPE_WALL
Plot area containing axes and data series in 3D charts.
@ OBJECTTYPE_CHARTTITLE
Chart background.
GUIDCNamePair aData
Definition: olehelper.cxx:99
OUString OoxResId(TranslateId aId)
Definition: ooxresid.cxx:14
PlotAreaRef mxPlotArea
Global chart text formatting.
bool mbPivotChart
True = show labels over chart maximum.
LegendRef mxLegend
Chart main title.
bool mbAutoTitleDel
Index to default formatting.
bool mbPlotVisOnly
True = automatic title deleted manually.
WallFloorRef mxBackWall
Floor formatting in 3D charts.
sal_Int32 mnDispBlanksAs
Path to embedded charts.
View3DRef mxView3D
Side wall formatting in 3D charts.
WallFloorRef mxFloor
Plot area of the chart.
OUString maSheetPath
Path to drawing fragment with embedded shapes.
constexpr OUStringLiteral PROP_ExternalData
constexpr OUStringLiteral PROP_IncludeHiddenCells
constexpr OUStringLiteral PROP_MissingValueTreatment