update dev300-m58
[ooovba.git] / oox / source / drawingml / shape.cxx
blob329aa6b362267ff56cb01f9532eb9f8eafdfe32e
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: shape.cxx,v $
10 * $Revision: 1.8.6.1 $
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/drawingml/shape.hxx"
32 #include "oox/drawingml/theme.hxx"
33 #include "oox/drawingml/fillproperties.hxx"
34 #include "oox/drawingml/lineproperties.hxx"
35 #include "oox/drawingml/textbody.hxx"
36 #include "oox/drawingml/table/tableproperties.hxx"
37 #include "oox/core/namespaces.hxx"
38 #include "oox/core/xmlfilterbase.hxx"
39 #include "oox/helper/propertyset.hxx"
40 #include "properties.hxx"
41 #include "tokens.hxx"
43 #include <tools/solar.h> // for the F_PI180 define
44 #include <com/sun/star/graphic/XGraphic.hpp>
45 #include <com/sun/star/container/XNamed.hpp>
46 #include <com/sun/star/beans/XMultiPropertySet.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
49 #include <com/sun/star/text/XText.hpp>
50 #include <basegfx/point/b2dpoint.hxx>
51 #include <basegfx/polygon/b2dpolygon.hxx>
52 #include <basegfx/matrix/b2dhommatrix.hxx>
54 using rtl::OUString;
55 using namespace ::oox::core;
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::awt;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::beans;
60 using namespace ::com::sun::star::frame;
61 using namespace ::com::sun::star::text;
62 using namespace ::com::sun::star::drawing;
64 namespace oox { namespace drawingml {
66 // ============================================================================
68 CreateShapeCallback::CreateShapeCallback( XmlFilterBase& rFilter ) :
69 mrFilter( rFilter )
73 CreateShapeCallback::~CreateShapeCallback()
77 OUString CreateShapeCallback::onCreateXShape( const OUString& rServiceName, const Rectangle& )
79 return rServiceName;
82 void CreateShapeCallback::onXShapeCreated( const Reference< XShape >& ) const
86 // ============================================================================
88 Shape::Shape( const sal_Char* pServiceName )
89 : mpLinePropertiesPtr( new LineProperties )
90 , mpFillPropertiesPtr( new FillProperties )
91 , mpGraphicPropertiesPtr( new GraphicProperties )
92 , mpCustomShapePropertiesPtr( new CustomShapeProperties )
93 , mpMasterTextListStyle( new TextListStyle )
94 , mnSubType( 0 )
95 , mnIndex( 0 )
96 , mnRotation( 0 )
97 , mbFlipH( false )
98 , mbFlipV( false )
100 if ( pServiceName )
101 msServiceName = OUString::createFromAscii( pServiceName );
102 setDefaults();
104 Shape::~Shape()
108 table::TablePropertiesPtr Shape::getTableProperties()
110 if ( !mpTablePropertiesPtr.get() )
111 mpTablePropertiesPtr.reset( new table::TableProperties() );
112 return mpTablePropertiesPtr;
115 void Shape::setDefaults()
117 maShapeProperties[ PROP_TextAutoGrowHeight ] <<= false;
118 maShapeProperties[ PROP_TextWordWrap ] <<= true;
119 maShapeProperties[ PROP_TextLeftDistance ] <<= static_cast< sal_Int32 >( 250 );
120 maShapeProperties[ PROP_TextUpperDistance ] <<= static_cast< sal_Int32 >( 125 );
121 maShapeProperties[ PROP_TextRightDistance ] <<= static_cast< sal_Int32 >( 250 );
122 maShapeProperties[ PROP_TextLowerDistance ] <<= static_cast< sal_Int32 >( 125 );
123 maShapeProperties[ PROP_CharHeight ] <<= static_cast< float >( 18.0 );
126 void Shape::setServiceName( const sal_Char* pServiceName )
128 if ( pServiceName )
129 msServiceName = OUString::createFromAscii( pServiceName );
133 const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
135 ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
136 return (aIt == maShapeStyleRefs.end()) ? 0 : &aIt->second;
139 void Shape::addShape(
140 const ::oox::core::XmlFilterBase& rFilterBase,
141 const ThemePtr& rxTheme,
142 const Reference< XShapes >& rxShapes,
143 const awt::Rectangle* pShapeRect,
144 ShapeIdMap* pShapeMap )
148 rtl::OUString sServiceName( msServiceName );
149 if( sServiceName.getLength() )
151 Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, rxTheme, rxShapes, pShapeRect, sal_False ) );
153 if( pShapeMap && msId.getLength() )
155 (*pShapeMap)[ msId ] = shared_from_this();
158 // if this is a group shape, we have to add also each child shape
159 Reference< XShapes > xShapes( xShape, UNO_QUERY );
160 if ( xShapes.is() )
161 addChildren( rFilterBase, *this, rxTheme, xShapes, pShapeRect ? *pShapeRect : awt::Rectangle( maPosition.X, maPosition.Y, maSize.Width, maSize.Height ), pShapeMap );
164 catch( const Exception& )
169 void Shape::applyShapeReference( const Shape& rReferencedShape )
171 mpTextBody = TextBodyPtr( new TextBody( *rReferencedShape.mpTextBody.get() ) );
172 maShapeProperties = rReferencedShape.maShapeProperties;
173 mpLinePropertiesPtr = LinePropertiesPtr( new LineProperties( *rReferencedShape.mpLinePropertiesPtr.get() ) );
174 mpFillPropertiesPtr = FillPropertiesPtr( new FillProperties( *rReferencedShape.mpFillPropertiesPtr.get() ) );
175 mpCustomShapePropertiesPtr = CustomShapePropertiesPtr( new CustomShapeProperties( *rReferencedShape.mpCustomShapePropertiesPtr.get() ) );
176 mpTablePropertiesPtr = table::TablePropertiesPtr( rReferencedShape.mpTablePropertiesPtr.get() ? new table::TableProperties( *rReferencedShape.mpTablePropertiesPtr.get() ) : NULL );
177 mpMasterTextListStyle = TextListStylePtr( new TextListStyle( *rReferencedShape.mpMasterTextListStyle.get() ) );
178 maShapeStyleRefs = rReferencedShape.maShapeStyleRefs;
179 maSize = rReferencedShape.maSize;
180 maPosition = rReferencedShape.maPosition;
181 mnRotation = rReferencedShape.mnRotation;
182 mbFlipH = rReferencedShape.mbFlipH;
183 mbFlipV = rReferencedShape.mbFlipV;
186 // for group shapes, the following method is also adding each child
187 void Shape::addChildren(
188 const ::oox::core::XmlFilterBase& rFilterBase,
189 Shape& rMaster,
190 const ThemePtr& rxTheme,
191 const Reference< XShapes >& rxShapes,
192 const awt::Rectangle& rClientRect,
193 ShapeIdMap* pShapeMap )
195 // first the global child union needs to be calculated
196 sal_Int32 nGlobalLeft = SAL_MAX_INT32;
197 sal_Int32 nGlobalRight = SAL_MIN_INT32;
198 sal_Int32 nGlobalTop = SAL_MAX_INT32;
199 sal_Int32 nGlobalBottom= SAL_MIN_INT32;
200 std::vector< ShapePtr >::iterator aIter( rMaster.maChildren.begin() );
201 while( aIter != rMaster.maChildren.end() )
203 sal_Int32 l = (*aIter)->maPosition.X;
204 sal_Int32 t = (*aIter)->maPosition.Y;
205 sal_Int32 r = l + (*aIter)->maSize.Width;
206 sal_Int32 b = t + (*aIter)->maSize.Height;
207 if ( nGlobalLeft > l )
208 nGlobalLeft = l;
209 if ( nGlobalRight < r )
210 nGlobalRight = r;
211 if ( nGlobalTop > t )
212 nGlobalTop = t;
213 if ( nGlobalBottom < b )
214 nGlobalBottom = b;
215 aIter++;
217 aIter = rMaster.maChildren.begin();
218 while( aIter != rMaster.maChildren.end() )
220 Rectangle aShapeRect;
221 Rectangle* pShapeRect = 0;
222 if ( ( nGlobalLeft != SAL_MAX_INT32 ) && ( nGlobalRight != SAL_MIN_INT32 ) && ( nGlobalTop != SAL_MAX_INT32 ) && ( nGlobalBottom != SAL_MIN_INT32 ) )
224 sal_Int32 nGlobalWidth = nGlobalRight - nGlobalLeft;
225 sal_Int32 nGlobalHeight = nGlobalBottom - nGlobalTop;
226 if ( nGlobalWidth && nGlobalHeight )
228 double fWidth = (*aIter)->maSize.Width;
229 double fHeight= (*aIter)->maSize.Height;
230 double fXScale = (double)rClientRect.Width / (double)nGlobalWidth;
231 double fYScale = (double)rClientRect.Height / (double)nGlobalHeight;
232 aShapeRect.X = static_cast< sal_Int32 >( ( ( (*aIter)->maPosition.X - nGlobalLeft ) * fXScale ) + rClientRect.X );
233 aShapeRect.Y = static_cast< sal_Int32 >( ( ( (*aIter)->maPosition.Y - nGlobalTop ) * fYScale ) + rClientRect.Y );
234 fWidth *= fXScale;
235 fHeight *= fYScale;
236 aShapeRect.Width = static_cast< sal_Int32 >( fWidth );
237 aShapeRect.Height = static_cast< sal_Int32 >( fHeight );
238 pShapeRect = &aShapeRect;
241 (*aIter++)->addShape( rFilterBase, rxTheme, rxShapes, pShapeRect, pShapeMap );
245 Reference< XShape > Shape::createAndInsert(
246 const ::oox::core::XmlFilterBase& rFilterBase,
247 const rtl::OUString& rServiceName,
248 const ThemePtr& rxTheme,
249 const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes,
250 const awt::Rectangle* pShapeRect,
251 sal_Bool bClearText )
253 awt::Size aSize( pShapeRect ? awt::Size( pShapeRect->Width, pShapeRect->Height ) : maSize );
254 awt::Point aPosition( pShapeRect ? awt::Point( pShapeRect->X, pShapeRect->Y ) : maPosition );
256 OUString aServiceName = rServiceName;
257 if( mxCreateCallback.get() )
258 aServiceName = mxCreateCallback->onCreateXShape( aServiceName, awt::Rectangle( aPosition.X / 360, aPosition.Y / 360, aSize.Width / 360, aSize.Height / 360 ) );
260 basegfx::B2DHomMatrix aTransformation;
261 if( aSize.Width != 1 || aSize.Height != 1)
263 // take care there are no zeros used by error
264 aTransformation.scale(
265 aSize.Width ? aSize.Width / 360.0 : 1.0,
266 aSize.Height ? aSize.Height / 360.0 : 1.0 );
269 if( mbFlipH || mbFlipV || mnRotation != 0)
271 // calculate object's center
272 basegfx::B2DPoint aCenter(0.5, 0.5);
273 aCenter *= aTransformation;
275 // center object at origin
276 aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
278 if( mbFlipH || mbFlipV)
280 // mirror around object's center
281 aTransformation.scale( mbFlipH ? -1.0 : 1.0, mbFlipV ? -1.0 : 1.0 );
284 if( mnRotation != 0 )
286 // rotate around object's center
287 aTransformation.rotate( F_PI180 * ( (double)mnRotation / 60000.0 ) );
290 // move object back from center
291 aTransformation.translate( aCenter.getX(), aCenter.getY() );
294 if( aPosition.X != 0 || aPosition.Y != 0)
296 // if global position is used, add it to transformation
297 aTransformation.translate( aPosition.X / 360.0, aPosition.Y / 360.0 );
300 // special for lineshape
301 if ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.LineShape" ) )
303 ::basegfx::B2DPolygon aPoly;
304 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
305 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
306 aPoly.transform( aTransformation );
308 // now creating the corresponding PolyPolygon
309 sal_Int32 i, nNumPoints = aPoly.count();
310 uno::Sequence< awt::Point > aPointSequence( nNumPoints );
311 awt::Point* pPoints = aPointSequence.getArray();
312 for( i = 0; i < nNumPoints; ++i )
314 const ::basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );
315 pPoints[ i ] = awt::Point( static_cast< sal_Int32 >( aPoint.getX() ), static_cast< sal_Int32 >( aPoint.getY() ) );
317 uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
318 aPolyPolySequence.getArray()[ 0 ] = aPointSequence;
320 maShapeProperties[ PROP_PolyPolygon ] <<= aPolyPolySequence;
322 else if ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.ConnectorShape" ) )
324 ::basegfx::B2DPolygon aPoly;
325 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
326 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
327 aPoly.transform( aTransformation );
329 basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
330 basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
331 awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
332 awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );
334 maShapeProperties[ PROP_StartPosition ] <<= aAWTStartPosition;
335 maShapeProperties[ PROP_EndPosition ] <<= aAWTEndPosition;
337 else
339 // now set transformation for this object
340 HomogenMatrix3 aMatrix;
342 aMatrix.Line1.Column1 = aTransformation.get(0,0);
343 aMatrix.Line1.Column2 = aTransformation.get(0,1);
344 aMatrix.Line1.Column3 = aTransformation.get(0,2);
346 aMatrix.Line2.Column1 = aTransformation.get(1,0);
347 aMatrix.Line2.Column2 = aTransformation.get(1,1);
348 aMatrix.Line2.Column3 = aTransformation.get(1,2);
350 aMatrix.Line3.Column1 = aTransformation.get(2,0);
351 aMatrix.Line3.Column2 = aTransformation.get(2,1);
352 aMatrix.Line3.Column3 = aTransformation.get(2,2);
354 maShapeProperties[ PROP_Transformation ] <<= aMatrix;
356 Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
357 if ( !mxShape.is() )
358 mxShape = Reference< drawing::XShape >( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
360 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
361 if( mxShape.is() && xSet.is() )
363 if( msName.getLength() )
365 Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
366 if( xNamed.is() )
367 xNamed->setName( msName );
369 rxShapes->add( mxShape );
371 // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
372 if ( bClearText )
374 uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
375 if ( xText.is() )
377 OUString aEmpty;
378 xText->setString( aEmpty );
382 LineProperties aLineProperties;
383 aLineProperties.maLineFill.moFillType = XML_noFill;
384 sal_Int32 nLinePhClr = -1;
385 FillProperties aFillProperties;
386 aFillProperties.moFillType = XML_noFill;
387 sal_Int32 nFillPhClr = -1;
389 if( rxTheme.get() )
391 if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
393 if( const LineProperties* pLineProps = rxTheme->getLineStyle( pLineRef->mnThemedIdx ) )
394 aLineProperties.assignUsed( *pLineProps );
395 nLinePhClr = pLineRef->maPhClr.getColor( rFilterBase );
397 if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
399 if( const FillProperties* pFillProps = rxTheme->getFillStyle( pFillRef->mnThemedIdx ) )
400 aFillProperties.assignUsed( *pFillProps );
401 nFillPhClr = pFillRef->maPhClr.getColor( rFilterBase );
403 // if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_fillRef ) )
404 // {
405 // if( const EffectProperties* pEffectProps = rxTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
406 // aEffectProperties.assignUsed( *pEffectProps );
407 // nEffectPhClr = pEffectRef->maPhClr.getColor( rFilterBase );
408 // }
411 aLineProperties.assignUsed( getLineProperties() );
412 aFillProperties.assignUsed( getFillProperties() );
414 PropertyMap aShapeProperties;
415 aShapeProperties.insert( getShapeProperties().begin(), getShapeProperties().end() );
416 if( mxCreateCallback.get() )
417 aShapeProperties.insert( mxCreateCallback->getShapeProperties().begin(), mxCreateCallback->getShapeProperties().end() );
419 // add properties from textbody to shape properties
420 if( mpTextBody.get() )
421 aShapeProperties.insert( mpTextBody->getTextProperties().maPropertyMap.begin(), mpTextBody->getTextProperties().maPropertyMap.end() );
423 // applying properties
424 PropertySet aPropSet( xSet );
425 if ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.GraphicObjectShape" ) )
426 mpGraphicPropertiesPtr->pushToPropSet( aPropSet, rFilterBase, -1 );
427 if ( mpTablePropertiesPtr.get() && ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.TableShape" ) ) )
428 mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle );
429 aFillProperties.pushToPropSet( aPropSet, FillProperties::DEFAULT_IDS, rFilterBase, rFilterBase.getModelObjectHelper(), mnRotation, nFillPhClr );
430 aLineProperties.pushToPropSet( aPropSet, LineProperties::DEFAULT_IDS, rFilterBase, rFilterBase.getModelObjectHelper(), nLinePhClr );
432 // applying autogrowheight property before setting shape size, because
433 // the shape size might be changed if currently autogrowheight is true
434 // we must also check that the PropertySet supports the property.
435 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
436 const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight );
437 if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) )
438 if( /*const Any* pAutoGrowHeight =*/ aShapeProperties.getProperty( PROP_TextAutoGrowHeight ) )
439 xSet->setPropertyValue( rPropName, Any( false ) );
441 // do not set properties at a group shape (this causes assertions from svx)
442 if( aServiceName != OUString::createFromAscii( "com.sun.star.drawing.GroupShape" ) )
443 aPropSet.setProperties( aShapeProperties );
445 if( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.CustomShape" ) )
446 mpCustomShapePropertiesPtr->pushToPropSet( rFilterBase, xSet, mxShape );
448 // in some cases, we don't have any text body.
449 if( getTextBody() )
451 Reference < XText > xText( mxShape, UNO_QUERY );
452 if ( xText.is() ) // not every shape is supporting an XText interface (e.g. GroupShape)
454 TextCharacterProperties aCharStyleProperties;
455 if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
457 if( rxTheme.get() )
458 if( const TextCharacterProperties* pCharProps = rxTheme->getFontStyle( pFontRef->mnThemedIdx ) )
459 aCharStyleProperties.assignUsed( *pCharProps );
460 aCharStyleProperties.maCharColor.assignIfUsed( pFontRef->maPhClr );
463 Reference < XTextCursor > xAt = xText->createTextCursor();
464 getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
469 // use a callback for further processing on the XShape (e.g. charts)
470 if( mxShape.is() && mxCreateCallback.get() )
471 mxCreateCallback->onXShapeCreated( mxShape );
473 return mxShape;
476 // the properties of rSource which are not part of rDest are being put into rDest
477 void addMissingProperties( const PropertyMap& rSource, PropertyMap& rDest )
479 PropertyMap::const_iterator aSourceIter( rSource.begin() );
480 while( aSourceIter != rSource.end() )
482 if ( rDest.find( (*aSourceIter ).first ) == rDest.end() )
483 rDest[ (*aSourceIter).first ] <<= (*aSourceIter).second;
484 aSourceIter++;
488 void Shape::setTextBody(const TextBodyPtr & pTextBody)
490 mpTextBody = pTextBody;
494 TextBodyPtr Shape::getTextBody()
496 return mpTextBody;
499 void Shape::setMasterTextListStyle( const TextListStylePtr& pMasterTextListStyle )
501 mpMasterTextListStyle = pMasterTextListStyle;