update credits
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blob253fce6ba73866b81113647ca03510ffe9c1cdf8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <algorithm>
21 #include <boost/optional.hpp>
23 #include "oox/vml/vmlshape.hxx"
25 #include <com/sun/star/beans/PropertyValues.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/awt/XControlModel.hpp>
28 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
29 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
30 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
31 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
32 #include <com/sun/star/drawing/XShapes.hpp>
33 #include <com/sun/star/drawing/XControlShape.hpp>
34 #include <com/sun/star/graphic/XGraphic.hpp>
35 #include <com/sun/star/table/BorderLine2.hpp>
36 #include <com/sun/star/text/HoriOrientation.hpp>
37 #include <com/sun/star/text/RelOrientation.hpp>
38 #include <com/sun/star/text/SizeType.hpp>
39 #include <com/sun/star/text/VertOrientation.hpp>
40 #include <com/sun/star/text/WrapTextMode.hpp>
41 #include <com/sun/star/text/XTextContent.hpp>
42 #include <com/sun/star/text/XTextDocument.hpp>
43 #include <com/sun/star/text/XTextFrame.hpp>
44 #include <com/sun/star/text/TextContentAnchorType.hpp>
45 #include <rtl/math.hxx>
46 #include <rtl/ustrbuf.hxx>
47 #include <svx/svdtrans.hxx>
48 #include "oox/drawingml/shapepropertymap.hxx"
49 #include "oox/helper/graphichelper.hxx"
50 #include "oox/helper/propertyset.hxx"
51 #include "oox/ole/axcontrol.hxx"
52 #include "oox/ole/axcontrolfragment.hxx"
53 #include "oox/ole/oleobjecthelper.hxx"
54 #include "oox/vml/vmldrawing.hxx"
55 #include "oox/vml/vmlshapecontainer.hxx"
56 #include "oox/vml/vmltextbox.hxx"
57 #include "oox/core/xmlfilterbase.hxx"
58 #include "oox/helper/containerhelper.hxx"
60 using ::com::sun::star::beans::XPropertySet;
61 using ::com::sun::star::uno::Any;
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::text;
66 namespace oox {
67 namespace vml {
69 // ============================================================================
71 using namespace ::com::sun::star;
72 using namespace ::com::sun::star::drawing;
73 using namespace ::com::sun::star::graphic;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star::io;
77 using ::oox::core::XmlFilterBase;
79 // ============================================================================
81 namespace {
83 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
84 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
86 // ----------------------------------------------------------------------------
88 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
90 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
91 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
92 awt::Point aAbsPoint;
93 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
94 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
95 return aAbsPoint;
98 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
100 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
101 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
102 awt::Rectangle aAbsRect;
103 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
104 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
105 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
106 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
107 return aAbsRect;
110 } // namespace
112 // ============================================================================
114 ShapeTypeModel::ShapeTypeModel():
115 mbAutoHeight( sal_False ),
116 mbVisible( sal_True )
120 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
122 moShapeType.assignIfUsed( rSource.moShapeType );
123 moCoordPos.assignIfUsed( rSource.moCoordPos );
124 moCoordSize.assignIfUsed( rSource.moCoordSize );
125 /* The style properties position, left, top, width, height, margin-left,
126 margin-top are not derived from shape template to shape. */
127 maStrokeModel.assignUsed( rSource.maStrokeModel );
128 maFillModel.assignUsed( rSource.maFillModel );
129 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
130 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
133 // ----------------------------------------------------------------------------
135 ShapeType::ShapeType( Drawing& rDrawing ) :
136 mrDrawing( rDrawing )
140 ShapeType::~ShapeType()
144 sal_Int32 ShapeType::getShapeType() const
146 return maTypeModel.moShapeType.get( 0 );
149 OUString ShapeType::getGraphicPath() const
151 return maTypeModel.moGraphicPath.get( OUString() );
154 awt::Rectangle ShapeType::getCoordSystem() const
156 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
157 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
158 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
161 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
163 return pParentAnchor ?
164 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
165 getAbsRectangle();
168 awt::Rectangle ShapeType::getAbsRectangle() const
170 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
172 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
173 if ( nWidth == 0 )
174 nWidth = 1;
176 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
177 if ( nHeight == 0 )
178 nHeight = 1;
180 sal_Int32 nLeft = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true )
181 + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true );
182 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
183 nLeft = 1;
185 return awt::Rectangle(
186 nLeft,
187 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
188 nWidth, nHeight );
191 awt::Rectangle ShapeType::getRelRectangle() const
193 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
194 if ( nWidth == 0 )
195 nWidth = 1;
197 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
198 if ( nHeight == 0 )
199 nHeight = 1;
201 return awt::Rectangle(
202 maTypeModel.maLeft.toInt32(),
203 maTypeModel.maTop.toInt32(),
204 nWidth, nHeight );
207 // ============================================================================
209 ClientData::ClientData() :
210 mnObjType( XML_TOKEN_INVALID ),
211 mnTextHAlign( XML_Left ),
212 mnTextVAlign( XML_Top ),
213 mnCol( -1 ),
214 mnRow( -1 ),
215 mnChecked( VML_CLIENTDATA_UNCHECKED ),
216 mnDropStyle( XML_Combo ),
217 mnDropLines( 1 ),
218 mnVal( 0 ),
219 mnMin( 0 ),
220 mnMax( 0 ),
221 mnInc( 0 ),
222 mnPage( 0 ),
223 mnSelType( XML_Single ),
224 mnVTEdit( VML_CLIENTDATA_TEXT ),
225 mbPrintObject( true ),
226 mbVisible( false ),
227 mbDde( false ),
228 mbNo3D( false ),
229 mbNo3D2( false ),
230 mbMultiLine( false ),
231 mbVScroll( false ),
232 mbSecretEdit( false )
236 // ----------------------------------------------------------------------------
238 ShapeModel::ShapeModel()
242 ShapeModel::~ShapeModel()
246 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
248 mxTextBox.reset( new TextBox(rModel) );
249 return *mxTextBox;
252 ClientData& ShapeModel::createClientData()
254 mxClientData.reset( new ClientData );
255 return *mxClientData;
258 // ----------------------------------------------------------------------------
260 ShapeBase::ShapeBase( Drawing& rDrawing ) :
261 ShapeType( rDrawing )
265 void ShapeBase::finalizeFragmentImport()
267 // resolve shape template reference
268 if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') )
269 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) )
270 maTypeModel.assignUsed( pShapeType->getTypeModel() );
273 OUString ShapeBase::getShapeName() const
275 if( !maTypeModel.maShapeName.isEmpty() )
276 return maTypeModel.maShapeName;
278 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
279 if( !aBaseName.isEmpty() )
281 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
282 if( nShapeIdx > 0 )
283 return OUStringBuffer( aBaseName ).append( sal_Unicode( ' ' ) ).append( nShapeIdx ).makeStringAndClear();
286 return OUString();
289 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
291 return 0;
294 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
296 return 0;
299 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
301 Reference< XShape > xShape;
302 if( mrDrawing.isShapeSupported( *this ) )
304 /* Calculate shape rectangle. Applications may do something special
305 according to some imported shape client data (e.g. Excel cell anchor). */
306 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
308 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
310 xShape = implConvertAndInsert( rxShapes, aShapeRect );
311 if( xShape.is() )
313 // set imported or generated shape name (not supported by form controls)
314 PropertySet aShapeProp( xShape );
315 if( aShapeProp.hasProperty( PROP_Name ) )
316 aShapeProp.setProperty( PROP_Name, getShapeName() );
317 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
318 if ( xControlShape.is() && !getTypeModel().mbVisible )
320 PropertySet aControlShapeProp( xControlShape->getControl() );
321 aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( sal_False ) );
323 /* Notify the drawing that a new shape has been inserted. For
324 convenience, pass the rectangle that contains position and
325 size of the shape. */
326 bool bGroupChild = pParentAnchor != 0;
327 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
330 else
331 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
333 return xShape;
336 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const
338 if( rxShape.is() )
340 /* Calculate shape rectangle. Applications may do something special
341 according to some imported shape client data (e.g. Excel cell anchor). */
342 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
344 // convert the shape, if the calculated rectangle is not empty
345 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
347 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
348 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
349 convertShapeProperties( rxShape );
354 // protected ------------------------------------------------------------------
356 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
358 /* Calculate shape rectangle. Applications may do something special
359 according to some imported shape client data (e.g. Excel cell anchor). */
360 awt::Rectangle aShapeRect;
361 const ClientData* pClientData = getClientData();
362 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
363 aShapeRect = getRectangle( pParentAnchor );
364 return aShapeRect;
367 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
369 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
370 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
371 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
372 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
374 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
375 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
377 // Any other service supporting the ShadowFormat property?
378 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
379 // TextFrames have BackColor, not FillColor
380 if (aPropMap.hasProperty(PROP_FillColor))
382 aPropMap.setProperty(PROP_BackColor, aPropMap[PROP_FillColor]);
383 aPropMap.erase(PROP_FillColor);
385 // And no LineColor property; individual borders can have colors and widths
386 boost::optional<sal_Int32> oLineWidth;
387 if (maTypeModel.maStrokeModel.moWeight.has())
388 oLineWidth.reset(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maStrokeModel.moWeight.get(), 0, false, false));
389 if (aPropMap.hasProperty(PROP_LineColor))
391 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
392 static sal_Int32 aBorders[] = {
393 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
395 for (unsigned int i = 0; i < SAL_N_ELEMENTS(aBorders); ++i)
397 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(aBorders[i])).get<table::BorderLine2>();
398 aBorderLine.Color = aPropMap[PROP_LineColor].get<sal_Int32>();
399 if (oLineWidth)
400 aBorderLine.LineWidth = *oLineWidth;
401 aPropMap.setProperty(aBorders[i], uno::makeAny(aBorderLine));
403 aPropMap.erase(PROP_LineColor);
406 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
407 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape);
409 PropertySet( rxShape ).setProperties( aPropMap );
412 // ============================================================================
414 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
415 ShapeBase( rDrawing ),
416 maService( rService )
420 void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel)
422 sal_Int32 nSurround = com::sun::star::text::WrapTextMode_THROUGHT;
423 if ( rTypeModel.moWrapType.get() == "square" || rTypeModel.moWrapType .get()== "tight" ||
424 rTypeModel.moWrapType.get() == "through" )
426 nSurround = com::sun::star::text::WrapTextMode_PARALLEL;
427 if ( rTypeModel.moWrapSide.get() == "left" )
428 nSurround = com::sun::star::text::WrapTextMode_LEFT;
429 else if ( rTypeModel.moWrapSide.get() == "right" )
430 nSurround = com::sun::star::text::WrapTextMode_RIGHT;
432 else if ( rTypeModel.moWrapType.get() == "topAndBottom" )
433 nSurround = com::sun::star::text::WrapTextMode_NONE;
435 rPropSet.setProperty(PROP_Surround, nSurround);
438 void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel)
440 if ( rTypeModel.maPositionHorizontal == "center" )
441 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
443 if ( rTypeModel.maPositionHorizontalRelative == "page" )
444 rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
446 if ( rTypeModel.maPositionVertical == "center" )
447 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
449 if ( rTypeModel.maPosition == "absolute" )
451 // Word supports as-character (inline) and at-character only, absolute can't be inline.
452 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
454 if ( rTypeModel.maPositionVerticalRelative == "page" )
456 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
458 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
460 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
462 else
464 // Vertical placement relative to margin, because parent style must not modify vertical position
465 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
468 else if( rTypeModel.maPosition == "relative" )
469 { // I'm not very sure this is correct either.
470 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
472 else // static (is the default) means anchored inline
474 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
476 lcl_setSurround( rPropSet, rTypeModel );
479 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
481 awt::Rectangle aShapeRect(rShapeRect);
482 boost::optional<sal_Int32> oRotation;
483 if (!maTypeModel.maRotation.isEmpty())
484 oRotation.reset(maTypeModel.maRotation.toInt32());
485 if (!maTypeModel.maFlip.isEmpty())
487 if (maTypeModel.maFlip.equalsAscii("x"))
489 aShapeRect.X += aShapeRect.Width;
490 aShapeRect.Width *= -1;
491 if (oRotation)
492 oRotation.reset(360 - *oRotation);
494 else if (maTypeModel.maFlip.equalsAscii("y"))
496 aShapeRect.Y += aShapeRect.Height;
497 aShapeRect.Height *= -1;
501 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
502 convertShapeProperties( xShape );
504 if ( maService.equalsAscii( "com.sun.star.text.TextFrame" ) )
506 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
507 PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
508 if( getTextBox()->borderDistanceSet )
510 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
511 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
512 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
513 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
516 else
518 // FIXME Setting the relative width/heigh only for everything but text frames as
519 // TextFrames already have relative widht/heigh feature... but currently not working
520 // in the way we need.
522 // Set the relative width / height if any
523 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
525 // Only page-relative width is supported ATM
526 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
528 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
529 // Only apply if nWidth != 0
530 if ( nWidth )
531 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
534 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
536 // Only page-relative height is supported ATM
537 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
539 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
540 // Only apply if nHeight != 0
541 if ( nHeight )
542 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
546 // drawinglayer default is center, MSO default is top.
547 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
548 if (maTypeModel.maVTextAnchor == "middle")
549 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
550 else if (maTypeModel.maVTextAnchor == "bottom")
551 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
552 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust));
554 if (getTextBox())
556 getTextBox()->convert(xShape);
557 if (getTextBox()->borderDistanceSet)
559 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, makeAny(sal_Int32(getTextBox()->borderDistanceLeft)));
560 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, makeAny(sal_Int32(getTextBox()->borderDistanceTop)));
561 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, makeAny(sal_Int32(getTextBox()->borderDistanceRight)));
562 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, makeAny(sal_Int32(getTextBox()->borderDistanceBottom)));
567 // Import Legacy Fragments (if any)
568 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
570 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
571 if( xInStrm.is() )
572 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
575 PropertySet aPropertySet(xShape);
576 if (xShape.is() && oRotation)
578 // See DffPropertyReader::Fix16ToAngle(): in VML, positive rotation angles are clockwise, we have them as counter-clockwise.
579 // Additionally, VML type is 0..360, our is 0.36000.
580 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(sal_Int32(NormAngle360((*oRotation) * -100))));
581 // If rotation is used, simple setPosition() is not enough.
582 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny( aShapeRect.X ) );
583 aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny( aShapeRect.Y ) );
586 lcl_SetAnchorType(aPropertySet, maTypeModel);
588 return xShape;
591 Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString& rGraphicPath ) const
593 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
594 if( xShape.is() )
596 XmlFilterBase& rFilter = mrDrawing.getFilter();
597 OUString aGraphicUrl = rFilter.getGraphicHelper().importEmbeddedGraphicObject( rGraphicPath );
598 PropertySet aPropSet( xShape );
599 if( !aGraphicUrl.isEmpty() )
601 aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl );
603 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
604 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
605 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
607 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
608 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
609 aPropSet.setProperty(PROP_Opaque, sal_False);
612 lcl_SetAnchorType(aPropSet, maTypeModel);
614 return xShape;
617 // ============================================================================
619 RectangleShape::RectangleShape( Drawing& rDrawing ) :
620 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
624 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
626 OUString aGraphicPath = getGraphicPath();
628 // try to create a picture object
629 if(!aGraphicPath.isEmpty())
630 return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
632 // default: try to create a rectangle shape
633 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
634 OUString sArcsize = maTypeModel.maArcsize;
635 if ( !sArcsize.isEmpty( ) )
637 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
638 sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
639 // Get the smallest half-side
640 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
641 sal_Int32 nRadius = 0;
642 if ( cLastChar == 'f' )
643 nRadius = size * nValue / 65536;
644 else if ( cLastChar == '%' )
645 nRadius = size * nValue / 100;
646 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
648 return xShape;
651 // ============================================================================
653 EllipseShape::EllipseShape( Drawing& rDrawing ) :
654 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
658 // ============================================================================
660 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
661 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
665 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
667 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
668 // polygon path
669 awt::Rectangle aCoordSys = getCoordSystem();
670 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
672 ::std::vector< awt::Point > aAbsPoints;
673 for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt )
674 aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) );
675 PointSequenceSequence aPointSeq( 1 );
676 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
677 PropertySet aPropSet( xShape );
678 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
680 return xShape;
683 LineShape::LineShape(Drawing& rDrawing)
684 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
688 awt::Rectangle LineShape::getAbsRectangle() const
690 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
691 awt::Rectangle aShapeRect;
692 sal_Int32 nIndex = 0;
694 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
695 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
696 nIndex = 0;
697 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
698 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
699 return aShapeRect;
702 awt::Rectangle LineShape::getRelRectangle() const
704 awt::Rectangle aShapeRect;
705 sal_Int32 nIndex = 0;
707 aShapeRect.X = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
708 aShapeRect.Y = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
709 nIndex = 0;
710 aShapeRect.Width = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.X;
711 aShapeRect.Height = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.Y;
712 return aShapeRect;
715 // ============================================================================
717 BezierShape::BezierShape(Drawing& rDrawing)
718 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
722 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
724 awt::Rectangle aCoordSys = getCoordSystem();
725 PolyPolygonBezierCoords aBezierCoords;
727 // If we have an 'x' in the last part of the path it means it is closed...
728 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
729 if ( nPos != -1 && maShapeModel.maVmlPath.copy(nPos).indexOf('x') != -1 )
731 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
734 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
736 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
738 // Bezier paths may consist of one or more sub-paths
739 typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
740 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
741 SubPathList aCoordLists;
742 FlagsList aFlagLists;
743 sal_Int32 nIndex = 0;
745 // Curve defined by to, from, control1 and control2 attributes
746 if ( maShapeModel.maVmlPath.isEmpty() )
748 aCoordLists.push_back( ::std::vector< awt::Point >() );
749 aFlagLists.push_back( ::std::vector< PolygonFlags >() );
751 // Start point
752 aCoordLists[ 0 ].push_back(
753 awt::Point(ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
754 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) ) );
755 // Control point 1
756 aCoordLists[ 0 ].push_back(
757 awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
758 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) ) );
759 // Control point 2
760 aCoordLists[ 0 ].push_back(
761 awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
762 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) ) );
763 // End point
764 aCoordLists[ 0 ].push_back(
765 awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
766 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) ) );
768 // First and last points are normals, points 2 and 4 are controls
769 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
770 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
771 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
773 // Curve defined by path attribute
774 else
776 // Parse VML path string and convert to absolute coordinates
777 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
779 for ( SubPathList::iterator aListIt = aCoordLists.begin(); aListIt != aCoordLists.end(); ++aListIt )
780 for ( ::std::vector< awt::Point >::iterator aPointIt = (*aListIt).begin(); aPointIt != (*aListIt).end(); ++aPointIt)
782 (*aPointIt) = lclGetAbsPoint( (*aPointIt), rShapeRect, aCoordSys );
786 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
787 for ( unsigned int i = 0; i < aCoordLists.size(); i++ )
788 aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
790 aBezierCoords.Flags.realloc( aFlagLists.size() );
791 for ( unsigned int i = 0; i < aFlagLists.size(); i++ )
792 aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
794 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
795 && aCoordLists.front().front().X == aCoordLists.back().back().X
796 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
797 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
798 // force to closed bezier shape (otherwise e.g. fill won't work).
799 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
803 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
805 if( aBezierCoords.Coordinates.hasElements())
807 PropertySet aPropSet( xShape );
808 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
811 // Hacky way of ensuring the shape is correctly sized/positioned
812 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
813 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
814 return xShape;
817 // ============================================================================
819 CustomShape::CustomShape( Drawing& rDrawing ) :
820 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
824 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
826 // try to create a custom shape
827 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
828 if( xShape.is() ) try
830 // create the custom shape geometry
831 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
832 xDefaulter->createCustomShapeDefaults( OUString::valueOf( getShapeType() ) );
833 // convert common properties
834 convertShapeProperties( xShape );
836 catch( Exception& )
839 return xShape;
842 // ============================================================================
844 ComplexShape::ComplexShape( Drawing& rDrawing ) :
845 CustomShape( rDrawing )
849 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
851 XmlFilterBase& rFilter = mrDrawing.getFilter();
852 sal_Int32 nShapeType = getShapeType();
853 OUString aGraphicPath = getGraphicPath();
855 // try to find registered OLE object info
856 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
858 OSL_ENSURE( nShapeType == VML_SHAPETYPE_PICTUREFRAME, "ComplexShape::implConvertAndInsert - unexpected shape type" );
860 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
861 if( pOleObjectInfo->mbDmlShape )
862 return Reference< XShape >();
864 PropertyMap aOleProps;
865 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
866 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
868 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
869 if( xShape.is() )
871 // set the replacement graphic
872 if( !aGraphicPath.isEmpty() )
874 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath );
875 if( xGraphic.is() )
876 aOleProps[ PROP_Graphic ] <<= xGraphic;
879 PropertySet aPropSet( xShape );
880 aPropSet.setProperties( aOleProps );
882 return xShape;
887 // try to find registered form control info
888 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
889 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
891 OSL_ENSURE( nShapeType == VML_SHAPETYPE_HOSTCONTROL, "ComplexShape::implConvertAndInsert - unexpected shape type" );
892 OUString aShapeName = getShapeName();
893 if( !aShapeName.isEmpty() )
895 OSL_ENSURE( aShapeName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" );
896 // load the control properties from fragment
897 ::oox::ole::EmbeddedControl aControl( aShapeName );
898 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
900 // create and return the control shape (including control model)
901 sal_Int32 nCtrlIndex = -1;
902 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
903 // on error, proceed and try to create picture from replacement image
904 if( xShape.is() )
905 return xShape;
910 // host application wants to create the shape (do not try failed OLE controls again)
911 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
913 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
914 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
915 if( xShape.is() )
916 return xShape;
919 // try to create a picture object
920 if( !aGraphicPath.isEmpty() )
921 return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
923 // default: try to create a custom shape
924 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
927 // ============================================================================
929 GroupShape::GroupShape( Drawing& rDrawing ) :
930 ShapeBase( rDrawing ),
931 mxChildren( new ShapeContainer( rDrawing ) )
935 GroupShape::~GroupShape()
939 void GroupShape::finalizeFragmentImport()
941 // basic shape processing
942 ShapeBase::finalizeFragmentImport();
943 // finalize all child shapes
944 mxChildren->finalizeFragmentImport();
947 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
949 return mxChildren->getShapeTypeById( rShapeId, true );
952 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
954 return mxChildren->getShapeById( rShapeId, true );
957 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
959 Reference< XShape > xGroupShape;
960 // check that this shape contains children and a valid coordinate system
961 ShapeParentAnchor aParentAnchor;
962 aParentAnchor.maShapeRect = rShapeRect;
963 aParentAnchor.maCoordSys = getCoordSystem();
964 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
966 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
967 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
968 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
969 if( !xChildShapes->hasElements() )
971 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
972 rxShapes->remove( xGroupShape );
973 xGroupShape.clear();
976 catch( Exception& )
979 // Make sure group shapes are inline as well, unless there is an explicit different style.
980 PropertySet aPropertySet(xGroupShape);
981 lcl_SetAnchorType(aPropertySet, maTypeModel);
982 return xGroupShape;
985 // ============================================================================
987 } // namespace vml
988 } // namespace oox
990 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */