1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "vbasheetobjects.hxx"
22 #include <rtl/math.hxx>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/container/XIndexContainer.hpp>
25 #include <com/sun/star/container/XNamed.hpp>
26 #include <com/sun/star/drawing/XControlShape.hpp>
27 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
28 #include <com/sun/star/drawing/XShapes.hpp>
29 #include <com/sun/star/form/FormComponentType.hpp>
30 #include <com/sun/star/form/XForm.hpp>
31 #include <com/sun/star/form/XFormComponent.hpp>
32 #include <com/sun/star/form/XFormsSupplier.hpp>
33 #include "vbasheetobject.hxx"
35 using namespace ::com::sun::star
;
36 using namespace ::ooo::vba
;
40 template< typename Type
>
41 inline bool lclGetProperty( Type
& orValue
, const uno::Reference
< beans::XPropertySet
>& rxPropSet
, const OUString
& rPropName
)
45 return rxPropSet
->getPropertyValue( rPropName
) >>= orValue
;
47 catch( uno::Exception
& )
53 /** Rounds the passed value to a multiple of 0.75 and converts it to 1/100 mm. */
54 inline double lclPointsToHmm( const uno::Any
& rPoints
) throw (uno::RuntimeException
)
56 return PointsToHmm( ::rtl::math::approxFloor( rPoints
.get
< double >() / 0.75 ) * 0.75 );
61 // Base implementations
63 /** Container for a specific type of drawing object in a spreadsheet.
65 Derived classes provide all required functionality specific to the type of
66 shapes covered by the container.
68 class ScVbaObjectContainer
: public ::cppu::WeakImplHelper1
< container::XIndexAccess
>
71 explicit ScVbaObjectContainer(
72 const uno::Reference
< XHelperInterface
>& rxParent
,
73 const uno::Reference
< uno::XComponentContext
>& rxContext
,
74 const uno::Reference
< frame::XModel
>& rxModel
,
75 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
76 const uno::Type
& rVbaType
) throw (uno::RuntimeException
);
78 /** Returns the VBA helper interface of the VBA collection object. */
79 inline const uno::Reference
< XHelperInterface
>& getParent() const { return mxParent
; }
80 /** Returns the component context of the VBA collection object. */
81 inline const uno::Reference
< uno::XComponentContext
>& getContext() const { return mxContext
; }
82 /** Returns the VBA type information of the objects in this container. */
83 inline const uno::Type
& getVbaType() const { return maVbaType
; }
85 /** Collects all shapes supported by this instance and inserts them into
86 the internal shape vector. */
87 void collectShapes() throw (uno::RuntimeException
);
88 /** Creates and returns a new UNO shape. */
89 uno::Reference
< drawing::XShape
> createShape( const awt::Point
& rPos
, const awt::Size
& rSize
) throw (uno::RuntimeException
);
90 /** Inserts the passed shape into the draw page and into this container, and returns its index in the draw page. */
91 sal_Int32
insertShape( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
);
92 /** Creates and returns a new VBA implementation object for the passed shape. */
93 ::rtl::Reference
< ScVbaSheetObjectBase
> createVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
);
94 /** Creates and returns a new VBA implementation object for the passed shape in an Any. */
95 uno::Any
createCollectionObject( const uno::Any
& rSource
) throw (uno::RuntimeException
);
96 /** Returns the VBA implementation object with the specified name. */
97 uno::Any
getItemByStringIndex( const OUString
& rIndex
) throw (uno::RuntimeException
);
100 virtual sal_Int32 SAL_CALL
getCount() throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
101 virtual uno::Any SAL_CALL
getByIndex( sal_Int32 nIndex
) throw (lang::IndexOutOfBoundsException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
104 virtual uno::Type SAL_CALL
getElementType() throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
105 virtual sal_Bool SAL_CALL
hasElements() throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
108 /** Derived classes return true, if the passed shape is supported by the instance. */
109 virtual bool implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const = 0;
110 /** Derived classes create and return a new VBA implementation object for the passed shape. */
111 virtual ScVbaSheetObjectBase
* implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
) = 0;
112 /** Derived classes return the service name of the UNO shape. */
113 virtual OUString
implGetShapeServiceName() const = 0;
115 /** Returns the shape name via 'Name' property of the UNO shape. May be overwritten. */
116 virtual OUString
implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const throw (uno::RuntimeException
);
117 /** Is called when a new UNO shape has been created but not yet inserted into the drawing page. */
118 virtual void implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
);
121 uno::Reference
< XHelperInterface
> mxParent
;
122 uno::Reference
< uno::XComponentContext
> mxContext
;
123 uno::Reference
< frame::XModel
> mxModel
;
124 uno::Reference
< lang::XMultiServiceFactory
> mxFactory
;
125 uno::Reference
< drawing::XShapes
> mxShapes
;
128 typedef ::std::vector
< uno::Reference
< drawing::XShape
> > ShapeVector
;
129 const uno::Type maVbaType
;
130 ShapeVector maShapes
;
133 ScVbaObjectContainer::ScVbaObjectContainer(
134 const uno::Reference
< XHelperInterface
>& rxParent
,
135 const uno::Reference
< uno::XComponentContext
>& rxContext
,
136 const uno::Reference
< frame::XModel
>& rxModel
,
137 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
138 const uno::Type
& rVbaType
) throw (uno::RuntimeException
) :
139 mxParent( rxParent
),
140 mxContext( rxContext
),
141 mxModel( rxModel
, uno::UNO_SET_THROW
),
142 mxFactory( rxModel
, uno::UNO_QUERY_THROW
),
143 maVbaType( rVbaType
)
145 uno::Reference
< drawing::XDrawPageSupplier
> xDrawPageSupp( rxSheet
, uno::UNO_QUERY_THROW
);
146 mxShapes
.set( xDrawPageSupp
->getDrawPage(), uno::UNO_QUERY_THROW
);
149 void ScVbaObjectContainer::collectShapes() throw (uno::RuntimeException
)
152 for( sal_Int32 nIndex
= 0, nCount
= mxShapes
->getCount(); nIndex
< nCount
; ++nIndex
)
154 uno::Reference
< drawing::XShape
> xShape( mxShapes
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
155 if( implPickShape( xShape
) )
156 maShapes
.push_back( xShape
);
160 uno::Reference
< drawing::XShape
> ScVbaObjectContainer::createShape( const awt::Point
& rPos
, const awt::Size
& rSize
) throw (uno::RuntimeException
)
162 uno::Reference
< drawing::XShape
> xShape( mxFactory
->createInstance( implGetShapeServiceName() ), uno::UNO_QUERY_THROW
);
163 xShape
->setPosition( rPos
);
164 xShape
->setSize( rSize
);
165 implOnShapeCreated( xShape
);
169 sal_Int32
ScVbaObjectContainer::insertShape( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
)
171 mxShapes
->add( rxShape
);
172 maShapes
.push_back( rxShape
);
173 return mxShapes
->getCount() - 1;
176 ::rtl::Reference
< ScVbaSheetObjectBase
> ScVbaObjectContainer::createVbaObject(
177 const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
)
179 return implCreateVbaObject( rxShape
);
182 uno::Any
ScVbaObjectContainer::createCollectionObject( const uno::Any
& rSource
) throw (uno::RuntimeException
)
184 uno::Reference
< drawing::XShape
> xShape( rSource
, uno::UNO_QUERY_THROW
);
185 uno::Reference
< excel::XSheetObject
> xSheetObject( implCreateVbaObject( xShape
) );
186 return uno::Any( xSheetObject
);
189 uno::Any
ScVbaObjectContainer::getItemByStringIndex( const OUString
& rIndex
) throw (uno::RuntimeException
)
191 for( ShapeVector::iterator aIt
= maShapes
.begin(), aEnd
= maShapes
.end(); aIt
!= aEnd
; ++aIt
)
192 if( rIndex
== implGetShapeName( *aIt
) )
193 return createCollectionObject( uno::Any( *aIt
) );
194 throw uno::RuntimeException();
199 sal_Int32 SAL_CALL
ScVbaObjectContainer::getCount() throw (uno::RuntimeException
, std::exception
)
201 return static_cast< sal_Int32
>( maShapes
.size() );
204 uno::Any SAL_CALL
ScVbaObjectContainer::getByIndex( sal_Int32 nIndex
)
205 throw (lang::IndexOutOfBoundsException
, lang::WrappedTargetException
, uno::RuntimeException
, std::exception
)
207 if( (0 <= nIndex
) && (nIndex
< getCount()) )
208 return uno::Any( maShapes
[ static_cast< size_t >( nIndex
) ] );
209 throw lang::IndexOutOfBoundsException();
214 uno::Type SAL_CALL
ScVbaObjectContainer::getElementType() throw (uno::RuntimeException
, std::exception
)
216 return cppu::UnoType
<drawing::XShape
>::get();
219 sal_Bool SAL_CALL
ScVbaObjectContainer::hasElements() throw (uno::RuntimeException
, std::exception
)
221 return !maShapes
.empty();
226 OUString
ScVbaObjectContainer::implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const throw (uno::RuntimeException
)
228 uno::Reference
< beans::XPropertySet
> xPropSet( rxShape
, uno::UNO_QUERY_THROW
);
229 return xPropSet
->getPropertyValue( "Name" ).get
< OUString
>();
232 void ScVbaObjectContainer::implOnShapeCreated( const uno::Reference
< drawing::XShape
>& /*rxShape*/ ) throw (uno::RuntimeException
)
236 class ScVbaObjectEnumeration
: public SimpleEnumerationBase
239 explicit ScVbaObjectEnumeration( const ScVbaObjectContainerRef
& rxContainer
);
240 virtual uno::Any
createCollectionObject( const uno::Any
& rSource
) SAL_OVERRIDE
;
243 ScVbaObjectContainerRef mxContainer
;
246 ScVbaObjectEnumeration::ScVbaObjectEnumeration( const ScVbaObjectContainerRef
& rxContainer
) :
247 SimpleEnumerationBase( rxContainer
->getParent(), rxContainer
->getContext(), rxContainer
.get() ),
248 mxContainer( rxContainer
)
252 uno::Any
ScVbaObjectEnumeration::createCollectionObject( const uno::Any
& rSource
)
254 return mxContainer
->createCollectionObject( rSource
);
257 ScVbaSheetObjectsBase::ScVbaSheetObjectsBase( const ScVbaObjectContainerRef
& rxContainer
) throw (css::uno::RuntimeException
) :
258 ScVbaSheetObjects_BASE( rxContainer
->getParent(), rxContainer
->getContext(), rxContainer
.get() ),
259 mxContainer( rxContainer
)
261 mxContainer
->collectShapes();
264 ScVbaSheetObjectsBase::~ScVbaSheetObjectsBase()
268 void ScVbaSheetObjectsBase::collectShapes() throw (uno::RuntimeException
)
270 mxContainer
->collectShapes();
273 // XEnumerationAccess
275 uno::Reference
< container::XEnumeration
> SAL_CALL
ScVbaSheetObjectsBase::createEnumeration() throw (uno::RuntimeException
)
277 return new ScVbaObjectEnumeration( mxContainer
);
282 uno::Type SAL_CALL
ScVbaSheetObjectsBase::getElementType() throw (uno::RuntimeException
)
284 return mxContainer
->getVbaType();
287 // ScVbaCollectionBase
289 uno::Any
ScVbaSheetObjectsBase::createCollectionObject( const uno::Any
& rSource
)
291 return mxContainer
->createCollectionObject( rSource
);
294 uno::Any
ScVbaSheetObjectsBase::getItemByStringIndex( const OUString
& rIndex
) throw (uno::RuntimeException
)
296 return mxContainer
->getItemByStringIndex( rIndex
);
299 // Graphic object containers supporting ooo.vba.excel.XGraphicObject
301 ScVbaGraphicObjectsBase::ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef
& rxContainer
) throw (uno::RuntimeException
) :
302 ScVbaGraphicObjects_BASE( rxContainer
)
308 uno::Any SAL_CALL
ScVbaGraphicObjectsBase::Add( const uno::Any
& rLeft
, const uno::Any
& rTop
, const uno::Any
& rWidth
, const uno::Any
& rHeight
) throw (uno::RuntimeException
, std::exception
)
310 /* Extract double values from passed Anys (the lclPointsToHmm() helper
311 function will throw a RuntimeException on any error), and convert from
312 points to 1/100 mm. */
313 awt::Point
aPos( static_cast<sal_Int32
>(lclPointsToHmm( rLeft
)), static_cast<sal_Int32
>(lclPointsToHmm( rTop
)) );
314 awt::Size
aSize( static_cast<sal_Int32
>(lclPointsToHmm( rWidth
)), static_cast<sal_Int32
>(lclPointsToHmm( rHeight
)) );
315 // TODO: translate coordinates for RTL sheets
316 if( (aPos
.X
< 0) || (aPos
.Y
< 0) || (aSize
.Width
<= 0) || (aSize
.Height
<= 0) )
317 throw uno::RuntimeException();
319 // create the UNO shape
320 uno::Reference
< drawing::XShape
> xShape( mxContainer
->createShape( aPos
, aSize
), uno::UNO_SET_THROW
);
321 sal_Int32 nIndex
= mxContainer
->insertShape( xShape
);
323 // create and return the VBA object
324 ::rtl::Reference
< ScVbaSheetObjectBase
> xVbaObject
= mxContainer
->createVbaObject( xShape
);
325 xVbaObject
->setDefaultProperties( nIndex
);
326 return uno::Any( uno::Reference
< excel::XSheetObject
>( xVbaObject
.get() ) );
331 class ScVbaControlContainer
: public ScVbaObjectContainer
334 explicit ScVbaControlContainer(
335 const uno::Reference
< XHelperInterface
>& rxParent
,
336 const uno::Reference
< uno::XComponentContext
>& rxContext
,
337 const uno::Reference
< frame::XModel
>& rxModel
,
338 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
339 const uno::Type
& rVbaType
,
340 const OUString
& rModelServiceName
,
341 sal_Int16 nComponentType
) throw (uno::RuntimeException
);
344 uno::Reference
< container::XIndexContainer
> createForm() throw (uno::RuntimeException
);
346 virtual bool implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const SAL_OVERRIDE
;
347 virtual OUString
implGetShapeServiceName() const SAL_OVERRIDE
;
348 virtual bool implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const;
349 virtual OUString
implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const throw (uno::RuntimeException
) SAL_OVERRIDE
;
350 virtual void implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
) SAL_OVERRIDE
;
353 uno::Reference
< container::XIndexContainer
> mxFormIC
;
354 OUString maModelServiceName
;
355 sal_Int16 mnComponentType
;
358 ScVbaControlContainer::ScVbaControlContainer(
359 const uno::Reference
< XHelperInterface
>& rxParent
,
360 const uno::Reference
< uno::XComponentContext
>& rxContext
,
361 const uno::Reference
< frame::XModel
>& rxModel
,
362 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
363 const uno::Type
& rVbaType
,
364 const OUString
& rModelServiceName
,
365 sal_Int16 nComponentType
) throw (uno::RuntimeException
) :
366 ScVbaObjectContainer( rxParent
, rxContext
, rxModel
, rxSheet
, rVbaType
),
367 maModelServiceName( rModelServiceName
),
368 mnComponentType( nComponentType
)
372 uno::Reference
< container::XIndexContainer
> ScVbaControlContainer::createForm() throw (uno::RuntimeException
)
376 uno::Reference
< form::XFormsSupplier
> xFormsSupp( mxShapes
, uno::UNO_QUERY_THROW
);
377 uno::Reference
< container::XNameContainer
> xFormsNC( xFormsSupp
->getForms(), uno::UNO_SET_THROW
);
378 OUString aFormName
= "Standard";
379 if( xFormsNC
->hasByName( aFormName
) )
381 mxFormIC
.set( xFormsNC
->getByName( aFormName
), uno::UNO_QUERY_THROW
);
385 uno::Reference
< form::XForm
> xForm( mxFactory
->createInstance( "com.sun.star.form.component.Form" ), uno::UNO_QUERY_THROW
);
386 xFormsNC
->insertByName( aFormName
, uno::Any( xForm
) );
387 mxFormIC
.set( xForm
, uno::UNO_QUERY_THROW
);
393 bool ScVbaControlContainer::implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const
397 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
398 uno::Reference
< beans::XPropertySet
> xModelProps( xControlShape
->getControl(), uno::UNO_QUERY_THROW
);
399 sal_Int16 nClassId
= -1;
400 return lclGetProperty( nClassId
, xModelProps
, "ClassId" ) &&
401 (nClassId
== mnComponentType
) && implCheckProperties( xModelProps
);
403 catch( uno::Exception
& )
409 OUString
ScVbaControlContainer::implGetShapeServiceName() const
411 return OUString( "com.sun.star.drawing.ControlShape" );
414 bool ScVbaControlContainer::implCheckProperties( const uno::Reference
< beans::XPropertySet
>& /*rxModelProps*/ ) const
419 OUString
ScVbaControlContainer::implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const throw (uno::RuntimeException
)
421 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
422 return uno::Reference
< container::XNamed
>( xControlShape
->getControl(), uno::UNO_QUERY_THROW
)->getName();
425 void ScVbaControlContainer::implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
)
427 // passed shape must be a control shape
428 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
430 // create the UNO control model
431 uno::Reference
< form::XFormComponent
> xFormComponent( mxFactory
->createInstance( maModelServiceName
), uno::UNO_QUERY_THROW
);
432 uno::Reference
< awt::XControlModel
> xControlModel( xFormComponent
, uno::UNO_QUERY_THROW
);
434 // insert the control model into the form and the shape
436 mxFormIC
->insertByIndex( mxFormIC
->getCount(), uno::Any( xFormComponent
) );
437 xControlShape
->setControl( xControlModel
);
442 class ScVbaButtonContainer
: public ScVbaControlContainer
445 explicit ScVbaButtonContainer(
446 const uno::Reference
< XHelperInterface
>& rxParent
,
447 const uno::Reference
< uno::XComponentContext
>& rxContext
,
448 const uno::Reference
< frame::XModel
>& rxModel
,
449 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
) throw (uno::RuntimeException
);
452 virtual ScVbaSheetObjectBase
* implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
) SAL_OVERRIDE
;
453 virtual bool implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const SAL_OVERRIDE
;
456 ScVbaButtonContainer::ScVbaButtonContainer(
457 const uno::Reference
< XHelperInterface
>& rxParent
,
458 const uno::Reference
< uno::XComponentContext
>& rxContext
,
459 const uno::Reference
< frame::XModel
>& rxModel
,
460 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
) throw (uno::RuntimeException
) :
461 ScVbaControlContainer(
462 rxParent
, rxContext
, rxModel
, rxSheet
,
463 cppu::UnoType
<excel::XButton
>::get(),
464 "com.sun.star.form.component.CommandButton",
465 form::FormComponentType::COMMANDBUTTON
)
469 ScVbaSheetObjectBase
* ScVbaButtonContainer::implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) throw (uno::RuntimeException
)
471 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
472 return new ScVbaButton( mxParent
, mxContext
, mxModel
, createForm(), xControlShape
);
475 bool ScVbaButtonContainer::implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const
477 // do not insert toggle buttons into the 'Buttons' collection
478 bool bToggle
= false;
479 return lclGetProperty( bToggle
, rxModelProps
, "Toggle" ) && !bToggle
;
482 ScVbaButtons::ScVbaButtons(
483 const uno::Reference
< XHelperInterface
>& rxParent
,
484 const uno::Reference
< uno::XComponentContext
>& rxContext
,
485 const uno::Reference
< frame::XModel
>& rxModel
,
486 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
) throw (uno::RuntimeException
) :
487 ScVbaGraphicObjectsBase( new ScVbaButtonContainer( rxParent
, rxContext
, rxModel
, rxSheet
) )
491 VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtons
, "ooo.vba.excel.Buttons" )
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */