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