LibreOffice Module oox (master)  1
converterbase.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/XAxisXSupplier.hpp>
23 #include <com/sun/star/chart/XAxisYSupplier.hpp>
24 #include <com/sun/star/chart/XAxisZSupplier.hpp>
25 #include <com/sun/star/chart/XChartDocument.hpp>
26 #include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
27 #include <com/sun/star/chart2/XChartDocument.hpp>
28 #include <com/sun/star/chart2/RelativePosition.hpp>
29 #include <com/sun/star/chart2/RelativeSize.hpp>
30 #include <com/sun/star/chart2/XTitle.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/uno/XComponentContext.hpp>
33 #include <osl/diagnose.h>
36 #include <oox/helper/helper.hxx>
37 #include <oox/token/properties.hxx>
38 #include <oox/token/tokens.hxx>
39 
40 
41 namespace oox::drawingml::chart {
42 
43 namespace cssc = ::com::sun::star::chart;
44 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::chart2;
47 using namespace ::com::sun::star::drawing;
48 using namespace ::com::sun::star::lang;
49 using namespace ::com::sun::star::uno;
50 
51 using ::oox::core::XmlFilterBase;
52 
53 namespace {
54 
55 struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > >
56 {
57  explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 )
58  { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; }
59 };
60 
64 struct TitleLayoutInfo
65 {
66  typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& );
67 
68  Reference< XTitle > mxTitle;
70  GetShapeFunc mpGetShape;
71 
72  explicit TitleLayoutInfo() : mpGetShape( nullptr ) {}
73 
74  void convertTitlePos(
75  ConverterRoot const & rRoot,
76  const Reference< cssc::XChartDocument >& rxChart1Doc );
77 };
78 
79 void TitleLayoutInfo::convertTitlePos( ConverterRoot const & rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc )
80 {
81  if( !(mxTitle.is() && mpGetShape) )
82  return;
83 
84  try
85  {
86  // try to get the title shape
87  Reference< XShape > xTitleShape = mpGetShape( rxChart1Doc );
88  // get title rotation angle, needed for correction of position of top-left edge
89  double fAngle = 0.0;
90  PropertySet aTitleProp( mxTitle );
91  aTitleProp.getProperty( fAngle, PROP_TextRotation );
92  // convert the position
93  LayoutModel& rLayout = mxLayout.getOrCreate();
94  LayoutConverter aLayoutConv( rRoot, rLayout );
95  aLayoutConv.convertFromModel( xTitleShape, fAngle );
96  }
97  catch( Exception& )
98  {
99  }
100 }
101 
102 /* The following local functions implement getting the XShape interface of all
103  supported title objects (chart and axes). This needs some effort due to the
104  design of the old Chart1 API used to access these objects. */
105 
108 #define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
109  PropertySet aPropSet( shape_supplier ); \
110  if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
111  return shape_supplier->supplier_func(); \
112  return Reference< XShape >(); \
113 
114 
116 #define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
117 Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
118 { \
119  Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
120  OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
121 }
122 
124 Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
125 {
126  OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
127 }
128 
129 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
130 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
131 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
132 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
133 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
134 
135 #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
136 #undef OOX_IMPLEMENT_GETTITLESHAPE
137 
138 } // namespace
139 
141 {
143  std::map< TitleKey, TitleLayoutInfo >
148  awt::Size maSize;
149 
150  explicit ConverterData(
151  XmlFilterBase& rFilter,
152  ChartConverter& rChartConverter,
153  const ChartSpaceModel& rChartModel,
154  const Reference< XChartDocument >& rxChartDoc,
155  const awt::Size& rChartSize );
156  ~ConverterData();
157 };
158 
160  XmlFilterBase& rFilter,
161  ChartConverter& rChartConverter,
162  const ChartSpaceModel& rChartModel,
163  const Reference< XChartDocument >& rxChartDoc,
164  const awt::Size& rChartSize ) :
165  maFormatter( rFilter, rxChartDoc, rChartModel ),
166  mrFilter( rFilter ),
167  mrConverter( rChartConverter ),
168  mxDoc( rxChartDoc ),
169  maSize( rChartSize )
170 {
171  OSL_ENSURE( mxDoc.is(), "ConverterData::ConverterData - missing chart document" );
172  // lock the model to suppress internal updates during conversion
173  try
174  {
175  mxDoc->lockControllers();
176  }
177  catch( Exception& )
178  {
179  }
180 
181  // prepare conversion of title positions
182  maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape;
183  maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape;
184  maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape;
185  maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape;
186  maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape;
187  maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape;
188 }
189 
191 {
192  // unlock the model
193  try
194  {
195  mxDoc->unlockControllers();
196  }
197  catch( Exception& )
198  {
199  }
200 }
201 
203  XmlFilterBase& rFilter,
204  ChartConverter& rChartConverter,
205  const ChartSpaceModel& rChartModel,
206  const Reference< XChartDocument >& rxChartDoc,
207  const awt::Size& rChartSize ) :
208  mxData( std::make_shared<ConverterData>( rFilter, rChartConverter, rChartModel, rxChartDoc, rChartSize ) )
209 {
210 }
211 
213 {
214 }
215 
216 Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
217 {
219  try
220  {
221  Reference<XMultiServiceFactory> xMSF(getComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW);
222 
223  xInt = xMSF->createInstance( rServiceName );
224  }
225  catch( Exception& )
226  {
227  }
228  OSL_ENSURE( xInt.is(), "ConverterRoot::createInstance - cannot create instance" );
229  return xInt;
230 }
231 
233 {
234  return mxData->mrFilter.getComponentContext();
235 }
236 
238 {
239  return mxData->mrFilter;
240 }
241 
243 {
244  return mxData->mrConverter;
245 }
246 
248 {
249  return mxData->mxDoc;
250 }
251 
252 const awt::Size& ConverterRoot::getChartSize() const
253 {
254  return mxData->maSize;
255 }
256 
258 {
259  return mxData->maFormatter;
260 }
261 
263  const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx )
264 {
265  OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" );
266  TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ];
267  OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" );
268  rTitleInfo.mxTitle = rxTitle;
269  rTitleInfo.mxLayout = rxLayout;
270 }
271 
273 {
274  try
275  {
276  Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW );
277  for (auto & title : mxData->maTitles)
278  title.second.convertTitlePos( *this, xChart1Doc );
279  }
280  catch( Exception& )
281  {
282  }
283 }
284 
285 namespace {
286 
288 sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode )
289 {
290  switch( nPosMode )
291  {
292  case XML_edge: // absolute start position as factor of chart size
293  return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize );
294  case XML_factor: // position relative to object default position
295  OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
296  return -1;
297  };
298 
299  OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
300  return -1;
301 }
302 
304 sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode )
305 {
306  sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize );
307  switch( nSizeMode )
308  {
309  case XML_factor: // passed value is width/height
310  return nValue;
311  case XML_edge: // passed value is right/bottom position
312  return nValue - nPos + 1;
313  };
314 
315  OSL_FAIL( "lclCalcSize - unknown size mode" );
316  return -1;
317 }
318 
320 double lclCalcRelSize( double fPos, double fSize, sal_Int32 nSizeMode )
321 {
322  switch( nSizeMode )
323  {
324  case XML_factor: // passed value is width/height
325  break;
326  case XML_edge: // passed value is right/bottom position
327  fSize -= fPos;
328  break;
329  default:
330  OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
331  fSize = 0.0;
332  };
333  return getLimitedValue< double, double >( fSize, 0.0, 1.0 - fPos );
334 }
335 
336 } // namespace
337 
339  ConverterBase< LayoutModel >( rParent, rModel )
340 {
341 }
342 
344 {
345 }
346 
347 bool LayoutConverter::calcAbsRectangle( awt::Rectangle& orRect ) const
348 {
349  if( !mrModel.mbAutoLayout )
350  {
351  awt::Size aChartSize = getChartSize();
352  if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
353  {
354  aChartSize = getDefaultPageSize();
355  }
356  orRect.X = lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode );
357  orRect.Y = lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode );
358  if( (orRect.X >= 0) && (orRect.Y >= 0) )
359  {
360  orRect.Width = lclCalcSize( orRect.X, aChartSize.Width, mrModel.mfW, mrModel.mnWMode );
361  orRect.Height = lclCalcSize( orRect.Y, aChartSize.Height, mrModel.mfH, mrModel.mnHMode );
362  return (orRect.Width > 0) && (orRect.Height > 0);
363  }
364  }
365  return false;
366 }
367 
369 {
370  if( !mrModel.mbAutoLayout &&
371  (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) &&
372  (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) )
373  {
374  RelativePosition aPos(
375  getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 ),
376  getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 ),
377  Alignment_TOP_LEFT );
378  rPropSet.setProperty( PROP_RelativePosition, aPos );
379 
380  RelativeSize aSize(
381  lclCalcRelSize( aPos.Primary, mrModel.mfW, mrModel.mnWMode ),
382  lclCalcRelSize( aPos.Secondary, mrModel.mfH, mrModel.mnHMode ) );
383  if( (aSize.Primary > 0.0) && (aSize.Secondary > 0.0) )
384  {
385  rPropSet.setProperty( PROP_RelativeSize, aSize );
386  return true;
387  }
388  }
389  return false;
390 }
391 
392 void LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle )
393 {
394  if( mrModel.mbAutoLayout )
395  return;
396 
397  awt::Size aChartSize = getChartSize();
398  if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
399  {
400  aChartSize = getDefaultPageSize();
401  }
402  awt::Point aShapePos(
403  lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode ),
404  lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode ) );
405  if( (aShapePos.X < 0) || (aShapePos.Y < 0) )
406  return;
407 
408  bool bPropSet = false;
409  // the call to XShape.getSize() may recalc the chart view
410  awt::Size aShapeSize = rxShape->getSize();
411  // rotated shapes need special handling...
412  if( aShapeSize.Height > 0 || aShapeSize.Width > 0 )
413  {
414  double fSin = fabs(sin(basegfx::deg2rad(fRotationAngle)));
415  // add part of height to X direction, if title is rotated down
416  if( fRotationAngle > 180.0 )
417  aShapePos.X += static_cast<sal_Int32>(fSin * aShapeSize.Height + 0.5);
418  // add part of width to Y direction, if title is rotated up
419  else if( fRotationAngle > 0.0 )
420  aShapePos.Y += static_cast<sal_Int32>(fSin * aShapeSize.Width + 0.5);
421  }
422  else if( fRotationAngle == 90.0 || fRotationAngle == 270.0 )
423  {
424  PropertySet aShapeProp( rxShape );
425  RelativePosition aPos(
426  getLimitedValue< double, double >(mrModel.mfX, 0.0, 1.0),
427  getLimitedValue< double, double >(mrModel.mfY, 0.0, 1.0),
428  fRotationAngle == 90.0 ? Alignment_TOP_RIGHT : Alignment_BOTTOM_LEFT );
429  // set the resulting position at the shape
430  if( aShapeProp.setProperty(PROP_RelativePosition, aPos) )
431  bPropSet = true;
432  }
433  // set the resulting position at the shape
434  if( !bPropSet )
435  rxShape->setPosition( aShapePos );
436 }
437 
438 } // namespace oox
439 
440 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 mnHMode
Mode for width.
Definition: modelbase.hxx:110
ObjectType
bool calcAbsRectangle(css::awt::Rectangle &orRect) const
Tries to calculate the absolute position and size from the contained OOXML layout model...
void convertTitlePositions()
Converts the positions of the main title and all axis titles.
constexpr double deg2rad(double v)
#define OOX_DEFINEFUNC_GETAXISTITLESHAPE(func_name, interface_type, supplier_func, property_name)
Implements a function returning the drawing shape of an axis title, if existing, using the specified ...
const sal_Int32 API_Y_AXIS
Base class of all converter classes.
ChartConverter & getChartConverter() const
Returns the chart converter.
double mfW
Top position of this object.
Definition: modelbase.hxx:105
std::shared_ptr< T > make_shared(Args &&...args)
ConverterData(XmlFilterBase &rFilter, ChartConverter &rChartConverter, const ChartSpaceModel &rChartModel, const Reference< XChartDocument > &rxChartDoc, const awt::Size &rChartSize)
ConverterRoot(::oox::core::XmlFilterBase &rFilter, ChartConverter &rChartConverter, const ChartSpaceModel &rChartModel, const css::uno::Reference< css::chart2::XChartDocument > &rxChartDoc, const css::awt::Size &rChartSize)
void registerTitleLayout(const css::uno::Reference< css::chart2::XTitle > &rxTitle, const ModelRef< LayoutModel > &rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx)
Registers a title object and its layout data, needed for conversion of the title position using the o...
double mfH
Width of this object.
Definition: modelbase.hxx:106
css::uno::Reference< css::uno::XInterface > createInstance(const OUString &rServiceName) const
Creates an instance for the passed service name, using the process service factory.
LayoutConverter(const ConverterRoot &rParent, LayoutModel &rModel)
ObjectType
Enumerates different object types for specific automatic formatting behaviour.
sal_Int32 mnWMode
Mode for top position.
Definition: modelbase.hxx:109
double mfY
Left position of this object.
Definition: modelbase.hxx:104
const sal_Int32 API_X_AXIS
std::shared_ptr< ConverterData > mxData
Reference< XTitle > mxTitle
std::map< TitleKey, TitleLayoutInfo > maTitles
css::uno::Reference< css::uno::XComponentContext > const & getComponentContext() const
const css::awt::Size & getChartSize() const
Returns the position and size of the chart shape in 1/100 mm.
#define OOX_FRAGMENT_GETTITLESHAPE(shape_supplier, supplier_func, property_name)
A code fragment that returns a shape object from the passed shape supplier using the specified interf...
A wrapper for a UNO property set.
Definition: propertyset.hxx:57
const sal_Int32 API_Z_AXIS
const sal_Int32 API_SECN_AXESSET
Reference< XChartDocument > mxDoc
std::u16string_view getTitle(std::u16string_view aPath)
sal_Int32 mnYMode
Mode for left position.
Definition: modelbase.hxx:108
ModelRef< LayoutModel > mxLayout
The API title object.
GetShapeFunc mpGetShape
The layout model, if existing.
const sal_Int32 API_PRIM_AXESSET
sal_Int32 mnXMode
Height of this object.
Definition: modelbase.hxx:107
bool mbAutoLayout
Layout target for plot area.
Definition: modelbase.hxx:112
::oox::core::XmlFilterBase & getFilter() const
Returns the filter object of the imported/exported document.
const PowerPointImport & mrFilter
Definition: pptimport.cxx:264
static css::awt::Size getDefaultPageSize()
Returns the default position and size of the chart shape in 1/100 mm.
css::uno::Reference< css::chart2::XChartDocument > const & getChartDocument() const
Returns the API chart document model.
constexpr OUStringLiteral first
bool convertFromModel(PropertySet &rPropSet)
Tries to set the position and size from the contained OOXML layout model.
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.
ObjectFormatter & getFormatter() const
Returns the object formatter.
::basegfx::B2IVector maSize
sal_Int16 nValue