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 192 : awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
86 : {
87 192 : double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
88 192 : double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
89 192 : awt::Point aAbsPoint;
90 192 : aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
91 192 : aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
92 192 : 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 78 : ShapeTypeModel::ShapeTypeModel():
112 : mbAutoHeight( sal_False ),
113 78 : mbVisible( sal_True )
114 : {
115 78 : }
116 :
117 22 : void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
118 : {
119 22 : moShapeType.assignIfUsed( rSource.moShapeType );
120 22 : moCoordPos.assignIfUsed( rSource.moCoordPos );
121 22 : 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 22 : maStrokeModel.assignUsed( rSource.maStrokeModel );
125 22 : maFillModel.assignUsed( rSource.maFillModel );
126 22 : moGraphicPath.assignIfUsed( rSource.moGraphicPath );
127 22 : moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
128 22 : }
129 :
130 : // ----------------------------------------------------------------------------
131 :
132 78 : ShapeType::ShapeType( Drawing& rDrawing ) :
133 78 : mrDrawing( rDrawing )
134 : {
135 78 : }
136 :
137 102 : ShapeType::~ShapeType()
138 : {
139 102 : }
140 :
141 28 : sal_Int32 ShapeType::getShapeType() const
142 : {
143 28 : return maTypeModel.moShapeType.get( 0 );
144 : }
145 :
146 42 : OUString ShapeType::getGraphicPath() const
147 : {
148 42 : 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 50 : awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
159 : {
160 : return pParentAnchor ?
161 58 : lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
162 108 : getAbsRectangle();
163 : }
164 :
165 42 : awt::Rectangle ShapeType::getAbsRectangle() const
166 : {
167 42 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
168 :
169 42 : sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
170 42 : if ( nWidth == 0 )
171 4 : nWidth = 1;
172 :
173 42 : sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
174 42 : if ( nHeight == 0 )
175 2 : nHeight = 1;
176 :
177 42 : sal_Int32 nLeft = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true )
178 42 : + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true );
179 42 : if (nLeft == 0 && maTypeModel.maPosition == "absolute")
180 18 : nLeft = 1;
181 :
182 : return awt::Rectangle(
183 : nLeft,
184 42 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
185 42 : 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 4 : 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 4 : mbSecretEdit( false )
223 : {
224 4 : }
225 :
226 : // ----------------------------------------------------------------------------
227 :
228 54 : ShapeModel::ShapeModel()
229 : {
230 54 : }
231 :
232 54 : ShapeModel::~ShapeModel()
233 : {
234 54 : }
235 :
236 26 : TextBox& ShapeModel::createTextBox()
237 : {
238 26 : mxTextBox.reset( new TextBox );
239 26 : return *mxTextBox;
240 : }
241 :
242 4 : ClientData& ShapeModel::createClientData()
243 : {
244 4 : mxClientData.reset( new ClientData );
245 4 : return *mxClientData;
246 : }
247 :
248 : // ----------------------------------------------------------------------------
249 :
250 54 : ShapeBase::ShapeBase( Drawing& rDrawing ) :
251 54 : ShapeType( rDrawing )
252 : {
253 54 : }
254 :
255 58 : void ShapeBase::finalizeFragmentImport()
256 : {
257 : // resolve shape template reference
258 58 : if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') )
259 30 : if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) )
260 22 : maTypeModel.assignUsed( pShapeType->getTypeModel() );
261 58 : }
262 :
263 24 : OUString ShapeBase::getShapeName() const
264 : {
265 24 : if( !maTypeModel.maShapeName.isEmpty() )
266 6 : return maTypeModel.maShapeName;
267 :
268 18 : OUString aBaseName = mrDrawing.getShapeBaseName( *this );
269 18 : if( !aBaseName.isEmpty() )
270 : {
271 2 : sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
272 2 : if( nShapeIdx > 0 )
273 2 : return OUStringBuffer( aBaseName ).append( sal_Unicode( ' ' ) ).append( nShapeIdx ).makeStringAndClear();
274 : }
275 :
276 16 : return OUString();
277 : }
278 :
279 12 : const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
280 : {
281 12 : return 0;
282 : }
283 :
284 0 : const ShapeBase* ShapeBase::getChildById( const OUString& ) const
285 : {
286 0 : return 0;
287 : }
288 :
289 54 : Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
290 : {
291 54 : Reference< XShape > xShape;
292 54 : 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 52 : awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
297 :
298 : // convert the shape, if the calculated rectangle is not empty
299 52 : if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
300 : {
301 52 : xShape = implConvertAndInsert( rxShapes, aShapeRect );
302 52 : if( xShape.is() )
303 : {
304 : // set imported or generated shape name (not supported by form controls)
305 48 : PropertySet aShapeProp( xShape );
306 48 : if( aShapeProp.hasProperty( PROP_Name ) )
307 22 : aShapeProp.setProperty( PROP_Name, getShapeName() );
308 48 : Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
309 48 : 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 48 : bool bGroupChild = pParentAnchor != 0;
318 48 : mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
319 : }
320 : }
321 : }
322 54 : return xShape;
323 : }
324 :
325 2 : void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const
326 : {
327 2 : 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 2 : awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
332 :
333 : // convert the shape, if the calculated rectangle is not empty
334 2 : if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
335 : {
336 2 : rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
337 2 : rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
338 2 : convertShapeProperties( rxShape );
339 : }
340 : }
341 2 : }
342 :
343 : // protected ------------------------------------------------------------------
344 :
345 54 : 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 54 : awt::Rectangle aShapeRect;
350 54 : const ClientData* pClientData = getClientData();
351 54 : if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
352 50 : aShapeRect = getRectangle( pParentAnchor );
353 54 : return aShapeRect;
354 : }
355 :
356 38 : void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
357 : {
358 38 : ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
359 38 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
360 38 : maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
361 38 : maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
362 :
363 : // TextFrames have FillColor, not BackColor
364 38 : uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
365 38 : if (xSInfo->supportsService("com.sun.star.text.TextFrame") && aPropMap.hasProperty(PROP_FillColor))
366 : {
367 10 : aPropMap.setProperty(PROP_BackColor, aPropMap[PROP_FillColor]);
368 10 : aPropMap.erase(PROP_FillColor);
369 : }
370 :
371 38 : PropertySet( rxShape ).setProperties( aPropMap );
372 38 : }
373 :
374 : // ============================================================================
375 :
376 50 : SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
377 : ShapeBase( rDrawing ),
378 50 : maService( rService )
379 : {
380 50 : }
381 :
382 46 : void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel)
383 : {
384 46 : if ( rTypeModel.maPositionHorizontal == "center" )
385 10 : rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
386 :
387 46 : if ( rTypeModel.maPositionHorizontalRelative == "page" )
388 4 : rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
389 :
390 46 : if ( rTypeModel.maPositionVertical == "center" )
391 2 : rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
392 :
393 46 : if ( rTypeModel.maPosition == "absolute" )
394 : {
395 40 : 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 4 : 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 36 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
406 : }
407 :
408 40 : if ( rTypeModel.maPositionVerticalRelative == "page" )
409 : {
410 4 : 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 36 : rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
416 : }
417 : }
418 6 : 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 6 : rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
425 : }
426 46 : }
427 :
428 34 : Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
429 : {
430 34 : awt::Rectangle aShapeRect(rShapeRect);
431 34 : if (!maTypeModel.maFlip.isEmpty())
432 : {
433 2 : if (maTypeModel.maFlip.equalsAscii("x"))
434 : {
435 2 : aShapeRect.X += aShapeRect.Width;
436 2 : 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 34 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
446 34 : convertShapeProperties( xShape );
447 :
448 34 : if ( maService.equalsAscii( "com.sun.star.text.TextFrame" ) )
449 : {
450 24 : PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
451 24 : PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
452 24 : if( getTextBox()->borderDistanceSet )
453 : {
454 24 : PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
455 24 : PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
456 24 : PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
457 24 : 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 10 : if ( !maTypeModel.maWidthPercent.isEmpty( ) )
468 : {
469 : // Only page-relative width is supported ATM
470 2 : if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
471 : {
472 2 : sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
473 : // Only apply if nWidth != 0
474 2 : if ( nWidth )
475 2 : PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
476 : }
477 : }
478 10 : if ( !maTypeModel.maHeightPercent.isEmpty( ) )
479 : {
480 : // Only page-relative height is supported ATM
481 2 : if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
482 : {
483 2 : sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
484 : // Only apply if nHeight != 0
485 2 : if ( nHeight )
486 2 : PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
487 : }
488 : }
489 : }
490 :
491 : // Import Legacy Fragments (if any)
492 34 : if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
493 : {
494 0 : Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
495 0 : if( xInStrm.is() )
496 0 : PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
497 : }
498 :
499 34 : PropertySet aPropertySet(xShape);
500 34 : if (xShape.is() && !maTypeModel.maRotation.isEmpty())
501 : {
502 2 : aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(maTypeModel.maRotation.toInt32() * 100));
503 : // If rotation is used, simple setPosition() is not enough.
504 2 : aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny( aShapeRect.X ) );
505 2 : aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny( aShapeRect.Y ) );
506 : }
507 :
508 34 : lcl_SetAnchorType(aPropertySet, maTypeModel);
509 :
510 34 : return xShape;
511 : }
512 :
513 12 : Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString& rGraphicPath ) const
514 : {
515 12 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
516 12 : if( xShape.is() )
517 : {
518 12 : XmlFilterBase& rFilter = mrDrawing.getFilter();
519 12 : OUString aGraphicUrl = rFilter.getGraphicHelper().importEmbeddedGraphicObject( rGraphicPath );
520 12 : PropertySet aPropSet( xShape );
521 12 : if( !aGraphicUrl.isEmpty() )
522 : {
523 12 : aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl );
524 : }
525 : // If the shape has an absolute position, set the properties accordingly.
526 12 : if ( maTypeModel.maPosition == "absolute" )
527 : {
528 6 : aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
529 6 : aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
530 6 : aPropSet.setProperty(PROP_Opaque, sal_False);
531 : }
532 :
533 12 : lcl_SetAnchorType(aPropSet, maTypeModel);
534 : }
535 12 : return xShape;
536 : }
537 :
538 : // ============================================================================
539 :
540 16 : RectangleShape::RectangleShape( Drawing& rDrawing ) :
541 16 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) )
542 : {
543 16 : }
544 :
545 16 : Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
546 : {
547 16 : OUString aGraphicPath = getGraphicPath();
548 :
549 : // try to create a picture object
550 16 : if(!aGraphicPath.isEmpty())
551 2 : return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
552 :
553 : // default: try to create a rectangle shape
554 14 : Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
555 14 : rtl::OUString sArcsize = maTypeModel.maArcsize;
556 14 : if ( !sArcsize.isEmpty( ) )
557 : {
558 2 : sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
559 2 : sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
560 : // Get the smallest half-side
561 2 : double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
562 2 : sal_Int32 nRadius = 0;
563 2 : if ( cLastChar == 'f' )
564 2 : nRadius = size * nValue / 65536;
565 0 : else if ( cLastChar == '%' )
566 0 : nRadius = size * nValue / 100;
567 2 : PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
568 : }
569 14 : return xShape;
570 : }
571 :
572 : // ============================================================================
573 :
574 2 : EllipseShape::EllipseShape( Drawing& rDrawing ) :
575 2 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) )
576 : {
577 2 : }
578 :
579 : // ============================================================================
580 :
581 0 : PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
582 0 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) )
583 : {
584 0 : }
585 :
586 0 : Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
587 : {
588 0 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
589 : // polygon path
590 0 : awt::Rectangle aCoordSys = getCoordSystem();
591 0 : if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
592 : {
593 0 : ::std::vector< awt::Point > aAbsPoints;
594 0 : for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt )
595 0 : aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) );
596 0 : PointSequenceSequence aPointSeq( 1 );
597 0 : aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
598 0 : PropertySet aPropSet( xShape );
599 0 : aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
600 : }
601 0 : return xShape;
602 : }
603 :
604 2 : LineShape::LineShape(Drawing& rDrawing)
605 2 : : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
606 : {
607 2 : }
608 :
609 2 : Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
610 : {
611 2 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
612 2 : awt::Rectangle aShapeRect(rShapeRect);
613 2 : sal_Int32 nIndex = 0;
614 :
615 2 : aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
616 2 : aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
617 2 : nIndex = 0;
618 2 : aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
619 2 : aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
620 :
621 2 : return SimpleShape::implConvertAndInsert(rxShapes, aShapeRect);
622 : }
623 :
624 : // ============================================================================
625 :
626 2 : BezierShape::BezierShape(Drawing& rDrawing)
627 2 : : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
628 : {
629 2 : }
630 :
631 2 : Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
632 : {
633 2 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
634 2 : awt::Rectangle aCoordSys = getCoordSystem();
635 :
636 2 : if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
637 : {
638 2 : const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
639 :
640 : // Bezier paths may consist of one or more sub-paths
641 : typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
642 : typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
643 2 : SubPathList aCoordLists;
644 2 : FlagsList aFlagLists;
645 2 : sal_Int32 nIndex = 0;
646 :
647 : // Curve defined by to, from, control1 and control2 attributes
648 2 : if ( maShapeModel.maVmlPath.isEmpty() )
649 : {
650 0 : aCoordLists.push_back( ::std::vector< awt::Point >() );
651 0 : aFlagLists.push_back( ::std::vector< PolygonFlags >() );
652 :
653 : // Start point
654 0 : aCoordLists[ 0 ].push_back(
655 0 : awt::Point(ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
656 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) ) );
657 : // Control point 1
658 0 : aCoordLists[ 0 ].push_back(
659 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
660 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) ) );
661 : // Control point 2
662 0 : aCoordLists[ 0 ].push_back(
663 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
664 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) ) );
665 : // End point
666 0 : aCoordLists[ 0 ].push_back(
667 0 : awt::Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
668 0 : ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) ) );
669 :
670 : // First and last points are normals, points 2 and 4 are controls
671 0 : aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
672 0 : aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
673 0 : aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
674 : }
675 : // Curve defined by path attribute
676 : else
677 : {
678 : // Parse VML path string and convert to absolute coordinates
679 2 : ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
680 :
681 8 : for ( SubPathList::iterator aListIt = aCoordLists.begin(); aListIt != aCoordLists.end(); ++aListIt )
682 198 : for ( ::std::vector< awt::Point >::iterator aPointIt = (*aListIt).begin(); aPointIt != (*aListIt).end(); ++aPointIt)
683 : {
684 192 : (*aPointIt) = lclGetAbsPoint( (*aPointIt), rShapeRect, aCoordSys );
685 : }
686 : }
687 :
688 2 : PolyPolygonBezierCoords aBezierCoords;
689 2 : aBezierCoords.Coordinates.realloc( aCoordLists.size() );
690 8 : for ( unsigned int i = 0; i < aCoordLists.size(); i++ )
691 6 : aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
692 :
693 2 : aBezierCoords.Flags.realloc( aFlagLists.size() );
694 8 : for ( unsigned int i = 0; i < aFlagLists.size(); i++ )
695 6 : aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
696 :
697 2 : PropertySet aPropSet( xShape );
698 2 : aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
699 : }
700 :
701 : // Hacky way of ensuring the shape is correctly sized/positioned
702 2 : xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
703 2 : xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
704 2 : return xShape;
705 : }
706 :
707 : // ============================================================================
708 :
709 28 : CustomShape::CustomShape( Drawing& rDrawing ) :
710 28 : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) )
711 : {
712 28 : }
713 :
714 14 : Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
715 : {
716 : // try to create a custom shape
717 14 : Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
718 14 : if( xShape.is() ) try
719 : {
720 : // create the custom shape geometry
721 14 : Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
722 2 : xDefaulter->createCustomShapeDefaults( OUString::valueOf( getShapeType() ) );
723 : // convert common properties
724 2 : convertShapeProperties( xShape );
725 : }
726 12 : catch( Exception& )
727 : {
728 : }
729 14 : return xShape;
730 : }
731 :
732 : // ============================================================================
733 :
734 28 : ComplexShape::ComplexShape( Drawing& rDrawing ) :
735 28 : CustomShape( rDrawing )
736 : {
737 28 : }
738 :
739 26 : Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
740 : {
741 26 : XmlFilterBase& rFilter = mrDrawing.getFilter();
742 26 : sal_Int32 nShapeType = getShapeType();
743 26 : OUString aGraphicPath = getGraphicPath();
744 :
745 : // try to find registered OLE object info
746 26 : if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
747 : {
748 : OSL_ENSURE( nShapeType == VML_SHAPETYPE_PICTUREFRAME, "ComplexShape::implConvertAndInsert - unexpected shape type" );
749 :
750 : // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
751 0 : if( pOleObjectInfo->mbDmlShape )
752 0 : return Reference< XShape >();
753 :
754 0 : PropertyMap aOleProps;
755 0 : awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
756 0 : if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
757 : {
758 0 : Reference< XShape > xShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rxShapes, rShapeRect );
759 0 : if( xShape.is() )
760 : {
761 : // set the replacement graphic
762 0 : if( !aGraphicPath.isEmpty() )
763 : {
764 0 : Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath );
765 0 : if( xGraphic.is() )
766 0 : aOleProps[ PROP_Graphic ] <<= xGraphic;
767 : }
768 :
769 0 : PropertySet aPropSet( xShape );
770 0 : aPropSet.setProperties( aOleProps );
771 :
772 0 : return xShape;
773 0 : }
774 0 : }
775 : }
776 :
777 : // try to find registered form control info
778 26 : const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
779 26 : if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
780 : {
781 : OSL_ENSURE( nShapeType == VML_SHAPETYPE_HOSTCONTROL, "ComplexShape::implConvertAndInsert - unexpected shape type" );
782 0 : OUString aShapeName = getShapeName();
783 0 : if( !aShapeName.isEmpty() )
784 : {
785 : OSL_ENSURE( aShapeName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" );
786 : // load the control properties from fragment
787 0 : ::oox::ole::EmbeddedControl aControl( aShapeName );
788 0 : if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
789 : {
790 : // create and return the control shape (including control model)
791 0 : sal_Int32 nCtrlIndex = -1;
792 0 : Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
793 : // on error, proceed and try to create picture from replacement image
794 0 : if( xShape.is() )
795 0 : return xShape;
796 0 : }
797 0 : }
798 : }
799 :
800 : // host application wants to create the shape (do not try failed OLE controls again)
801 26 : if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
802 : {
803 : OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
804 2 : Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
805 2 : if( xShape.is() )
806 2 : return xShape;
807 : }
808 :
809 : // try to create a picture object
810 24 : if( !aGraphicPath.isEmpty() )
811 10 : return SimpleShape::createPictureObject(rxShapes, rShapeRect, aGraphicPath);
812 :
813 : // default: try to create a custom shape
814 14 : return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
815 : }
816 :
817 : // ============================================================================
818 :
819 4 : GroupShape::GroupShape( Drawing& rDrawing ) :
820 : ShapeBase( rDrawing ),
821 4 : mxChildren( new ShapeContainer( rDrawing ) )
822 : {
823 4 : }
824 :
825 8 : GroupShape::~GroupShape()
826 : {
827 8 : }
828 :
829 6 : void GroupShape::finalizeFragmentImport()
830 : {
831 : // basic shape processing
832 6 : ShapeBase::finalizeFragmentImport();
833 : // finalize all child shapes
834 6 : mxChildren->finalizeFragmentImport();
835 6 : }
836 :
837 6 : const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
838 : {
839 6 : return mxChildren->getShapeTypeById( rShapeId, true );
840 : }
841 :
842 0 : const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
843 : {
844 0 : return mxChildren->getShapeById( rShapeId, true );
845 : }
846 :
847 4 : Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
848 : {
849 4 : Reference< XShape > xGroupShape;
850 : // check that this shape contains children and a valid coordinate system
851 4 : ShapeParentAnchor aParentAnchor;
852 4 : aParentAnchor.maShapeRect = rShapeRect;
853 4 : aParentAnchor.maCoordSys = getCoordSystem();
854 4 : if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
855 : {
856 4 : xGroupShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rxShapes, rShapeRect );
857 4 : Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
858 4 : mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
859 : // no child shape has been created - delete the group shape
860 4 : if( !xChildShapes->hasElements() )
861 : {
862 4 : rxShapes->remove( xGroupShape );
863 4 : xGroupShape.clear();
864 4 : }
865 : }
866 0 : catch( Exception& )
867 : {
868 : }
869 4 : return xGroupShape;
870 : }
871 :
872 : // ============================================================================
873 :
874 : } // namespace vml
875 174 : } // namespace oox
876 :
877 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|