1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: vmlshape.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/vml/vmlshape.hxx"
32 #include <rtl/math.hxx>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/beans/PropertyValues.hpp>
35 #include <com/sun/star/awt/XControlModel.hpp>
36 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
37 #include <com/sun/star/drawing/XControlShape.hpp>
38 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
39 #include <com/sun/star/drawing/XShapes.hpp>
40 #include <com/sun/star/graphic/XGraphic.hpp>
41 #include "properties.hxx"
42 #include "oox/helper/propertymap.hxx"
43 #include "oox/helper/propertyset.hxx"
44 #include "oox/core/xmlfilterbase.hxx"
45 #include "oox/ole/axcontrol.hxx"
46 #include "oox/ole/axcontrolfragment.hxx"
47 #include "oox/ole/oleobjecthelper.hxx"
48 #include "oox/vml/vmldrawing.hxx"
49 #include "oox/vml/vmlshapecontainer.hxx"
51 using ::rtl::OUString
;
52 using ::com::sun::star::uno::Exception
;
53 using ::com::sun::star::uno::Reference
;
54 using ::com::sun::star::uno::UNO_QUERY
;
55 using ::com::sun::star::uno::UNO_QUERY_THROW
;
56 using ::com::sun::star::uno::UNO_SET_THROW
;
57 using ::com::sun::star::lang::XMultiServiceFactory
;
58 using ::com::sun::star::awt::Point
;
59 using ::com::sun::star::awt::Rectangle
;
60 using ::com::sun::star::awt::Size
;
61 using ::com::sun::star::awt::XControlModel
;
62 using ::com::sun::star::graphic::XGraphic
;
63 using ::com::sun::star::drawing::PointSequenceSequence
;
64 using ::com::sun::star::drawing::XControlShape
;
65 using ::com::sun::star::drawing::XEnhancedCustomShapeDefaulter
;
66 using ::com::sun::star::drawing::XShape
;
67 using ::com::sun::star::drawing::XShapes
;
68 using ::oox::core::XmlFilterBase
;
73 // ============================================================================
77 Point
lclGetAbsPoint( const Point
& rRelPoint
, const Rectangle
& rShapeRect
, const Rectangle
& rCoordSys
)
79 double fWidthRatio
= static_cast< double >( rShapeRect
.Width
) / rCoordSys
.Width
;
80 double fHeightRatio
= static_cast< double >( rShapeRect
.Height
) / rCoordSys
.Height
;
82 aAbsPoint
.X
= static_cast< sal_Int32
>( rShapeRect
.X
+ fWidthRatio
* (rRelPoint
.X
- rCoordSys
.X
) + 0.5 );
83 aAbsPoint
.Y
= static_cast< sal_Int32
>( rShapeRect
.Y
+ fHeightRatio
* (rRelPoint
.Y
- rCoordSys
.Y
) + 0.5 );
87 Rectangle
lclGetAbsRect( const Rectangle
& rRelRect
, const Rectangle
& rShapeRect
, const Rectangle
& rCoordSys
)
89 double fWidthRatio
= static_cast< double >( rShapeRect
.Width
) / rCoordSys
.Width
;
90 double fHeightRatio
= static_cast< double >( rShapeRect
.Height
) / rCoordSys
.Height
;
92 aAbsRect
.X
= static_cast< sal_Int32
>( rShapeRect
.X
+ fWidthRatio
* (rRelRect
.X
- rCoordSys
.X
) + 0.5 );
93 aAbsRect
.Y
= static_cast< sal_Int32
>( rShapeRect
.Y
+ fHeightRatio
* (rRelRect
.Y
- rCoordSys
.Y
) + 0.5 );
94 aAbsRect
.Width
= static_cast< sal_Int32
>( fWidthRatio
* rRelRect
.Width
+ 0.5 );
95 aAbsRect
.Height
= static_cast< sal_Int32
>( fHeightRatio
* rRelRect
.Height
+ 0.5 );
99 Reference
< XShape
> lclCreateXShape( const XmlFilterBase
& rFilter
, const OUString
& rService
)
101 OSL_ENSURE( rService
.getLength() > 0, "lclCreateXShape - missing UNO shape service name" );
102 Reference
< XShape
> xShape
;
105 Reference
< XMultiServiceFactory
> xFactory( rFilter
.getModel(), UNO_QUERY_THROW
);
106 xShape
.set( xFactory
->createInstance( rService
), UNO_QUERY_THROW
);
111 OSL_ENSURE( xShape
.is(), "lclCreateXShape - cannot instanciate shape object" );
115 void lclInsertXShape( const Reference
< XShapes
>& rxShapes
, const Reference
< XShape
>& rxShape
)
117 OSL_ENSURE( rxShapes
.is(), "lclInsertXShape - missing XShapes container" );
118 OSL_ENSURE( rxShape
.is(), "lclInsertXShape - missing XShape" );
119 if( rxShapes
.is() && rxShape
.is() ) try
121 // insert shape into passed shape collection (maybe drawpage or group shape)
122 rxShapes
->add( rxShape
);
129 void lclSetXShapeRect( const Reference
< XShape
>& rxShape
, const Rectangle
& rShapeRect
)
131 OSL_ENSURE( rxShape
.is(), "lclSetXShapeRect - missing XShape" );
134 rxShape
->setPosition( Point( rShapeRect
.X
, rShapeRect
.Y
) );
135 rxShape
->setSize( Size( rShapeRect
.Width
, rShapeRect
.Height
) );
139 Reference
< XShape
> lclCreateAndInsertXShape( const XmlFilterBase
& rFilter
,
140 const Reference
< XShapes
>& rxShapes
, const OUString
& rService
, const Rectangle
& rShapeRect
)
142 Reference
< XShape
> xShape
= lclCreateXShape( rFilter
, rService
);
143 lclInsertXShape( rxShapes
, xShape
);
144 lclSetXShapeRect( xShape
, rShapeRect
);
150 // ============================================================================
152 ShapeTypeModel::ShapeTypeModel()
156 void ShapeTypeModel::assignUsed( const ShapeTypeModel
& rSource
)
158 moShapeType
.assignIfUsed( rSource
.moShapeType
);
159 moCoordPos
.assignIfUsed( rSource
.moCoordPos
);
160 moCoordSize
.assignIfUsed( rSource
.moCoordSize
);
161 /* The style properties position, left, top, width, height, margin-left,
162 margin-top are not derived from shape template to shape. */
163 maStrokeModel
.assignUsed( rSource
.maStrokeModel
);
164 maFillModel
.assignUsed( rSource
.maFillModel
);
165 moGraphicPath
.assignIfUsed( rSource
.moGraphicPath
);
166 moGraphicTitle
.assignIfUsed( rSource
.moGraphicTitle
);
169 // ----------------------------------------------------------------------------
171 ShapeType::ShapeType( const Drawing
& rDrawing
) :
172 mrDrawing( rDrawing
)
176 ShapeType::~ShapeType()
180 OUString
ShapeType::getGraphicPath() const
182 return maTypeModel
.moGraphicPath
.get( OUString() );
185 Rectangle
ShapeType::getCoordSystem() const
187 Int32Pair aCoordPos
= maTypeModel
.moCoordPos
.get( Int32Pair( 0, 0 ) );
188 Int32Pair aCoordSize
= maTypeModel
.moCoordSize
.get( Int32Pair( 1000, 1000 ) );
189 return Rectangle( aCoordPos
.first
, aCoordPos
.second
, aCoordSize
.first
, aCoordSize
.second
);
192 Rectangle
ShapeType::getRectangle( const ShapeParentAnchor
* pParentAnchor
) const
194 return pParentAnchor
?
195 lclGetAbsRect( getRelRectangle(), pParentAnchor
->maShapeRect
, pParentAnchor
->maCoordSys
) :
199 Rectangle
ShapeType::getAbsRectangle() const
201 const XmlFilterBase
& rFilter
= mrDrawing
.getFilter();
203 ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maLeft
, 0, true, true ) + ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maMarginLeft
, 0, true, true ),
204 ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maTop
, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maMarginTop
, 0, false, true ),
205 ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maWidth
, 0, true, true ),
206 ConversionHelper::decodeMeasureToHmm( rFilter
, maTypeModel
.maHeight
, 0, false, true ) );
209 Rectangle
ShapeType::getRelRectangle() const
212 maTypeModel
.maLeft
.toInt32(),
213 maTypeModel
.maTop
.toInt32(),
214 maTypeModel
.maWidth
.toInt32(),
215 maTypeModel
.maHeight
.toInt32() );
218 // ============================================================================
220 ShapeClientData::ShapeClientData() :
221 mnObjType( XML_TOKEN_INVALID
),
224 mbPrintObject( true ),
229 // ----------------------------------------------------------------------------
231 ShapeModel::ShapeModel()
235 ShapeClientData
& ShapeModel::createClientData()
237 mxClientData
.reset( new ShapeClientData
);
238 return *mxClientData
;
241 // ----------------------------------------------------------------------------
243 ShapeBase::ShapeBase( const Drawing
& rDrawing
) :
244 ShapeType( rDrawing
)
248 void ShapeBase::finalizeFragmentImport()
250 // resolve shape template reference
251 if( (maShapeModel
.maType
.getLength() > 1) && (maShapeModel
.maType
[ 0 ] == '#') )
252 if( const ShapeType
* pShapeType
= mrDrawing
.getShapes().getShapeTypeById( maShapeModel
.maType
.copy( 1 ), true ) )
253 maTypeModel
.assignUsed( pShapeType
->getTypeModel() );
256 const ShapeType
* ShapeBase::getChildTypeById( const OUString
& ) const
261 const ShapeBase
* ShapeBase::getChildById( const OUString
& ) const
266 Reference
< XShape
> ShapeBase::convertAndInsert( const Reference
< XShapes
>& rxShapes
, const ShapeParentAnchor
* pParentAnchor
) const
268 Reference
< XShape
> xShape
;
269 if( mrDrawing
.isShapeSupported( *this ) )
271 /* Calculate shape rectangle. Applications may do something special
272 according to some imported shape client data (e.g. Excel cell anchor). */
273 Rectangle aShapeRect
= calcShapeRectangle( pParentAnchor
);
274 // convert the shape, if the calculated rectangle is not empty
275 if( ((aShapeRect
.Width
> 0) || (aShapeRect
.Height
> 0)) && rxShapes
.is() )
276 xShape
= implConvertAndInsert( rxShapes
, aShapeRect
);
281 void ShapeBase::convertFormatting( const Reference
< XShape
>& rxShape
, const ShapeParentAnchor
* pParentAnchor
) const
285 /* Calculate shape rectangle. Applications may do something special
286 according to some imported shape client data (e.g. Excel cell anchor). */
287 Rectangle aShapeRect
= calcShapeRectangle( pParentAnchor
);
288 // convert the shape, if the calculated rectangle is not empty
289 if( (aShapeRect
.Width
> 0) || (aShapeRect
.Height
> 0) )
291 lclSetXShapeRect( rxShape
, aShapeRect
);
292 convertShapeProperties( rxShape
);
297 // protected ------------------------------------------------------------------
299 Rectangle
ShapeBase::calcShapeRectangle( const ShapeParentAnchor
* pParentAnchor
) const
301 /* Calculate shape rectangle. Applications may do something special
302 according to some imported shape client data (e.g. Excel cell anchor). */
303 Rectangle aShapeRect
;
304 if( !maShapeModel
.mxClientData
.get() || !mrDrawing
.convertShapeClientAnchor( aShapeRect
, maShapeModel
.mxClientData
->maAnchor
) )
305 aShapeRect
= getRectangle( pParentAnchor
);
309 void ShapeBase::convertShapeProperties( const Reference
< XShape
>& rxShape
) const
311 PropertyMap aPropMap
;
313 maTypeModel
.maStrokeModel
.pushToPropMap( aPropMap
, mrDrawing
.getFilter() );
314 maTypeModel
.maFillModel
.pushToPropMap( aPropMap
, mrDrawing
.getFilter() );
316 PropertySet
aPropSet( rxShape
);
317 aPropSet
.setProperties( aPropMap
);
320 // ============================================================================
322 SimpleShape::SimpleShape( const Drawing
& rDrawing
, const OUString
& rService
) :
323 ShapeBase( rDrawing
),
324 maService( rService
)
328 Reference
< XShape
> SimpleShape::implConvertAndInsert( const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
330 Reference
< XShape
> xShape
= lclCreateAndInsertXShape( mrDrawing
.getFilter(), rxShapes
, maService
, rShapeRect
);
331 convertShapeProperties( xShape
);
335 // ============================================================================
337 RectangleShape::RectangleShape( const Drawing
& rDrawing
) :
338 SimpleShape( rDrawing
, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) )
342 // ============================================================================
344 EllipseShape::EllipseShape( const Drawing
& rDrawing
) :
345 SimpleShape( rDrawing
, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) )
349 // ============================================================================
351 PolyLineShape::PolyLineShape( const Drawing
& rDrawing
) :
352 SimpleShape( rDrawing
, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) )
356 Reference
< XShape
> PolyLineShape::implConvertAndInsert( const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
358 Reference
< XShape
> xShape
= SimpleShape::implConvertAndInsert( rxShapes
, rShapeRect
);
360 Rectangle aCoordSys
= getCoordSystem();
361 if( !maShapeModel
.maPoints
.empty() && (aCoordSys
.Width
> 0) && (aCoordSys
.Height
> 0) )
363 ::std::vector
< Point
> aAbsPoints
;
364 for( ShapeModel::PointVector::const_iterator aIt
= maShapeModel
.maPoints
.begin(), aEnd
= maShapeModel
.maPoints
.end(); aIt
!= aEnd
; ++aIt
)
365 aAbsPoints
.push_back( lclGetAbsPoint( *aIt
, rShapeRect
, aCoordSys
) );
366 PointSequenceSequence
aPointSeq( 1 );
367 aPointSeq
[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints
);
368 PropertySet
aPropSet( xShape
);
369 aPropSet
.setProperty( PROP_PolyPolygon
, aPointSeq
);
374 // ============================================================================
376 CustomShape::CustomShape( const Drawing
& rDrawing
) :
377 SimpleShape( rDrawing
, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) )
381 Reference
< XShape
> CustomShape::implConvertAndInsert( const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
383 // try to create a custom shape
384 Reference
< XShape
> xShape
= SimpleShape::implConvertAndInsert( rxShapes
, rShapeRect
);
385 if( xShape
.is() ) try
387 // create the custom shape geometry
388 Reference
< XEnhancedCustomShapeDefaulter
> xDefaulter( xShape
, UNO_QUERY_THROW
);
389 xDefaulter
->createCustomShapeDefaults( OUString::valueOf( maTypeModel
.moShapeType
.get( 0 ) ) );
390 // convert common properties
391 convertShapeProperties( xShape
);
399 // ============================================================================
401 ComplexShape::ComplexShape( const Drawing
& rDrawing
) :
402 CustomShape( rDrawing
)
406 Reference
< XShape
> ComplexShape::implConvertAndInsert( const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
408 XmlFilterBase
& rFilter
= mrDrawing
.getFilter();
409 OUString aGraphicPath
= getGraphicPath();
411 // try to find registered OLE object info
412 if( const OleObjectInfo
* pOleObjectInfo
= mrDrawing
.getOleObjectInfo( maTypeModel
.maShapeId
) )
414 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
415 if( pOleObjectInfo
->mbDmlShape
)
416 return Reference
< XShape
>();
418 PropertyMap aOleProps
;
419 Size
aOleSize( rShapeRect
.Width
, rShapeRect
.Height
);
420 if( rFilter
.getOleObjectHelper().importOleObject( aOleProps
, *pOleObjectInfo
, aOleSize
) )
422 Reference
< XShape
> xShape
= lclCreateAndInsertXShape( rFilter
, rxShapes
, CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rShapeRect
);
425 // set the replacement graphic
426 if( aGraphicPath
.getLength() > 0 )
428 Reference
< XGraphic
> xGraphic
= rFilter
.importEmbeddedGraphic( aGraphicPath
);
430 aOleProps
[ PROP_Graphic
] <<= xGraphic
;
433 PropertySet
aPropSet( xShape
);
434 aPropSet
.setProperties( aOleProps
);
441 // try to find registered form control info
442 const ControlInfo
* pControlInfo
= mrDrawing
.getControlInfo( maTypeModel
.maShapeId
);
443 if( pControlInfo
&& (pControlInfo
->maFragmentPath
.getLength() > 0) && (maTypeModel
.maName
.getLength() > 0) )
445 OSL_ENSURE( maTypeModel
.maName
== pControlInfo
->maName
, "ComplexShape::implConvertAndInsert - control name mismatch" );
446 ::oox::ole::AxControl
aControl( maTypeModel
.maName
);
447 // load the control properties from fragment
448 if( rFilter
.importFragment( new ::oox::ole::AxControlFragment( rFilter
, pControlInfo
->maFragmentPath
, aControl
) ) ) try
450 // create control model and insert it into the form of the draw page
451 Reference
< XControlModel
> xCtrlModel( aControl
.convertAndInsert( mrDrawing
.getControlHelper() ), UNO_SET_THROW
);
452 if( maShapeModel
.mxClientData
.get() )
453 mrDrawing
.convertControlClientData( xCtrlModel
, *maShapeModel
.mxClientData
);
455 // create the control shape, set control model at the shape
456 Reference
< XShape
> xShape
= lclCreateAndInsertXShape(
457 rFilter
, rxShapes
, CREATE_OUSTRING( "com.sun.star.drawing.ControlShape" ), rShapeRect
);
458 Reference
< XControlShape
> xCtrlShape( xShape
, UNO_QUERY
); // do not throw, but always return the shape
459 if( xCtrlShape
.is() )
460 xCtrlShape
->setControl( xCtrlModel
);
466 // on error, proceed and try to create picture from replacement image
469 // try to create a picture object
470 if( aGraphicPath
.getLength() > 0 )
472 Reference
< XShape
> xShape
= lclCreateAndInsertXShape( rFilter
, rxShapes
, CREATE_OUSTRING( "com.sun.star.drawing.GraphicObjectShape" ), rShapeRect
);
475 OUString aGraphicUrl
= rFilter
.importEmbeddedGraphicObject( aGraphicPath
);
476 if( aGraphicUrl
.getLength() > 0 )
478 PropertySet
aPropSet( xShape
);
479 aPropSet
.setProperty( PROP_GraphicURL
, aGraphicUrl
);
485 // default: try to create a custom shape
486 return CustomShape::implConvertAndInsert( rxShapes
, rShapeRect
);
489 // ============================================================================
491 GroupShape::GroupShape( const Drawing
& rDrawing
) :
492 ShapeBase( rDrawing
),
493 mxChildren( new ShapeContainer( rDrawing
) )
497 GroupShape::~GroupShape()
501 void GroupShape::finalizeFragmentImport()
503 // basic shape processing
504 ShapeBase::finalizeFragmentImport();
505 // finalize all child shapes
506 mxChildren
->finalizeFragmentImport();
509 const ShapeType
* GroupShape::getChildTypeById( const OUString
& rShapeId
) const
511 return mxChildren
->getShapeTypeById( rShapeId
, true );
514 const ShapeBase
* GroupShape::getChildById( const OUString
& rShapeId
) const
516 return mxChildren
->getShapeById( rShapeId
, true );
519 Reference
< XShape
> GroupShape::implConvertAndInsert( const Reference
< XShapes
>& rxShapes
, const Rectangle
& rShapeRect
) const
521 Reference
< XShape
> xGroupShape
;
522 // check that this shape contains children and a valid coordinate system
523 ShapeParentAnchor aParentAnchor
;
524 aParentAnchor
.maShapeRect
= rShapeRect
;
525 aParentAnchor
.maCoordSys
= getCoordSystem();
526 if( !mxChildren
->empty() && (aParentAnchor
.maCoordSys
.Width
> 0) && (aParentAnchor
.maCoordSys
.Height
> 0) ) try
528 xGroupShape
= lclCreateAndInsertXShape( mrDrawing
.getFilter(), rxShapes
, CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rShapeRect
);
529 Reference
< XShapes
> xChildShapes( xGroupShape
, UNO_QUERY_THROW
);
530 mxChildren
->convertAndInsert( xChildShapes
, &aParentAnchor
);
531 // no child shape has been created - delete the group shape
532 if( !xChildShapes
->hasElements() )
534 rxShapes
->remove( xGroupShape
);
544 // ============================================================================