update dev300-m58
[ooovba.git] / oox / source / vml / vmlshape.cxx
blobd586196acee403879c8047a2c01a0f070893d201
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 $
10 * $Revision: 1.5 $
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/FillStyle.hpp>
37 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
38 #include <com/sun/star/drawing/XControlShape.hpp>
39 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
40 #include <com/sun/star/drawing/XShapes.hpp>
41 #include <com/sun/star/graphic/XGraphic.hpp>
42 #include "properties.hxx"
43 #include "oox/helper/propertymap.hxx"
44 #include "oox/helper/propertyset.hxx"
45 #include "oox/core/xmlfilterbase.hxx"
46 #include "oox/ole/axcontrol.hxx"
47 #include "oox/ole/axcontrolfragment.hxx"
48 #include "oox/ole/oleobjecthelper.hxx"
49 #include "oox/vml/vmldrawing.hxx"
50 #include "oox/vml/vmlshapecontainer.hxx"
52 using ::rtl::OUString;
53 using ::com::sun::star::uno::Exception;
54 using ::com::sun::star::uno::Reference;
55 using ::com::sun::star::uno::UNO_QUERY;
56 using ::com::sun::star::uno::UNO_QUERY_THROW;
57 using ::com::sun::star::uno::UNO_SET_THROW;
58 using ::com::sun::star::lang::XMultiServiceFactory;
59 using ::com::sun::star::awt::Point;
60 using ::com::sun::star::awt::Rectangle;
61 using ::com::sun::star::awt::Size;
62 using ::com::sun::star::awt::XControlModel;
63 using ::com::sun::star::graphic::XGraphic;
64 using ::com::sun::star::drawing::PointSequenceSequence;
65 using ::com::sun::star::drawing::XControlShape;
66 using ::com::sun::star::drawing::XEnhancedCustomShapeDefaulter;
67 using ::com::sun::star::drawing::XShape;
68 using ::com::sun::star::drawing::XShapes;
69 using ::oox::core::XmlFilterBase;
71 namespace oox {
72 namespace vml {
74 // ============================================================================
76 namespace {
78 sal_Int32 lclGetMeasure( const XmlFilterBase& /*rFilter*/, const OUString& rValue, sal_Int32 nRefValue )
80 // default for missing values is 0
81 if( rValue.getLength() == 0 )
82 return 0;
84 // TODO: according to spec, value may contain "auto"
85 if( rValue.equalsAscii( "auto" ) )
86 return nRefValue;
88 // extract the double value and find start position of unit characters
89 rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
90 sal_Int32 nEndPos = 0;
91 double fValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &nEndPos );
92 if( (eConvStatus != rtl_math_ConversionStatus_Ok) || (fValue == 0.0) )
93 return 0;
95 // process trailing unit, convert to 1/100 mm
96 static const OUString saPx = CREATE_OUSTRING( "px" );
97 OUString aUnit = ((0 < nEndPos) && (nEndPos < rValue.getLength())) ? rValue.copy( nEndPos ) : saPx;
98 if( aUnit.getLength() == 2 )
100 sal_Unicode cChar1 = aUnit[ 0 ];
101 sal_Unicode cChar2 = aUnit[ 1 ];
102 if( (cChar1 == 'i') && (cChar2 == 'n') ) // 1 inch = 2540 1/100mm
103 fValue *= 2540.0;
104 else if( (cChar1 == 'c') && (cChar2 == 'm') ) // 1 cm = 1000 1/100mm
105 fValue *= 1000.0;
106 else if( (cChar1 == 'm') && (cChar2 == 'm') ) // 1 mm = 100 1/100mm
107 fValue *= 100.0;
108 else if( (cChar1 == 'p') && (cChar2 == 't') ) // 1 point = 1/72 inch
109 fValue *= 2540.0 / 72.0;
110 else if( (cChar1 == 'p') && (cChar2 == 'c') ) // 1 pica = 1/6 inch
111 fValue *= 2540.0 / 6.0;
112 else if( (cChar1 == 'e') && (cChar2 == 'm') ) // relative to refvalue
113 fValue *= nRefValue;
114 else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device
115 fValue *= 1.0;
117 else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
119 fValue *= nRefValue / 100.0;
121 else
123 OSL_ENSURE( false, "lclGetMeasure - unknown measure unit" );
124 fValue = nRefValue;
126 return static_cast< sal_Int32 >( fValue + 0.5 );
129 Point lclGetAbsPoint( const Point& rRelPoint, const Rectangle& rShapeRect, const Rectangle& rCoordSys )
131 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
132 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
133 Point aAbsPoint;
134 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
135 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
136 return aAbsPoint;
139 Rectangle lclGetAbsRect( const Rectangle& rRelRect, const Rectangle& rShapeRect, const Rectangle& rCoordSys )
141 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
142 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
143 Rectangle aAbsRect;
144 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
145 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
146 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
147 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
148 return aAbsRect;
151 Reference< XShape > lclCreateXShape( const XmlFilterBase& rFilter, const OUString& rService )
153 OSL_ENSURE( rService.getLength() > 0, "lclCreateXShape - missing UNO shape service name" );
154 Reference< XShape > xShape;
157 Reference< XMultiServiceFactory > xFactory( rFilter.getModel(), UNO_QUERY_THROW );
158 xShape.set( xFactory->createInstance( rService ), UNO_QUERY_THROW );
160 catch( Exception& )
163 OSL_ENSURE( xShape.is(), "lclCreateXShape - cannot instanciate shape object" );
164 return xShape;
167 void lclInsertXShape( const Reference< XShapes >& rxShapes, const Reference< XShape >& rxShape, const Rectangle& rShapeRect )
169 OSL_ENSURE( rxShapes.is(), "lclInsertXShape - missing XShapes container" );
170 OSL_ENSURE( rxShape.is(), "lclInsertXShape - missing XShape" );
171 if( rxShapes.is() && rxShape.is() ) try
173 // insert shape into passed shape collection (maybe drawpage or group shape)
174 rxShapes->add( rxShape );
175 // set position/size
176 rxShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) );
177 rxShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) );
179 catch( Exception& )
184 Reference< XShape > lclCreateAndInsertXShape( const XmlFilterBase& rFilter,
185 const Reference< XShapes >& rxShapes, const OUString& rService, const Rectangle& rShapeRect )
187 Reference< XShape > xShape = lclCreateXShape( rFilter, rService );
188 lclInsertXShape( rxShapes, xShape, rShapeRect );
189 return xShape;
192 } // namespace
194 // ============================================================================
196 ShapeTypeModel::ShapeTypeModel()
200 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
202 monShapeType.assignIfUsed( rSource.monShapeType );
203 monCoordLeft.assignIfUsed( rSource.monCoordLeft );
204 monCoordTop.assignIfUsed( rSource.monCoordTop );
205 monCoordWidth.assignIfUsed( rSource.monCoordWidth );
206 monCoordHeight.assignIfUsed( rSource.monCoordHeight );
207 /* The style properties position, left, top, width, height, margin-left,
208 margin-top are not derived from shape template to shape. */
209 mobStroked.assignIfUsed( rSource.mobStroked );
210 moStrokeColor.assignIfUsed( rSource.moStrokeColor );
211 mobFilled.assignIfUsed( rSource.mobFilled );
212 moFillColor.assignIfUsed( rSource.moFillColor );
213 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
214 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
217 // ----------------------------------------------------------------------------
219 ShapeType::ShapeType( const Drawing& rDrawing ) :
220 mrDrawing( rDrawing )
224 ShapeType::~ShapeType()
228 OUString ShapeType::getGraphicPath() const
230 return maTypeModel.moGraphicPath.get( OUString() );
233 Rectangle ShapeType::getCoordSystem() const
235 return Rectangle(
236 maTypeModel.monCoordLeft.get( 0 ),
237 maTypeModel.monCoordTop.get( 0 ),
238 maTypeModel.monCoordWidth.get( 1000 ),
239 maTypeModel.monCoordHeight.get( 1000 ) );
242 Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
244 return pParentAnchor ?
245 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
246 getAbsRectangle();
249 Rectangle ShapeType::getAbsRectangle() const
251 const XmlFilterBase& rFilter = mrDrawing.getFilter();
252 return Rectangle(
253 lclGetMeasure( rFilter, maTypeModel.maLeft, 0 ) + lclGetMeasure( rFilter, maTypeModel.maMarginLeft, 0 ),
254 lclGetMeasure( rFilter, maTypeModel.maTop, 0 ) + lclGetMeasure( rFilter, maTypeModel.maMarginTop, 0 ),
255 lclGetMeasure( rFilter, maTypeModel.maWidth, 0 ),
256 lclGetMeasure( rFilter, maTypeModel.maHeight, 0 ) );
259 Rectangle ShapeType::getRelRectangle() const
261 return Rectangle(
262 maTypeModel.maLeft.toInt32(),
263 maTypeModel.maTop.toInt32(),
264 maTypeModel.maWidth.toInt32(),
265 maTypeModel.maHeight.toInt32() );
268 // ============================================================================
270 ShapeClientData::ShapeClientData() :
271 mnObjType( XML_TOKEN_INVALID ),
272 mbPrintObject( true )
276 // ----------------------------------------------------------------------------
278 ShapeModel::ShapeModel()
282 ShapeClientData& ShapeModel::createClientData()
284 mxClientData.reset( new ShapeClientData );
285 return *mxClientData;
288 // ----------------------------------------------------------------------------
290 ShapeBase::ShapeBase( const Drawing& rDrawing ) :
291 ShapeType( rDrawing )
295 void ShapeBase::finalizeFragmentImport()
297 // resolve shape template reference
298 if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') )
299 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) )
300 maTypeModel.assignUsed( pShapeType->getTypeModel() );
303 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
305 return 0;
308 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
310 return 0;
313 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
315 Reference< XShape > xShape;
316 /* Calculate shape rectangle. Applications may do something special
317 according to some imported shape client data (e.g. Excel cell anchor). */
318 Rectangle aShapeRect;
319 if( !maShapeModel.mxClientData.get() || !mrDrawing.convertShapeClientAnchor( aShapeRect, maShapeModel.mxClientData->maAnchor ) )
320 aShapeRect = getRectangle( pParentAnchor );
321 // convert the shape, if the calculated rectangle is not empty
322 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
323 xShape = implConvertAndInsert( rxShapes, aShapeRect );
324 return xShape;
327 // protected ------------------------------------------------------------------
329 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
331 // shape properties
332 PropertySet aPropSet( rxShape );
334 // fill style
335 bool bFilled = maTypeModel.mobFilled.get( true );
336 aPropSet.setProperty( PROP_FillStyle, bFilled ? ::com::sun::star::drawing::FillStyle_SOLID : ::com::sun::star::drawing::FillStyle_NONE );
339 // ============================================================================
341 SimpleShape::SimpleShape( const Drawing& rDrawing, const OUString& rService ) :
342 ShapeBase( rDrawing ),
343 maService( rService )
347 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
349 Reference< XShape > xShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, maService, rShapeRect );
350 convertShapeProperties( xShape );
351 return xShape;
354 // ============================================================================
356 RectangleShape::RectangleShape( const Drawing& rDrawing ) :
357 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) )
361 // ============================================================================
363 EllipseShape::EllipseShape( const Drawing& rDrawing ) :
364 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) )
368 // ============================================================================
370 PolyLineShape::PolyLineShape( const Drawing& rDrawing ) :
371 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) )
375 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
377 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
378 // polygon path
379 Rectangle aCoordSys = getCoordSystem();
380 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
382 ::std::vector< Point > aAbsPoints;
383 for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt )
384 aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) );
385 PointSequenceSequence aPointSeq( 1 );
386 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
387 PropertySet aPropSet( xShape );
388 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
390 return xShape;
393 // ============================================================================
395 CustomShape::CustomShape( const Drawing& rDrawing ) :
396 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) )
400 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
402 // try to create a custom shape
403 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
404 if( xShape.is() ) try
406 // create the custom shape geometry
407 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
408 xDefaulter->createCustomShapeDefaults( OUString::valueOf( maTypeModel.monShapeType.get( 0 ) ) );
409 // convert common properties
410 convertShapeProperties( xShape );
412 catch( Exception& )
415 return xShape;
418 // ============================================================================
420 ComplexShape::ComplexShape( const Drawing& rDrawing ) :
421 CustomShape( rDrawing )
425 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
427 XmlFilterBase& rFilter = mrDrawing.getFilter();
428 OUString aGraphicPath = getGraphicPath();
430 // try to find registered OLE object info
431 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
433 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
434 if( pOleObjectInfo->mbDmlShape )
435 return Reference< XShape >();
437 PropertyMap aOleProps;
438 Size aOleSize( rShapeRect.Width, rShapeRect.Height );
439 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
441 Reference< XShape > xShape = lclCreateAndInsertXShape( rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rShapeRect );
442 if( xShape.is() )
444 // set the replacement graphic
445 if( aGraphicPath.getLength() > 0 )
447 Reference< XGraphic > xGraphic = rFilter.importEmbeddedGraphic( aGraphicPath );
448 if( xGraphic.is() )
449 aOleProps[ PROP_Graphic ] <<= xGraphic;
452 PropertySet aPropSet( xShape );
453 aPropSet.setProperties( aOleProps );
455 return xShape;
460 // try to find registered form control info
461 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
462 if( pControlInfo && (pControlInfo->maFragmentPath.getLength() > 0) && (maTypeModel.maName.getLength() > 0) )
464 OSL_ENSURE( maTypeModel.maName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" );
465 ::oox::ole::AxControl aControl( maTypeModel.maName );
466 // load the control properties from fragment
467 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) ) try
469 // create control model and insert it into the form of the draw page
470 Reference< XControlModel > xCtrlModel( aControl.convertAndInsert( mrDrawing.getControlHelper() ), UNO_SET_THROW );
471 if( maShapeModel.mxClientData.get() )
472 mrDrawing.convertControlClientData( xCtrlModel, *maShapeModel.mxClientData );
474 // create the control shape, set control model at the shape
475 Reference< XShape > xShape = lclCreateAndInsertXShape(
476 rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.ControlShape" ), rShapeRect );
477 Reference< XControlShape > xCtrlShape( xShape, UNO_QUERY ); // do not throw, but always return the shape
478 if( xCtrlShape.is() )
479 xCtrlShape->setControl( xCtrlModel );
480 return xShape;
482 catch( Exception& )
485 // on error, proceed and try to create picture from replacement image
488 // try to create a picture object
489 if( aGraphicPath.getLength() > 0 )
491 Reference< XShape > xShape = lclCreateAndInsertXShape( rFilter, rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GraphicObjectShape" ), rShapeRect );
492 if( xShape.is() )
494 OUString aGraphicUrl = rFilter.importEmbeddedGraphicObject( aGraphicPath );
495 if( aGraphicUrl.getLength() > 0 )
497 PropertySet aPropSet( xShape );
498 aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl );
501 return xShape;
504 // default: try to create a custom shape
505 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
508 // ============================================================================
510 GroupShape::GroupShape( const Drawing& rDrawing ) :
511 ShapeBase( rDrawing ),
512 mxChildren( new ShapeContainer( rDrawing ) )
516 GroupShape::~GroupShape()
520 void GroupShape::finalizeFragmentImport()
522 // basic shape processing
523 ShapeBase::finalizeFragmentImport();
524 // finalize all child shapes
525 mxChildren->finalizeFragmentImport();
528 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
530 return mxChildren->getShapeTypeById( rShapeId, true );
533 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
535 return mxChildren->getShapeById( rShapeId, true );
538 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
540 Reference< XShape > xShape;
541 // check that this shape contains children and a valid coordinate system
542 ShapeParentAnchor aParentAnchor;
543 aParentAnchor.maShapeRect = rShapeRect;
544 aParentAnchor.maCoordSys = getCoordSystem();
545 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
547 xShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rShapeRect );
548 Reference< XShapes > xShapes( xShape, UNO_QUERY_THROW );
549 mxChildren->convertAndInsert( xShapes, &aParentAnchor );
551 catch( Exception& )
554 return xShape;
557 // ============================================================================
559 } // namespace vml
560 } // namespace oox