diff options
Diffstat (limited to 'oox/source/vml/vmlshape.cxx')
-rw-r--r-- | oox/source/vml/vmlshape.cxx | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx new file mode 100644 index 000000000000..d557a7f50354 --- /dev/null +++ b/oox/source/vml/vmlshape.cxx @@ -0,0 +1,555 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/vml/vmlshape.hxx" +#include <rtl/math.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include "properties.hxx" +#include "oox/helper/graphichelper.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/helper/propertyset.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/ole/axcontrol.hxx" +#include "oox/ole/axcontrolfragment.hxx" +#include "oox/ole/oleobjecthelper.hxx" +#include "oox/vml/vmldrawing.hxx" +#include "oox/vml/vmlshapecontainer.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +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::awt::Point; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::awt::Size; +using ::com::sun::star::awt::XControlModel; +using ::com::sun::star::graphic::XGraphic; +using ::com::sun::star::drawing::PointSequenceSequence; +using ::com::sun::star::drawing::XControlShape; +using ::com::sun::star::drawing::XEnhancedCustomShapeDefaulter; +using ::com::sun::star::drawing::XShape; +using ::com::sun::star::drawing::XShapes; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace vml { + +// ============================================================================ + +namespace { + +Point lclGetAbsPoint( const Point& rRelPoint, const Rectangle& rShapeRect, const Rectangle& rCoordSys ) +{ + double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width; + double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height; + Point aAbsPoint; + aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 ); + aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 ); + return aAbsPoint; +} + +Rectangle lclGetAbsRect( const Rectangle& rRelRect, const Rectangle& rShapeRect, const Rectangle& rCoordSys ) +{ + double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width; + double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height; + Rectangle aAbsRect; + aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 ); + aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 ); + aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 ); + aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 ); + return aAbsRect; +} + +Reference< XShape > lclCreateXShape( const XmlFilterBase& rFilter, const OUString& rService ) +{ + OSL_ENSURE( rService.getLength() > 0, "lclCreateXShape - missing UNO shape service name" ); + Reference< XShape > xShape; + try + { + Reference< XMultiServiceFactory > xFactory( rFilter.getModelFactory(), UNO_SET_THROW ); + xShape.set( xFactory->createInstance( rService ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + } + OSL_ENSURE( xShape.is(), "lclCreateXShape - cannot instanciate shape object" ); + return xShape; +} + +void lclInsertXShape( const Reference< XShapes >& rxShapes, const Reference< XShape >& rxShape ) +{ + OSL_ENSURE( rxShapes.is(), "lclInsertXShape - missing XShapes container" ); + OSL_ENSURE( rxShape.is(), "lclInsertXShape - missing XShape" ); + if( rxShapes.is() && rxShape.is() ) try + { + // insert shape into passed shape collection (maybe drawpage or group shape) + rxShapes->add( rxShape ); + } + catch( Exception& ) + { + } +} + +void lclSetXShapeRect( const Reference< XShape >& rxShape, const Rectangle& rShapeRect ) +{ + OSL_ENSURE( rxShape.is(), "lclSetXShapeRect - missing XShape" ); + if( rxShape.is() ) + { + rxShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) ); + rxShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) ); + } +} + +Reference< XShape > lclCreateAndInsertXShape( const XmlFilterBase& rFilter, + const Reference< XShapes >& rxShapes, const OUString& rService, const Rectangle& rShapeRect ) +{ + Reference< XShape > xShape = lclCreateXShape( rFilter, rService ); + lclInsertXShape( rxShapes, xShape ); + lclSetXShapeRect( xShape, rShapeRect ); + return xShape; +} + +} // namespace + +// ============================================================================ + +ShapeTypeModel::ShapeTypeModel() +{ +} + +void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource ) +{ + moShapeType.assignIfUsed( rSource.moShapeType ); + moCoordPos.assignIfUsed( rSource.moCoordPos ); + moCoordSize.assignIfUsed( rSource.moCoordSize ); + /* The style properties position, left, top, width, height, margin-left, + margin-top are not derived from shape template to shape. */ + maStrokeModel.assignUsed( rSource.maStrokeModel ); + maFillModel.assignUsed( rSource.maFillModel ); + moGraphicPath.assignIfUsed( rSource.moGraphicPath ); + moGraphicTitle.assignIfUsed( rSource.moGraphicTitle ); +} + +// ---------------------------------------------------------------------------- + +ShapeType::ShapeType( Drawing& rDrawing ) : + mrDrawing( rDrawing ) +{ +} + +ShapeType::~ShapeType() +{ +} + +OUString ShapeType::getGraphicPath() const +{ + return maTypeModel.moGraphicPath.get( OUString() ); +} + +Rectangle ShapeType::getCoordSystem() const +{ + Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) ); + Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) ); + return Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second ); +} + +Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const +{ + return pParentAnchor ? + lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) : + getAbsRectangle(); +} + +Rectangle ShapeType::getAbsRectangle() const +{ + const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); + return Rectangle( + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true ) ); +} + +Rectangle ShapeType::getRelRectangle() const +{ + return Rectangle( + maTypeModel.maLeft.toInt32(), + maTypeModel.maTop.toInt32(), + maTypeModel.maWidth.toInt32(), + maTypeModel.maHeight.toInt32() ); +} + +// ============================================================================ + +ShapeClientData::ShapeClientData() : + mnObjType( XML_TOKEN_INVALID ), + mnCol( -1 ), + mnRow( -1 ), + mbPrintObject( true ), + mbVisible( false ) +{ +} + +// ---------------------------------------------------------------------------- + +ShapeModel::ShapeModel() +{ +} + +ShapeClientData& ShapeModel::createClientData() +{ + mxClientData.reset( new ShapeClientData ); + return *mxClientData; +} + +// ---------------------------------------------------------------------------- + +ShapeBase::ShapeBase( Drawing& rDrawing ) : + ShapeType( rDrawing ) +{ +} + +void ShapeBase::finalizeFragmentImport() +{ + // resolve shape template reference + if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') ) + if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) ) + maTypeModel.assignUsed( pShapeType->getTypeModel() ); +} + +const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const +{ + return 0; +} + +const ShapeBase* ShapeBase::getChildById( const OUString& ) const +{ + return 0; +} + +Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const +{ + Reference< XShape > xShape; + if( mrDrawing.isShapeSupported( *this ) ) + { + /* Calculate shape rectangle. Applications may do something special + according to some imported shape client data (e.g. Excel cell anchor). */ + Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); + // convert the shape, if the calculated rectangle is not empty + if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() ) + { + xShape = implConvertAndInsert( rxShapes, aShapeRect ); + /* Notify the drawing that a new shape has been inserted (but not + for children of group shapes). For convenience, pass the + rectangle that contains position and size of the shape. */ + if( !pParentAnchor && xShape.is() ) + mrDrawing.notifyShapeInserted( xShape, aShapeRect ); + } + } + return xShape; +} + +void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const +{ + if( rxShape.is() ) + { + /* Calculate shape rectangle. Applications may do something special + according to some imported shape client data (e.g. Excel cell anchor). */ + Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); + // convert the shape, if the calculated rectangle is not empty + if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) ) + { + lclSetXShapeRect( rxShape, aShapeRect ); + convertShapeProperties( rxShape ); + } + } +} + +// protected ------------------------------------------------------------------ + +Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const +{ + /* Calculate shape rectangle. Applications may do something special + according to some imported shape client data (e.g. Excel cell anchor). */ + Rectangle aShapeRect; + if( !maShapeModel.mxClientData.get() || !mrDrawing.convertShapeClientAnchor( aShapeRect, maShapeModel.mxClientData->maAnchor ) ) + aShapeRect = getRectangle( pParentAnchor ); + return aShapeRect; +} + +void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const +{ + ModelObjectHelper& rModelObjectHelper = mrDrawing.getFilter().getModelObjectHelper(); + const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); + + PropertyMap aPropMap; + maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rModelObjectHelper, rGraphicHelper ); + maTypeModel.maFillModel.pushToPropMap( aPropMap, rModelObjectHelper, rGraphicHelper ); + + PropertySet aPropSet( rxShape ); + aPropSet.setProperties( aPropMap ); +} + +// ============================================================================ + +SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) : + ShapeBase( rDrawing ), + maService( rService ) +{ +} + +Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + Reference< XShape > xShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, maService, rShapeRect ); + convertShapeProperties( xShape ); + return xShape; +} + +// ============================================================================ + +RectangleShape::RectangleShape( Drawing& rDrawing ) : + SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) ) +{ +} + +// ============================================================================ + +EllipseShape::EllipseShape( Drawing& rDrawing ) : + SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) ) +{ +} + +// ============================================================================ + +PolyLineShape::PolyLineShape( Drawing& rDrawing ) : + SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) ) +{ +} + +Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect ); + // polygon path + Rectangle aCoordSys = getCoordSystem(); + if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) ) + { + ::std::vector< Point > aAbsPoints; + for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt ) + aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) ); + PointSequenceSequence aPointSeq( 1 ); + aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints ); + PropertySet aPropSet( xShape ); + aPropSet.setProperty( PROP_PolyPolygon, aPointSeq ); + } + return xShape; +} + +// ============================================================================ + +CustomShape::CustomShape( Drawing& rDrawing ) : + SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) ) +{ +} + +Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + // try to create a custom shape + Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect ); + if( xShape.is() ) try + { + // create the custom shape geometry + Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW ); + xDefaulter->createCustomShapeDefaults( OUString::valueOf( maTypeModel.moShapeType.get( 0 ) ) ); + // convert common properties + convertShapeProperties( xShape ); + } + catch( Exception& ) + { + } + return xShape; +} + +// ============================================================================ + +ComplexShape::ComplexShape( Drawing& rDrawing ) : + CustomShape( rDrawing ) +{ +} + +Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + XmlFilterBase& rFilter = mrDrawing.getFilter(); + OUString aGraphicPath = getGraphicPath(); + + // try to find registered OLE object info + if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) ) + { + // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here + if( pOleObjectInfo->mbDmlShape ) + return Reference< XShape >(); + + PropertyMap aOleProps; + Size aOleSize( rShapeRect.Width, rShapeRect.Height ); + if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) ) + { + Reference< XShape > xShape = lclCreateAndInsertXShape( rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rShapeRect ); + if( xShape.is() ) + { + // set the replacement graphic + if( aGraphicPath.getLength() > 0 ) + { + Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath ); + if( xGraphic.is() ) + aOleProps[ PROP_Graphic ] <<= xGraphic; + } + + PropertySet aPropSet( xShape ); + aPropSet.setProperties( aOleProps ); + + return xShape; + } + } + } + + // try to find registered form control info + const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId ); + if( pControlInfo && (pControlInfo->maFragmentPath.getLength() > 0) && (maTypeModel.maName.getLength() > 0) ) + { + OSL_ENSURE( maTypeModel.maName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" ); + ::oox::ole::EmbeddedControl aControl( maTypeModel.maName ); + // load the control properties from fragment + if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) ) try + { + // create control model and insert it into the form of the draw page + Reference< XControlModel > xCtrlModel( mrDrawing.getControlForm().convertAndInsert( aControl ), UNO_SET_THROW ); + if( maShapeModel.mxClientData.get() ) + mrDrawing.convertControlClientData( xCtrlModel, *maShapeModel.mxClientData ); + + // create the control shape, set control model at the shape + Reference< XShape > xShape = lclCreateAndInsertXShape( + rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.ControlShape" ), rShapeRect ); + Reference< XControlShape > xCtrlShape( xShape, UNO_QUERY ); // do not throw, but always return the shape + if( xCtrlShape.is() ) + xCtrlShape->setControl( xCtrlModel ); + return xShape; + } + catch( Exception& ) + { + } + // on error, proceed and try to create picture from replacement image + } + + // try to create a picture object + if( aGraphicPath.getLength() > 0 ) + { + Reference< XShape > xShape = lclCreateAndInsertXShape( rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GraphicObjectShape" ), rShapeRect ); + if( xShape.is() ) + { + OUString aGraphicUrl = rFilter.getGraphicHelper().importEmbeddedGraphicObject( aGraphicPath ); + if( aGraphicUrl.getLength() > 0 ) + { + PropertySet aPropSet( xShape ); + aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl ); + } + } + return xShape; + } + + // default: try to create a custom shape + return CustomShape::implConvertAndInsert( rxShapes, rShapeRect ); +} + +// ============================================================================ + +GroupShape::GroupShape( Drawing& rDrawing ) : + ShapeBase( rDrawing ), + mxChildren( new ShapeContainer( rDrawing ) ) +{ +} + +GroupShape::~GroupShape() +{ +} + +void GroupShape::finalizeFragmentImport() +{ + // basic shape processing + ShapeBase::finalizeFragmentImport(); + // finalize all child shapes + mxChildren->finalizeFragmentImport(); +} + +const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const +{ + return mxChildren->getShapeTypeById( rShapeId, true ); +} + +const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const +{ + return mxChildren->getShapeById( rShapeId, true ); +} + +Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + Reference< XShape > xGroupShape; + // check that this shape contains children and a valid coordinate system + ShapeParentAnchor aParentAnchor; + aParentAnchor.maShapeRect = rShapeRect; + aParentAnchor.maCoordSys = getCoordSystem(); + if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try + { + xGroupShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rShapeRect ); + Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW ); + mxChildren->convertAndInsert( xChildShapes, &aParentAnchor ); + // no child shape has been created - delete the group shape + if( !xChildShapes->hasElements() ) + { + rxShapes->remove( xGroupShape ); + xGroupShape.clear(); + } + } + catch( Exception& ) + { + } + return xGroupShape; +} + +// ============================================================================ + +} // namespace vml +} // namespace oox + |