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 
42 using namespace ::com::sun::star;
43 using ::com::sun::star::uno::Reference;
44 using ::com::sun::star::uno::Exception;
45 using ::com::sun::star::uno::UNO_QUERY;
46 using ::com::sun::star::uno::UNO_QUERY_THROW;
47 using ::com::sun::star::uno::makeAny;
48 using ::com::sun::star::drawing::XDrawPageSupplier;
49 using ::com::sun::star::drawing::XShapes;
50 using ::com::sun::star::chart2::XDiagram;
51 using ::com::sun::star::chart2::XTitled;
52 
53 namespace oox::drawingml::chart {
54 
55 using namespace ::com::sun::star::awt;
56 using namespace ::com::sun::star::chart2;
57 using namespace ::com::sun::star::chart2::data;
58 using namespace ::com::sun::star::drawing;
59 using namespace ::com::sun::star::uno;
60 using 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 
147 void 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() )
214  {
215  bIsMonthBasedTimeUnit = mrModel.mxPlotArea->maAxes[0]->monBaseTimeUnit.get() == 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() );
243  aDiaProp.setProperty( PROP_IncludeHiddenCells, !mrModel.mbPlotVisOnly );
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() );
302  aProps.setProperty( PROP_ExternalData , uno::makeAny(mrModel.maSheetPath) );
303  }
304 }
305 
306 } // namespace oox::drawingml::chart
307 
308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString OoxResId(std::string_view aId)
Definition: ooxresid.cxx:14
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.
void convertTitlePositions()
Converts the positions of the main title and all axis titles.
Base class of all converter classes.
ChartConverter & getChartConverter() const
Returns the chart converter.
void convertFromModel(const css::uno::Reference< css::chart2::XDiagram > &rxDiagram, ObjectType eObjType)
Converts the OOXML wall/floor model to a chart2 diagram.
bool mbPivotChart
True = show labels over chart maximum.
ChartSpaceConverter(const ConverterRoot &rParent, ChartSpaceModel &rModel)
bool importFragment(const rtl::Reference< FragmentHandler > &rxHandler)
Imports a fragment using the passed fragment handler, which contains the full path to the fragment st...
OUString maSheetPath
Path to drawing fragment with embedded shapes.
void convertFromModel(const css::uno::Reference< css::chart2::XDiagram > &rxDiagram)
Creates a legend object and attaches it at the passed diagram.
void convertFromModel(View3DModel &rView3DModel)
Converts the OOXML plot area model to a chart2 diagram.
void convertFrameFormatting(PropertySet &rPropSet, const ModelRef< Shape > &rxShapeProp, ObjectType eObjType, sal_Int32 nSeriesIdx=-1)
Sets frame formatting properties to the passed property set.
static bool lcl_useWorkaroundForNoGapInOOXML(Reference< chart2::XChartDocument > const &xChartDoc)
PlotAreaRef mxPlotArea
Global chart text formatting.
LegendRef mxLegend
Chart main title.
Plot area containing axes and data series in 3D charts.
View3DRef mxView3D
Side wall formatting in 3D charts.
bool mbPlotVisOnly
True = automatic title deleted manually.
const css::awt::Size & getChartSize() const
Returns the position and size of the chart shape in 1/100 mm.
A wrapper for a UNO property set.
Definition: propertyset.hxx:57
sal_Int32 mnDispBlanksAs
Path to embedded charts.
WallFloorRef mxFloor
Plot area of the chart.
bool mbAutoTitleDel
Index to default formatting.
WallFloorRef mxBackWall
Floor formatting in 3D charts.
::oox::core::XmlFilterBase & getFilter() const
Returns the filter object of the imported/exported document.
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.
static css::awt::Size getDefaultPageSize()
Returns the default position and size of the chart shape in 1/100 mm.
virtual void createDataProvider(const css::uno::Reference< css::chart2::XChartDocument > &rxChartDoc)
Creates an internal data provider.
Background and side wall in 3D charts.
css::uno::Reference< css::chart2::XChartDocument > const & getChartDocument() const
Returns the API chart document model.
Handler for a chart drawing fragment (c:userShapes root element).
GUIDCNamePair aData
Definition: olehelper.cxx:98
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.
ObjectFormatter & getFormatter() const
Returns the object formatter.