summaryrefslogtreecommitdiff
path: root/oox/source/drawingml/chart/converterbase.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/drawingml/chart/converterbase.cxx')
-rw-r--r--oox/source/drawingml/chart/converterbase.cxx265
1 files changed, 256 insertions, 9 deletions
diff --git a/oox/source/drawingml/chart/converterbase.cxx b/oox/source/drawingml/chart/converterbase.cxx
index 534ce48e0278..b5a0511bf1b8 100644
--- a/oox/source/drawingml/chart/converterbase.cxx
+++ b/oox/source/drawingml/chart/converterbase.cxx
@@ -30,6 +30,14 @@
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/chart/XAxisXSupplier.hpp>
+#include <com/sun/star/chart/XAxisYSupplier.hpp>
+#include <com/sun/star/chart/XAxisZSupplier.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <tools/solar.h> // for F_PI180
+#include "properties.hxx"
#include "oox/core/xmlfilterbase.hxx"
#include "oox/drawingml/theme.hxx"
@@ -37,22 +45,126 @@ using ::rtl::OUString;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::XInterface;
using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::UNO_QUERY;
using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
using ::com::sun::star::lang::XMultiServiceFactory;
using ::com::sun::star::frame::XModel;
+using ::com::sun::star::awt::Point;
+using ::com::sun::star::awt::Rectangle;
using ::com::sun::star::awt::Size;
+using ::com::sun::star::chart2::RelativePosition;
using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::chart2::XTitle;
+using ::com::sun::star::drawing::XShape;
using ::oox::core::XmlFilterBase;
+namespace cssc = ::com::sun::star::chart;
+
namespace oox {
namespace drawingml {
namespace chart {
// ============================================================================
+namespace {
+
+struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > >
+{
+ inline explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 )
+ { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; }
+};
+
+// ----------------------------------------------------------------------------
+
+/** A helper structure to store all data related to title objects. Needed for
+ the conversion of manual title positions that needs the old Chart1 API.
+ */
+struct TitleLayoutInfo
+{
+ typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTitle >
+ mxTitle; /// The API title object.
+ ModelRef< LayoutModel > mxLayout; /// The layout model, if existing.
+ GetShapeFunc mpGetShape; /// Helper function to receive the title shape.
+
+ inline explicit TitleLayoutInfo() : mpGetShape( 0 ) {}
+
+ void convertTitlePos(
+ ConverterRoot& rRoot,
+ const Reference< cssc::XChartDocument >& rxChart1Doc );
+};
+
+void TitleLayoutInfo::convertTitlePos( ConverterRoot& rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc )
+{
+ if( mxTitle.is() && mpGetShape ) try
+ {
+ // try to get the title shape
+ Reference< XShape > xTitleShape( mpGetShape( rxChart1Doc ), UNO_SET_THROW );
+ // get title rotation angle, needed for correction of position of top-left edge
+ double fAngle = 0.0;
+ PropertySet aTitleProp( mxTitle );
+ aTitleProp.getProperty( fAngle, PROP_TextRotation );
+ // convert the position
+ LayoutModel& rLayout = mxLayout.getOrCreate();
+ LayoutConverter aLayoutConv( rRoot, rLayout );
+ aLayoutConv.convertFromModel( xTitleShape, fAngle );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+/* The following local functions implement getting the XShape interface of all
+ supported title objects (chart and axes). This needs some effort due to the
+ design of the old Chart1 API used to access these objects. */
+
+/** A code fragment that returns a shape object from the passed shape supplier
+ using the specified interface function. Checks a boolean property first. */
+#define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
+ PropertySet aPropSet( shape_supplier ); \
+ if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
+ return shape_supplier->supplier_func(); \
+ return Reference< XShape >(); \
+
+/** Implements a function returning the drawing shape of an axis title, if
+ existing, using the specified API interface and its function. */
+#define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
+Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
+{ \
+ Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
+ OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
+}
+
+/** Returns the drawing shape of the main title, if existing. */
+Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
+{
+ OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
+}
+
+OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
+OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
+OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
+OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
+OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
+
+#undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
+#undef OOX_IMPLEMENT_GETTITLESHAPE
+
+} // namespace
+
+// ============================================================================
+
struct ConverterData
{
+ typedef ::std::map< TitleKey, TitleLayoutInfo > TitleMap;
+
ObjectFormatter maFormatter;
+ TitleMap maTitles;
XmlFilterBase& mrFilter;
ChartConverter& mrConverter;
Reference< XChartDocument > mxDoc;
@@ -91,6 +203,14 @@ ConverterData::ConverterData(
catch( Exception& )
{
}
+
+ // prepare conversion of title positions
+ maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape;
+ maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape;
+ maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape;
+ maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape;
+ maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape;
+ maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape;
}
ConverterData::~ConverterData()
@@ -122,13 +242,12 @@ ConverterRoot::~ConverterRoot()
{
}
-Reference< XInterface > ConverterRoot::createInstance(
- const Reference< XMultiServiceFactory >& rxFactory, const OUString& rServiceName )
+Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
{
Reference< XInterface > xInt;
- if( rxFactory.is() ) try
+ try
{
- xInt = rxFactory->createInstance( rServiceName );
+ xInt = mxData->mrFilter.getGlobalFactory()->createInstance( rServiceName );
}
catch( Exception& )
{
@@ -137,11 +256,6 @@ Reference< XInterface > ConverterRoot::createInstance(
return xInt;
}
-Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
-{
- return createInstance( mxData->mrFilter.getGlobalFactory(), rServiceName );
-}
-
XmlFilterBase& ConverterRoot::getFilter() const
{
return mxData->mrFilter;
@@ -167,6 +281,139 @@ ObjectFormatter& ConverterRoot::getFormatter() const
return mxData->maFormatter;
}
+void ConverterRoot::registerTitleLayout( const Reference< XTitle >& rxTitle,
+ const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx )
+{
+ OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" );
+ TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ];
+ OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" );
+ rTitleInfo.mxTitle = rxTitle;
+ rTitleInfo.mxLayout = rxLayout;
+}
+
+void ConverterRoot::convertTitlePositions()
+{
+ try
+ {
+ Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW );
+ for( ConverterData::TitleMap::iterator aIt = mxData->maTitles.begin(), aEnd = mxData->maTitles.end(); aIt != aEnd; ++aIt )
+ aIt->second.convertTitlePos( *this, xChart1Doc );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// ============================================================================
+
+namespace {
+
+/** Returns a position value in the chart area in 1/100 mm. */
+sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode )
+{
+ switch( nPosMode )
+ {
+ case XML_edge: // absolute start position as factor of chart size
+ return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize );
+ case XML_factor: // position relative to object default position
+ OSL_ENSURE( false, "lclCalcPosition - relative positioning not supported" );
+ return -1;
+ };
+
+ OSL_ENSURE( false, "lclCalcPosition - unknown positioning mode" );
+ return -1;
+}
+
+/** Returns a size value in the chart area in 1/100 mm. */
+sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode )
+{
+ sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize );
+ switch( nSizeMode )
+ {
+ case XML_factor: // size as factor of chart size
+ return nValue;
+ case XML_edge: // absolute end position as factor of chart size
+ return nValue - nPos + 1;
+ };
+
+ OSL_ENSURE( false, "lclCalcSize - unknown size mode" );
+ return -1;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+LayoutConverter::LayoutConverter( const ConverterRoot& rParent, LayoutModel& rModel ) :
+ ConverterBase< LayoutModel >( rParent, rModel )
+{
+}
+
+LayoutConverter::~LayoutConverter()
+{
+}
+
+bool LayoutConverter::calcAbsRectangle( Rectangle& orRect ) const
+{
+ if( !mrModel.mbAutoLayout )
+ {
+ const Size& rChartSize = getChartSize();
+ orRect.X = lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode );
+ orRect.Y = lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode );
+ if( (orRect.X >= 0) && (orRect.Y >= 0) )
+ {
+ orRect.Width = lclCalcSize( orRect.X, rChartSize.Width, mrModel.mfW, mrModel.mnWMode );
+ orRect.Height = lclCalcSize( orRect.Y, rChartSize.Height, mrModel.mfH, mrModel.mnHMode );
+ return (orRect.Width > 0) && (orRect.Height > 0);
+ }
+ }
+ return false;
+}
+
+bool LayoutConverter::convertFromModel( PropertySet& rPropSet )
+{
+ if( !mrModel.mbAutoLayout &&
+ (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) &&
+ (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) )
+ {
+ RelativePosition aPos;
+ aPos.Primary = getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 );
+ aPos.Secondary = getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 );
+ aPos.Anchor = ::com::sun::star::drawing::Alignment_TOP_LEFT;
+ rPropSet.setProperty( PROP_RelativePosition, aPos );
+ return true;
+ }
+ return false;
+}
+
+bool LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle )
+{
+ if( !mrModel.mbAutoLayout )
+ {
+ const Size& rChartSize = getChartSize();
+ Point aShapePos(
+ lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode ),
+ lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode ) );
+ if( (aShapePos.X >= 0) && (aShapePos.Y >= 0) )
+ {
+ // the call to XShape.getSize() may recalc the chart view
+ Size aShapeSize = rxShape->getSize();
+ // rotated shapes need special handling...
+ double fSin = fabs( sin( fRotationAngle * F_PI180 ) );
+ // add part of height to X direction, if title is rotated down
+ if( fRotationAngle > 180.0 )
+ aShapePos.X += static_cast< sal_Int32 >( fSin * aShapeSize.Height + 0.5 );
+ // add part of width to Y direction, if title is rotated up
+ else if( fRotationAngle > 0.0 )
+ aShapePos.Y += static_cast< sal_Int32 >( fSin * aShapeSize.Width + 0.5 );
+ // set the resulting position at the shape
+ rxShape->setPosition( aShapePos );
+ return true;
+ }
+ }
+ return false;
+}
+
// ============================================================================
} // namespace chart