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"
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>
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
) :
73 CreateShapeCallback::~CreateShapeCallback()
77 OUString
CreateShapeCallback::onCreateXShape( const OUString
& rServiceName
, const Rectangle
& )
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
)
101 msServiceName
= OUString::createFromAscii( pServiceName
);
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
)
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
);
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
,
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
)
209 if ( nGlobalRight
< r
)
211 if ( nGlobalTop
> t
)
213 if ( nGlobalBottom
< b
)
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
);
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
;
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
);
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
);
367 xNamed
->setName( msName
);
369 rxShapes
->add( mxShape
);
371 // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
374 uno::Reference
< text::XText
> xText( mxShape
, uno::UNO_QUERY
);
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;
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 ) )
405 // if( const EffectProperties* pEffectProps = rxTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
406 // aEffectProperties.assignUsed( *pEffectProps );
407 // nEffectPhClr = pEffectRef->maPhClr.getColor( rFilterBase );
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.
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
) )
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
);
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
;
488 void Shape::setTextBody(const TextBodyPtr
& pTextBody
)
490 mpTextBody
= pTextBody
;
494 TextBodyPtr
Shape::getTextBody()
499 void Shape::setMasterTextListStyle( const TextListStylePtr
& pMasterTextListStyle
)
501 mpMasterTextListStyle
= pMasterTextListStyle
;