Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <algorithm>
21 :
22 : #include "oox/vml/vmlshape.hxx"
23 :
24 : #include <com/sun/star/beans/PropertyValues.hpp>
25 : #include <com/sun/star/beans/XPropertySet.hpp>
26 : #include <com/sun/star/awt/XControlModel.hpp>
27 : #include <com/sun/star/drawing/PointSequenceSequence.hpp>
28 : #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
29 : #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
30 : #include <com/sun/star/drawing/XShapes.hpp>
31 : #include <com/sun/star/drawing/XControlShape.hpp>
32 : #include <com/sun/star/graphic/XGraphic.hpp>
33 : #include <com/sun/star/text/HoriOrientation.hpp>
34 : #include <com/sun/star/text/RelOrientation.hpp>
35 : #include <com/sun/star/text/SizeType.hpp>
36 : #include <com/sun/star/text/VertOrientation.hpp>
37 : #include <com/sun/star/text/XTextContent.hpp>
38 : #include <com/sun/star/text/XTextDocument.hpp>
39 : #include <com/sun/star/text/XTextFrame.hpp>
40 : #include <com/sun/star/text/TextContentAnchorType.hpp>
41 : #include <rtl/math.hxx>
42 : #include <rtl/ustrbuf.hxx>
43 : #include "oox/drawingml/shapepropertymap.hxx"
44 : #include "oox/helper/graphichelper.hxx"
45 : #include "oox/helper/propertyset.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"
51 : #include "oox/vml/vmltextbox.hxx"
52 : #include "oox/core/xmlfilterbase.hxx"
53 : #include "oox/helper/containerhelper.hxx"
54 :
55 : using ::com::sun::star::beans::XPropertySet;
56 : using ::com::sun::star::uno::Any;
57 :
58 : using namespace ::com::sun::star;
59 : using namespace ::com::sun::star::text;
60 :
61 : namespace oox {
62 : namespace vml {
63 :
64 : // ============================================================================
65 :
66 : using namespace ::com::sun::star;
67 : using namespace ::com::sun::star::drawing;
68 : using namespace ::com::sun::star::graphic;
69 : using namespace ::com::sun::star::uno;
70 : using namespace ::com::sun::star::io;
71 :
72 : using ::oox::core::XmlFilterBase;
73 : using ::rtl::OUString;
74 : using ::rtl::OUStringBuffer;
75 :
76 : // ============================================================================
77 :
78 : namespace {
79 :
80 : const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
81 : const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
82 :
83 : // ----------------------------------------------------------------------------
84 :
85 96 : awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
86 : {
87 96 : double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
88 96 : double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
89 96 : awt::Point aAbsPoint;
90 96 : aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
91 96 : aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
92 96 : return aAbsPoint;
93 : }
94 :
95 8 : awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
96 : {
97 8 : double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
98 8 : double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
99 8 : awt::Rectangle aAbsRect;
100 8 : aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
101 8 : aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
102 8 : aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
103 8 : aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
104 8 : return aAbsRect;
105 : }
106 :
107 : } // namespace
108 :
109 : // ============================================================================
110 :
111 43 : ShapeTypeModel::ShapeTypeModel():
112 : mbAutoHeight( sal_False ),
113 43 : mbVisible( sal_True )
114 : {
115 43 : }
116 :
117 11 : void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
118 : {
119 11 : moShapeType.assignIfUsed( rSource.moShapeType );
120 11 : moCoordPos.assignIfUsed( rSource.moCoordPos );
121 11 : moCoordSize.assignIfUsed( rSource.moCoordSize );
122 : /* The style properties position, left, top, width, height, margin-left,
123 : margin-top are not derived from shape template to shape. */
124 11 : maStrokeModel.assignUsed( rSource.maStrokeModel );
125 11 : maFillModel.assignUsed( rSource.maFillModel );
126 11 : moGraphicPath.assignIfUsed( rSource.moGraphicPath );
127 11 : moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
128 11 : }
129 :
130 : // ----------------------------------------------------------------------------
131 :
132 43 : ShapeType::ShapeType( Drawing& rDrawing ) :
133 43 : mrDrawing( rDrawing )
134 : {
135 43 : }
136 :
137 55 : ShapeType::~ShapeType()
138 : {
139 55 : }
140 :
141 15 : sal_Int32 ShapeType::getShapeType() const
142 : {
143 15 : return maTypeModel.moShapeType.get( 0 );
144 : }
145 :
146 22 : OUString ShapeType::getGraphicPath() const
147 : {
148 22 : return maTypeModel.moGraphicPath.get( OUString() );
149 : }
150 :
151 6 : awt::Rectangle ShapeType::getCoordSystem() const
152 : {
153 6 : Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
154 6 : Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
155 6 : return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
156 : }
157 :
158 29 : awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
159 : {
160 : return pParentAnchor ?
161 37 : lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
162 66 : getAbsRectangle();
163 : }
164 :
165 21 : awt::Rectangle ShapeType::getAbsRectangle() const
166 : {
167 21 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
168 :
169 21 : sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
170 21 : if ( nWidth == 0 )
171 2 : nWidth = 1;
172 :
173 21 : sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
174 21 : if ( nHeight == 0 )
175 1 : nHeight = 1;
176 :
177 21 : sal_Int32 nLeft = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true )
178 21 : + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true );
179 21 : if (nLeft == 0 && maTypeModel.maPosition == "absolute")
180 10 : nLeft = 1;
181 :
182 : return awt::Rectangle(
183 : nLeft,
184 21 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
185 21 : nWidth, nHeight );
186 : }
187 :
188 8 : awt::Rectangle ShapeType::getRelRectangle() const
189 : {
190 : return awt::Rectangle(
191 8 : maTypeModel.maLeft.toInt32(),
192 8 : maTypeModel.maTop.toInt32(),
193 8 : maTypeModel.maWidth.toInt32(),
194 32 : maTypeModel.maHeight.toInt32() );
195 : }
196 :
197 : // ============================================================================
198 :
199 2 : ClientData::ClientData() :
200 : mnObjType( XML_TOKEN_INVALID ),
201 : mnTextHAlign( XML_Left ),
202 : mnTextVAlign( XML_Top ),
203 : mnCol( -1 ),
204 : mnRow( -1 ),
205 : mnChecked( VML_CLIENTDATA_UNCHECKED ),
206 : mnDropStyle( XML_Combo ),
207 : mnDropLines( 1 ),
208 : mnVal( 0 ),
209 : mnMin( 0 ),
210 : mnMax( 0 ),
211 : mnInc( 0 ),
212 : mnPage( 0 ),
213 : mnSelType( XML_Single ),
214 : mnVTEdit( VML_CLIENTDATA_TEXT ),
215 : mbPrintObject( true ),
216 : mbVisible( false ),
217 : mbDde( false ),
218 : mbNo3D( false ),
219 : mbNo3D2( false ),
220 : mbMultiLine( false ),
221 : mbVScroll( false ),
222 2 : mbSecretEdit( false )
223 : {
224 2 : }
225 :
226 : // ----------------------------------------------------------------------------
227 :
228 31 : ShapeModel::ShapeModel()
229 : {
230 31 : }
231 :
232 31 : ShapeModel::~ShapeModel()
233 : {
234 31 : }
235 :
236 15 : TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
237 : {
238 15 : mxTextBox.reset( new TextBox(rModel) );
239 15 : return *mxTextBox;
240 : }
241 :
242 2 : ClientData& ShapeModel::createClientData()
243 : {
244 2 : mxClientData.reset( new ClientData );
245 2 : return *mxClientData;
246 : }
247 :
248 : // ----------------------------------------------------------------------------
249 :
250 31 : ShapeBase::ShapeBase( Drawing& rDrawing ) :
251 31 : ShapeType( rDrawing )
252 : {
253 31 : }
254 :
255 31 : void ShapeBase::finalizeFragmentImport()
256 : {
257 : // resolve shape template reference
258 31 : if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') )
259 15 : if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) )
260 11 : maTypeModel.assignUsed( pShapeType->getTypeModel() );
261 31 : }
262 :
263 22 : OUString ShapeBase::getShapeName() const
264 : {
265 22 : if( !maTypeModel.maShapeName.isEmpty() )
266 3 : return maTypeModel.maShapeName;
267 :
268 19 : OUString aBaseName = mrDrawing.getShapeBaseName( *this );
269 19 : if( !aBaseName.isEmpty() )
270 : {
271 1 : sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
272 1 : if( nShapeIdx > 0 )
273 1 : return OUStringBuffer( aBaseName ).append( sal_Unicode( ' ' ) ).append( nShapeIdx ).makeStringAndClear();
274 : }
275 :
276 18 : return OUString();
277 : }
278 :
279 6 : const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
280 : {
281 6 : return 0;
282 : }
283 :
284 0 : const ShapeBase* ShapeBase::getChildById( const OUString& ) const
285 : {
286 0 : return 0;
287 : }
288 :
289 31 : Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
290 : {
291 31 : Reference< XShape > xShape;
292 31 : if( mrDrawing.isShapeSupported( *this ) )
293 : {
294 : /* Calculate shape rectangle. Applications may do something special
295 : according to some imported shape client data (e.g. Excel cell anchor). */
296 30 : awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
297 :
298 : // convert the shape, if the calculated rectangle is not empty
299 30 : if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
300 : {
301 30 : xShape = implConvertAndInsert( rxShapes, aShapeRect );
302 30 : if( xShape.is() )
303 : {
304 : // set imported or generated shape name (not supported by form controls)
305 30 : PropertySet aShapeProp( xShape );
306 30 : if( aShapeProp.hasProperty( PROP_Name ) )
307 21 : aShapeProp.setProperty( PROP_Name, getShapeName() );
308 30 : Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
309 30 : if ( xControlShape.is() && !getTypeModel().mbVisible )
310 : {
311 0 : PropertySet aControlShapeProp( xControlShape->getControl() );
312 0 : aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( sal_False ) );
313 : }
314 : /* Notify the drawing that a new shape has been inserted. For
315 : convenience, pass the rectangle that contains position and
316 : size of the shape. */
317 30 : bool bGroupChild = pParentAnchor != 0;
318 30 : mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
319 : }
320 : }
321 : }
322 31 : return xShape;
323 : }
324 :
325 1 : void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const
326 : {
327 1 : if( rxShape.is() )
328 : {
329 : /* Calculate shape rectangle. Applications may do something special
330 : according to some imported shape client data (e.g. Excel cell anchor). */
331 1 : awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
332 :
333 : // convert the shape, if the calculated rectangle is not empty
334 1 : if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
335 : {
336 1 : rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
337 1 : rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
338 1 : convertShapeProperties( rxShape );
339 : }
340 : }
341 1 : }
342 :
343 : // protected ------------------------------------------------------------------
344 :
345 31 : awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
346 : {
347 : /* Calculate shape rectangle. Applications may do something special
348 : according to some imported shape client data (e.g. Excel cell anchor). */
349 31 : awt::Rectangle aShapeRect;
350 31 : const ClientData* pClientData = getClientData();
351 31 : if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
352 29 : aShapeRect = getRectangle( pParentAnchor );
353 31 : return aShapeRect;
354 : }
355 :
356 18 : void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
357 : {
358 18 : ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
359 18 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
360 18 : maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
361 18 : maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
362 :
363 : // TextFrames have FillColor, not BackColor
364 18 : uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
365 18 : if (xSInfo->supportsService("com.sun.star.text.TextFrame") && aPropMap.hasProperty(PROP_FillColor))
366 : {
367 4 : aPropMap.setProperty(PROP_BackColor, aPropMap[PROP_FillColor]);
368 4 : aPropMap.erase(PROP_FillColor);
369 : }
370 :
371 18 : PropertySet( rxShape ).setProperties( aPropMap );
372 18 : }
373 :
374 : // ============================================================================
375 :
376 26 : SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
377 : ShapeBase( rDrawing ),
378 26 : maService( rService )
379 : {
380 26 : }
381 :
382 29 : void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel)
383 : {
384 29 : if ( rTypeModel.maPositionHorizontal == "center" )
385 6 : rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
386 :
387 29 : if ( rTypeModel.maPositionHorizontalRelative == "page" )
388 3 : rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
389 :
390 29 : if ( rTypeModel.maPositionVertical == "center" )
391 2 : rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
392 :
393 29 : if ( rTypeModel.maPosition == "absolute" )
394 : {
395 26 : if (rTypeModel.moWrapAnchorX.get() == "page" && rTypeModel.moWrapAnchorY.get() == "page")
396 : {
397 : // I'm not sure if AT_PAGE is always correct here (not sure what the parent that
398 : // the spec talks about can be), but with Writer SwXDrawPage::add()
399 : // always in practice uses this because of pDoc->GetCurrentLayout() being NULL at this point.
400 2 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PAGE);
401 : }
402 : else
403 : {
404 : // Map to as-character by default, that fixes vertical position of some textframes.
405 24 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
406 : }
407 :
408 26 : if ( rTypeModel.maPositionVerticalRelative == "page" )
409 : {
410 2 : rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
411 : }
412 : else
413 : {
414 : // Vertical placement relative to margin, because parent style must not modify vertical position
415 24 : rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
416 : }
417 : }
418 3 : else if( rTypeModel.maPosition == "relative" )
419 : { // I'm not very sure this is correct either.
420 0 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
421 : }
422 : else // static (is the default) means anchored inline
423 : {
424 3 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
425 : }
426 29 : }
427 :
428 16 : Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
429 : {
430 16 : awt::Rectangle aShapeRect(rShapeRect);
431 16 : if (!maTypeModel.maFlip.isEmpty())
432 : {
433 1 : if (maTypeModel.maFlip.equalsAscii("x"))
434 : {
435 1 : aShapeRect.X += aShapeRect.Width;
436 1 : aShapeRect.Width *= -1;
437 : }
438 0 : else if (maTypeModel.maFlip.equalsAscii("y"))
439 : {
440 0 : aShapeRect.Y += aShapeRect.Height;
441 0 : aShapeRect.Height *= -1;
442 : }
443 : }
444 :
445 16 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
446 16 : convertShapeProperties( xShape );
447 :
448 16 : if ( maService.equalsAscii( "com.sun.star.text.TextFrame" ) )
449 : {
450 8 : PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
451 8 : PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
452 8 : if( getTextBox()->borderDistanceSet )
453 : {
454 8 : PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
455 8 : PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
456 8 : PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
457 8 : PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
458 : }
459 : }
460 : else
461 : {
462 : // FIXME Setting the relative width/heigh only for everything but text frames as
463 : // TextFrames already have relative widht/heigh feature... but currently not working
464 : // in the way we need.
465 :
466 : // Set the relative width / height if any
467 8 : if ( !maTypeModel.maWidthPercent.isEmpty( ) )
468 : {
469 : // Only page-relative width is supported ATM
470 3 : if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
471 : {
472 1 : sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
473 : // Only apply if nWidth != 0
474 1 : if ( nWidth )
475 1 : PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
476 : }
477 : }
478 8 : if ( !maTypeModel.maHeightPercent.isEmpty( ) )
479 : {
480 : // Only page-relative height is supported ATM
481 1 : if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
482 : {
483 1 : sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
484 : // Only apply if nHeight != 0
485 1 : if ( nHeight )
486 1 : PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
487 : }
488 : }
489 :
490 8 : if (getTextBox())
491 3 : getTextBox()->convert(xShape);
492 : }
493 :
494 : // Import Legacy Fragments (if any)
495 16 : if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
496 : {
497 0 : Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
498 0 : if( xInStrm.is() )
499 0 : PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
500 : }
501 :
502 16 : PropertySet aPropertySet(xShape);
503 16 : if (xShape.is() && !maTypeModel.maRotation.isEmpty())
504 : {
505 1 : aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(maTypeModel.maRotation.toInt32() * 100));
506 : // If rotation is used, simple setPosition() is not enough.
507 1 : aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny( aShapeRect.X ) );
508 1 : aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny( aShapeRect.Y ) );
509 : }
510 :
511 16 : lcl_SetAnchorType(aPropertySet, maTypeModel);
512 :
513 16 : return xShape;
514 : }
515 :
516 8 : Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString& rGraphicPath ) const
517 : {
518 8 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
519 8 : if( xShape.is() )
520 : {
521 8 : XmlFilterBase& rFilter = mrDrawing.getFilter();
522 8 : OUString aGraphicUrl = rFilter.getGraphicHelper().importEmbeddedGraphicObject( rGraphicPath );
523 8 : PropertySet aPropSet( xShape );
524 8 : if( !aGraphicUrl.isEmpty() )
525 : {
526 8 : aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl );
527 : }
528 8 : uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
529 : // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
530 8 : if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
531 : {
532 3 : aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
533 3 : aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
534 3 : aPropSet.setProperty(PROP_Opaque, sal_False);
535 : }
536 :
537 8 : lcl_SetAnchorType(aPropSet, maTypeModel);
538 : }
539 8 : return xShape;
540 : }
541 :
542 : // ============================================================================
543 :
544 8 : RectangleShape::RectangleShape( Drawing& rDrawing ) :
545 8 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) )
546 : {
547 8 : }
548 :
549 8 : Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
550 : {
551 8 : OUString aGraphicPath = getGraphicPath();
552 :
553 : // try to create a picture object
554 8 : if(!aGraphicPath.isEmpty())
555 1 : return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
556 :
557 : // default: try to create a rectangle shape
558 7 : Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
559 7 : rtl::OUString sArcsize = maTypeModel.maArcsize;
560 7 : if ( !sArcsize.isEmpty( ) )
561 : {
562 1 : sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
563 1 : sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
564 : // Get the smallest half-side
565 1 : double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
566 1 : sal_Int32 nRadius = 0;
567 1 : if ( cLastChar == 'f' )
568 1 : nRadius = size * nValue / 65536;
569 0 : else if ( cLastChar == '%' )
570 0 : nRadius = size * nValue / 100;
571 1 : PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
572 : }
573 7 : return xShape;
574 : }
575 :
576 : // ============================================================================
577 :
578 1 : EllipseShape::EllipseShape( Drawing& rDrawing ) :
579 1 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) )
580 : {
581 1 : }
582 :
583 : // ============================================================================
584 :
585 0 : PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
586 0 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) )
587 : {
588 0 : }
589 :
590 0 : Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
591 : {
592 0 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
593 : // polygon path
594 0 : awt::Rectangle aCoordSys = getCoordSystem();
595 0 : if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
596 : {
597 0 : ::std::vector< awt::Point > aAbsPoints;
598 0 : for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt )
599 0 : aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) );
600 0 : PointSequenceSequence aPointSeq( 1 );
601 0 : aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
602 0 : PropertySet aPropSet( xShape );
603 0 : aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
604 : }
605 0 : return xShape;
606 : }
607 :
608 1 : LineShape::LineShape(Drawing& rDrawing)
609 1 : : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
610 : {
611 1 : }
612 :
613 1 : Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
614 : {
615 1 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
616 1 : awt::Rectangle aShapeRect(rShapeRect);
617 1 : sal_Int32 nIndex = 0;
618 :
619 1 : aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
620 1 : aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
621 1 : nIndex = 0;
622 1 : aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
623 1 : aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
624 :
625 1 : return SimpleShape::implConvertAndInsert(rxShapes, aShapeRect);
626 : }
627 :
628 : // ============================================================================
629 :
630 1 : BezierShape::BezierShape(Drawing& rDrawing)
631 1 : : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
632 : {
633 1 : }
634 :
635 1 : Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
636 : {
637 1 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
638 1 : awt::Rectangle aCoordSys = getCoordSystem();
639 :
640 1 : if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
641 : {
642 1 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
643 :
644 : // Bezier paths may consist of one or more sub-paths
645 : typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
646 : typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
647 1 : SubPathList aCoordLists;
648 1 : FlagsList aFlagLists;
649 1 : sal_Int32 nIndex = 0;
650 :
651 : // Curve defined by to, from, control1 and control2 attributes
652 1 : if ( maShapeModel.maVmlPath.isEmpty() )
653 : {
654 0 : aCoordLists.push_back( ::std::vector< awt::Point >() );
655 0 : aFlagLists.push_back( ::std::vector< PolygonFlags >() );
656 :
657 : // Start point
658 0 : aCoordLists[ 0 ].push_back(
659 0 : awt::Point(ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
660 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) ) );
661 : // Control point 1
662 0 : aCoordLists[ 0 ].push_back(
663 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
664 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) ) );
665 : // Control point 2
666 0 : aCoordLists[ 0 ].push_back(
667 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
668 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) ) );
669 : // End point
670 0 : aCoordLists[ 0 ].push_back(
671 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
672 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) ) );
673 :
674 : // First and last points are normals, points 2 and 4 are controls
675 0 : aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
676 0 : aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
677 0 : aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
678 : }
679 : // Curve defined by path attribute
680 : else
681 : {
682 : // Parse VML path string and convert to absolute coordinates
683 1 : ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
684 :
685 4 : for ( SubPathList::iterator aListIt = aCoordLists.begin(); aListIt != aCoordLists.end(); ++aListIt )
686 99 : for ( ::std::vector< awt::Point >::iterator aPointIt = (*aListIt).begin(); aPointIt != (*aListIt).end(); ++aPointIt)
687 : {
688 96 : (*aPointIt) = lclGetAbsPoint( (*aPointIt), rShapeRect, aCoordSys );
689 : }
690 : }
691 :
692 1 : PolyPolygonBezierCoords aBezierCoords;
693 1 : aBezierCoords.Coordinates.realloc( aCoordLists.size() );
694 4 : for ( unsigned int i = 0; i < aCoordLists.size(); i++ )
695 3 : aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
696 :
697 1 : aBezierCoords.Flags.realloc( aFlagLists.size() );
698 4 : for ( unsigned int i = 0; i < aFlagLists.size(); i++ )
699 3 : aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
700 :
701 1 : PropertySet aPropSet( xShape );
702 1 : aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
703 : }
704 :
705 : // Hacky way of ensuring the shape is correctly sized/positioned
706 1 : xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
707 1 : xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
708 1 : return xShape;
709 : }
710 :
711 : // ============================================================================
712 :
713 15 : CustomShape::CustomShape( Drawing& rDrawing ) :
714 15 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) )
715 : {
716 15 : }
717 :
718 6 : Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
719 : {
720 : // try to create a custom shape
721 6 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
722 6 : if( xShape.is() ) try
723 : {
724 : // create the custom shape geometry
725 6 : Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
726 1 : xDefaulter->createCustomShapeDefaults( OUString::valueOf( getShapeType() ) );
727 : // convert common properties
728 1 : convertShapeProperties( xShape );
729 : }
730 5 : catch( Exception& )
731 : {
732 : }
733 6 : return xShape;
734 : }
735 :
736 : // ============================================================================
737 :
738 15 : ComplexShape::ComplexShape( Drawing& rDrawing ) :
739 15 : CustomShape( rDrawing )
740 : {
741 15 : }
742 :
743 14 : Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
744 : {
745 14 : XmlFilterBase& rFilter = mrDrawing.getFilter();
746 14 : sal_Int32 nShapeType = getShapeType();
747 14 : OUString aGraphicPath = getGraphicPath();
748 :
749 : // try to find registered OLE object info
750 14 : if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
751 : {
752 : OSL_ENSURE( nShapeType == VML_SHAPETYPE_PICTUREFRAME, "ComplexShape::implConvertAndInsert - unexpected shape type" );
753 :
754 : // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
755 0 : if( pOleObjectInfo->mbDmlShape )
756 0 : return Reference< XShape >();
757 :
758 0 : PropertyMap aOleProps;
759 0 : awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
760 0 : if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
761 : {
762 0 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rxShapes, rShapeRect );
763 0 : if( xShape.is() )
764 : {
765 : // set the replacement graphic
766 0 : if( !aGraphicPath.isEmpty() )
767 : {
768 0 : Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath );
769 0 : if( xGraphic.is() )
770 0 : aOleProps[ PROP_Graphic ] <<= xGraphic;
771 : }
772 :
773 0 : PropertySet aPropSet( xShape );
774 0 : aPropSet.setProperties( aOleProps );
775 :
776 0 : return xShape;
777 0 : }
778 0 : }
779 : }
780 :
781 : // try to find registered form control info
782 14 : const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
783 14 : if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
784 : {
785 : OSL_ENSURE( nShapeType == VML_SHAPETYPE_HOSTCONTROL, "ComplexShape::implConvertAndInsert - unexpected shape type" );
786 0 : OUString aShapeName = getShapeName();
787 0 : if( !aShapeName.isEmpty() )
788 : {
789 : OSL_ENSURE( aShapeName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" );
790 : // load the control properties from fragment
791 0 : ::oox::ole::EmbeddedControl aControl( aShapeName );
792 0 : if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
793 : {
794 : // create and return the control shape (including control model)
795 0 : sal_Int32 nCtrlIndex = -1;
796 0 : Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
797 : // on error, proceed and try to create picture from replacement image
798 0 : if( xShape.is() )
799 0 : return xShape;
800 0 : }
801 0 : }
802 : }
803 :
804 : // host application wants to create the shape (do not try failed OLE controls again)
805 14 : if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
806 : {
807 : OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
808 1 : Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
809 1 : if( xShape.is() )
810 1 : return xShape;
811 : }
812 :
813 : // try to create a picture object
814 13 : if( !aGraphicPath.isEmpty() )
815 7 : return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
816 :
817 : // default: try to create a custom shape
818 6 : return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
819 : }
820 :
821 : // ============================================================================
822 :
823 5 : GroupShape::GroupShape( Drawing& rDrawing ) :
824 : ShapeBase( rDrawing ),
825 5 : mxChildren( new ShapeContainer( rDrawing ) )
826 : {
827 5 : }
828 :
829 10 : GroupShape::~GroupShape()
830 : {
831 10 : }
832 :
833 5 : void GroupShape::finalizeFragmentImport()
834 : {
835 : // basic shape processing
836 5 : ShapeBase::finalizeFragmentImport();
837 : // finalize all child shapes
838 5 : mxChildren->finalizeFragmentImport();
839 5 : }
840 :
841 7 : const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
842 : {
843 7 : return mxChildren->getShapeTypeById( rShapeId, true );
844 : }
845 :
846 0 : const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
847 : {
848 0 : return mxChildren->getShapeById( rShapeId, true );
849 : }
850 :
851 5 : Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
852 : {
853 5 : Reference< XShape > xGroupShape;
854 : // check that this shape contains children and a valid coordinate system
855 5 : ShapeParentAnchor aParentAnchor;
856 5 : aParentAnchor.maShapeRect = rShapeRect;
857 5 : aParentAnchor.maCoordSys = getCoordSystem();
858 5 : if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
859 : {
860 5 : xGroupShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rxShapes, rShapeRect );
861 5 : Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
862 5 : mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
863 : // no child shape has been created - delete the group shape
864 5 : if( !xChildShapes->hasElements() )
865 : {
866 0 : rxShapes->remove( xGroupShape );
867 0 : xGroupShape.clear();
868 5 : }
869 : }
870 0 : catch( Exception& )
871 : {
872 : }
873 : // Make sure group shapes are inline as well, unless there is an explicit different style.
874 5 : PropertySet aPropertySet(xGroupShape);
875 5 : lcl_SetAnchorType(aPropertySet, maTypeModel);
876 5 : return xGroupShape;
877 : }
878 :
879 : // ============================================================================
880 :
881 : } // namespace vml
882 51 : } // namespace oox
883 :
884 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|