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 <com/sun/star/frame/XModel.hpp>
34 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 #include <com/sun/star/sheet/XSpreadsheet.hpp>
36 #include "vbasheetobject.hxx"
37 #include <cppuhelper/implbase.hxx>
39 using namespace ::com::sun::star
;
40 using namespace ::ooo::vba
;
44 template< typename Type
>
45 bool lclGetProperty( Type
& orValue
, const uno::Reference
< beans::XPropertySet
>& rxPropSet
, const OUString
& rPropName
)
49 return rxPropSet
->getPropertyValue( rPropName
) >>= orValue
;
51 catch( uno::Exception
& )
57 /** Rounds the passed value to a multiple of 0.75 and converts it to 1/100 mm.
59 @throws uno::RuntimeException
61 double lclPointsToHmm( const uno::Any
& rPoints
)
63 return PointsToHmm( ::rtl::math::approxFloor( rPoints
.get
< double >() / 0.75 ) * 0.75 );
68 // Base implementations
70 /** Container for a specific type of drawing object in a spreadsheet.
72 Derived classes provide all required functionality specific to the type of
73 shapes covered by the container.
75 class ScVbaObjectContainer
: public ::cppu::WeakImplHelper
< container::XIndexAccess
>
78 /// @throws uno::RuntimeException
79 explicit ScVbaObjectContainer(
80 const uno::Reference
< XHelperInterface
>& rxParent
,
81 const uno::Reference
< uno::XComponentContext
>& rxContext
,
82 const uno::Reference
< frame::XModel
>& rxModel
,
83 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
84 const uno::Type
& rVbaType
);
86 /** Returns the VBA helper interface of the VBA collection object. */
87 const uno::Reference
< XHelperInterface
>& getParent() const { return mxParent
; }
88 /** Returns the component context of the VBA collection object. */
89 const uno::Reference
< uno::XComponentContext
>& getContext() const { return mxContext
; }
90 /** Returns the VBA type information of the objects in this container. */
91 const uno::Type
& getVbaType() const { return maVbaType
; }
93 /** Collects all shapes supported by this instance and inserts them into
94 the internal shape vector.
96 @throws uno::RuntimeException
99 /** Creates and returns a new UNO shape.
101 @throws uno::RuntimeException
103 uno::Reference
< drawing::XShape
> createShape( const awt::Point
& rPos
, const awt::Size
& rSize
);
104 /** Inserts the passed shape into the draw page and into this container, and returns its index in the draw page.
106 @throws uno::RuntimeException
108 sal_Int32
insertShape( const uno::Reference
< drawing::XShape
>& rxShape
);
109 /** Creates and returns a new VBA implementation object for the passed shape.
111 @throws uno::RuntimeException
113 ::rtl::Reference
< ScVbaSheetObjectBase
> createVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
);
114 /** Creates and returns a new VBA implementation object for the passed shape in an Any.
116 @throws uno::RuntimeException
118 uno::Any
createCollectionObject( const uno::Any
& rSource
);
119 /** Returns the VBA implementation object with the specified name.
121 @throws uno::RuntimeException
123 uno::Any
getItemByStringIndex( const OUString
& rIndex
);
126 virtual sal_Int32 SAL_CALL
getCount() override
;
127 virtual uno::Any SAL_CALL
getByIndex( sal_Int32 nIndex
) override
;
130 virtual uno::Type SAL_CALL
getElementType() override
;
131 virtual sal_Bool SAL_CALL
hasElements() override
;
134 /** Derived classes return true, if the passed shape is supported by the instance. */
135 virtual bool implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const = 0;
136 /** Derived classes create and return a new VBA implementation object for the passed shape.
138 @throws uno::RuntimeException
140 virtual ScVbaSheetObjectBase
* implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) = 0;
141 /** Derived classes return the service name of the UNO shape. */
142 virtual OUString
implGetShapeServiceName() const = 0;
144 /** Returns the shape name via 'Name' property of the UNO shape. May be overwritten.
146 @throws uno::RuntimeException
148 virtual OUString
implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const;
149 /** Is called when a new UNO shape has been created but not yet inserted into the drawing page.
151 @throws uno::RuntimeException
153 virtual void implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
);
156 uno::Reference
< XHelperInterface
> mxParent
;
157 uno::Reference
< uno::XComponentContext
> mxContext
;
158 uno::Reference
< frame::XModel
> mxModel
;
159 uno::Reference
< lang::XMultiServiceFactory
> mxFactory
;
160 uno::Reference
< drawing::XShapes
> mxShapes
;
163 typedef ::std::vector
< uno::Reference
< drawing::XShape
> > ShapeVector
;
164 const uno::Type maVbaType
;
165 ShapeVector maShapes
;
168 ScVbaObjectContainer::ScVbaObjectContainer(
169 const uno::Reference
< XHelperInterface
>& rxParent
,
170 const uno::Reference
< uno::XComponentContext
>& rxContext
,
171 const uno::Reference
< frame::XModel
>& rxModel
,
172 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
173 const uno::Type
& rVbaType
) :
174 mxParent( rxParent
),
175 mxContext( rxContext
),
176 mxModel( rxModel
, uno::UNO_SET_THROW
),
177 mxFactory( rxModel
, uno::UNO_QUERY_THROW
),
178 maVbaType( rVbaType
)
180 uno::Reference
< drawing::XDrawPageSupplier
> xDrawPageSupp( rxSheet
, uno::UNO_QUERY_THROW
);
181 mxShapes
.set( xDrawPageSupp
->getDrawPage(), uno::UNO_QUERY_THROW
);
184 void ScVbaObjectContainer::collectShapes()
187 for( sal_Int32 nIndex
= 0, nCount
= mxShapes
->getCount(); nIndex
< nCount
; ++nIndex
)
189 uno::Reference
< drawing::XShape
> xShape( mxShapes
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
190 if( implPickShape( xShape
) )
191 maShapes
.push_back( xShape
);
195 uno::Reference
< drawing::XShape
> ScVbaObjectContainer::createShape( const awt::Point
& rPos
, const awt::Size
& rSize
)
197 uno::Reference
< drawing::XShape
> xShape( mxFactory
->createInstance( implGetShapeServiceName() ), uno::UNO_QUERY_THROW
);
198 xShape
->setPosition( rPos
);
199 xShape
->setSize( rSize
);
200 implOnShapeCreated( xShape
);
204 sal_Int32
ScVbaObjectContainer::insertShape( const uno::Reference
< drawing::XShape
>& rxShape
)
206 mxShapes
->add( rxShape
);
207 maShapes
.push_back( rxShape
);
208 return mxShapes
->getCount() - 1;
211 ::rtl::Reference
< ScVbaSheetObjectBase
> ScVbaObjectContainer::createVbaObject(
212 const uno::Reference
< drawing::XShape
>& rxShape
)
214 return implCreateVbaObject( rxShape
);
217 uno::Any
ScVbaObjectContainer::createCollectionObject( const uno::Any
& rSource
)
219 uno::Reference
< drawing::XShape
> xShape( rSource
, uno::UNO_QUERY_THROW
);
220 uno::Reference
< excel::XSheetObject
> xSheetObject( implCreateVbaObject( xShape
) );
221 return uno::Any( xSheetObject
);
224 uno::Any
ScVbaObjectContainer::getItemByStringIndex( const OUString
& rIndex
)
226 auto aIt
= std::find_if(maShapes
.begin(), maShapes
.end(),
227 [&rIndex
, this](const ShapeVector::value_type
& rxShape
) { return rIndex
== implGetShapeName( rxShape
); });
228 if (aIt
!= maShapes
.end())
229 return createCollectionObject( uno::Any( *aIt
) );
230 throw uno::RuntimeException();
235 sal_Int32 SAL_CALL
ScVbaObjectContainer::getCount()
237 return static_cast< sal_Int32
>( maShapes
.size() );
240 uno::Any SAL_CALL
ScVbaObjectContainer::getByIndex( sal_Int32 nIndex
)
242 if( (0 <= nIndex
) && (nIndex
< getCount()) )
243 return uno::Any( maShapes
[ static_cast< size_t >( nIndex
) ] );
244 throw lang::IndexOutOfBoundsException();
249 uno::Type SAL_CALL
ScVbaObjectContainer::getElementType()
251 return cppu::UnoType
<drawing::XShape
>::get();
254 sal_Bool SAL_CALL
ScVbaObjectContainer::hasElements()
256 return !maShapes
.empty();
261 OUString
ScVbaObjectContainer::implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const
263 uno::Reference
< beans::XPropertySet
> xPropSet( rxShape
, uno::UNO_QUERY_THROW
);
264 return xPropSet
->getPropertyValue( "Name" ).get
< OUString
>();
267 void ScVbaObjectContainer::implOnShapeCreated( const uno::Reference
< drawing::XShape
>& /*rxShape*/ )
273 class ScVbaObjectEnumeration
: public SimpleEnumerationBase
276 explicit ScVbaObjectEnumeration( const ScVbaObjectContainerRef
& rxContainer
);
277 virtual uno::Any
createCollectionObject( const uno::Any
& rSource
) override
;
280 ScVbaObjectContainerRef mxContainer
;
285 ScVbaObjectEnumeration::ScVbaObjectEnumeration( const ScVbaObjectContainerRef
& rxContainer
) :
286 SimpleEnumerationBase( rxContainer
.get() ),
287 mxContainer( rxContainer
)
291 uno::Any
ScVbaObjectEnumeration::createCollectionObject( const uno::Any
& rSource
)
293 return mxContainer
->createCollectionObject( rSource
);
296 ScVbaSheetObjectsBase::ScVbaSheetObjectsBase( const ScVbaObjectContainerRef
& rxContainer
) :
297 ScVbaSheetObjects_BASE( rxContainer
->getParent(), rxContainer
->getContext(), rxContainer
.get() ),
298 mxContainer( rxContainer
)
300 mxContainer
->collectShapes();
303 ScVbaSheetObjectsBase::~ScVbaSheetObjectsBase()
307 void ScVbaSheetObjectsBase::collectShapes()
309 mxContainer
->collectShapes();
312 // XEnumerationAccess
314 uno::Reference
< container::XEnumeration
> SAL_CALL
ScVbaSheetObjectsBase::createEnumeration()
316 return new ScVbaObjectEnumeration( mxContainer
);
321 uno::Type SAL_CALL
ScVbaSheetObjectsBase::getElementType()
323 return mxContainer
->getVbaType();
326 // ScVbaCollectionBase
328 uno::Any
ScVbaSheetObjectsBase::createCollectionObject( const uno::Any
& rSource
)
330 return mxContainer
->createCollectionObject( rSource
);
333 uno::Any
ScVbaSheetObjectsBase::getItemByStringIndex( const OUString
& rIndex
)
335 return mxContainer
->getItemByStringIndex( rIndex
);
338 // Graphic object containers supporting ooo.vba.excel.XGraphicObject
340 ScVbaGraphicObjectsBase::ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef
& rxContainer
) :
341 ScVbaGraphicObjects_BASE( rxContainer
)
347 uno::Any SAL_CALL
ScVbaGraphicObjectsBase::Add( const uno::Any
& rLeft
, const uno::Any
& rTop
, const uno::Any
& rWidth
, const uno::Any
& rHeight
)
349 /* Extract double values from passed Anys (the lclPointsToHmm() helper
350 function will throw a RuntimeException on any error), and convert from
351 points to 1/100 mm. */
352 awt::Point
aPos( static_cast<sal_Int32
>(lclPointsToHmm( rLeft
)), static_cast<sal_Int32
>(lclPointsToHmm( rTop
)) );
353 awt::Size
aSize( static_cast<sal_Int32
>(lclPointsToHmm( rWidth
)), static_cast<sal_Int32
>(lclPointsToHmm( rHeight
)) );
354 // TODO: translate coordinates for RTL sheets
355 if( (aPos
.X
< 0) || (aPos
.Y
< 0) || (aSize
.Width
<= 0) || (aSize
.Height
<= 0) )
356 throw uno::RuntimeException();
358 // create the UNO shape
359 uno::Reference
< drawing::XShape
> xShape( mxContainer
->createShape( aPos
, aSize
), uno::UNO_SET_THROW
);
360 sal_Int32 nIndex
= mxContainer
->insertShape( xShape
);
362 // create and return the VBA object
363 ::rtl::Reference
< ScVbaSheetObjectBase
> xVbaObject
= mxContainer
->createVbaObject( xShape
);
364 xVbaObject
->setDefaultProperties( nIndex
);
365 return uno::Any( uno::Reference
< excel::XSheetObject
>( xVbaObject
.get() ) );
372 class ScVbaControlContainer
: public ScVbaObjectContainer
375 /// @throws uno::RuntimeException
376 explicit ScVbaControlContainer(
377 const uno::Reference
< XHelperInterface
>& rxParent
,
378 const uno::Reference
< uno::XComponentContext
>& rxContext
,
379 const uno::Reference
< frame::XModel
>& rxModel
,
380 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
381 const uno::Type
& rVbaType
,
382 const OUString
& rModelServiceName
,
383 sal_Int16
/* css::form::FormComponentType */ eType
);
386 /// @throws uno::RuntimeException
387 uno::Reference
< container::XIndexContainer
> const & createForm();
389 virtual bool implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const override
;
390 virtual OUString
implGetShapeServiceName() const override
;
391 virtual bool implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const;
392 virtual OUString
implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const override
;
393 virtual void implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
) override
;
396 uno::Reference
< container::XIndexContainer
> mxFormIC
;
397 OUString maModelServiceName
;
398 sal_Int16
/* css::form::FormComponentType */ meType
;
403 ScVbaControlContainer::ScVbaControlContainer(
404 const uno::Reference
< XHelperInterface
>& rxParent
,
405 const uno::Reference
< uno::XComponentContext
>& rxContext
,
406 const uno::Reference
< frame::XModel
>& rxModel
,
407 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
408 const uno::Type
& rVbaType
,
409 const OUString
& rModelServiceName
,
410 sal_Int16
/* css::form::FormComponentType */ eType
) :
411 ScVbaObjectContainer( rxParent
, rxContext
, rxModel
, rxSheet
, rVbaType
),
412 maModelServiceName( rModelServiceName
),
417 uno::Reference
< container::XIndexContainer
> const & ScVbaControlContainer::createForm()
421 uno::Reference
< form::XFormsSupplier
> xFormsSupp( mxShapes
, uno::UNO_QUERY_THROW
);
422 uno::Reference
< container::XNameContainer
> xFormsNC( xFormsSupp
->getForms(), uno::UNO_SET_THROW
);
423 OUString aFormName
= "Standard";
424 if( xFormsNC
->hasByName( aFormName
) )
426 mxFormIC
.set( xFormsNC
->getByName( aFormName
), uno::UNO_QUERY_THROW
);
430 uno::Reference
< form::XForm
> xForm( mxFactory
->createInstance( "com.sun.star.form.component.Form" ), uno::UNO_QUERY_THROW
);
431 xFormsNC
->insertByName( aFormName
, uno::Any( xForm
) );
432 mxFormIC
.set( xForm
, uno::UNO_QUERY_THROW
);
438 bool ScVbaControlContainer::implPickShape( const uno::Reference
< drawing::XShape
>& rxShape
) const
442 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
443 uno::Reference
< beans::XPropertySet
> xModelProps( xControlShape
->getControl(), uno::UNO_QUERY_THROW
);
444 sal_Int16 nClassId
= -1;
445 return lclGetProperty( nClassId
, xModelProps
, "ClassId" ) &&
446 (nClassId
== meType
) && implCheckProperties( xModelProps
);
448 catch( uno::Exception
& )
454 OUString
ScVbaControlContainer::implGetShapeServiceName() const
456 return "com.sun.star.drawing.ControlShape";
459 bool ScVbaControlContainer::implCheckProperties( const uno::Reference
< beans::XPropertySet
>& /*rxModelProps*/ ) const
464 OUString
ScVbaControlContainer::implGetShapeName( const uno::Reference
< drawing::XShape
>& rxShape
) const
466 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
467 return uno::Reference
< container::XNamed
>( xControlShape
->getControl(), uno::UNO_QUERY_THROW
)->getName();
470 void ScVbaControlContainer::implOnShapeCreated( const uno::Reference
< drawing::XShape
>& rxShape
)
472 // passed shape must be a control shape
473 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
475 // create the UNO control model
476 uno::Reference
< form::XFormComponent
> xFormComponent( mxFactory
->createInstance( maModelServiceName
), uno::UNO_QUERY_THROW
);
477 uno::Reference
< awt::XControlModel
> xControlModel( xFormComponent
, uno::UNO_QUERY_THROW
);
479 // insert the control model into the form and the shape
481 mxFormIC
->insertByIndex( mxFormIC
->getCount(), uno::Any( xFormComponent
) );
482 xControlShape
->setControl( xControlModel
);
489 class ScVbaButtonContainer
: public ScVbaControlContainer
491 bool mbOptionButtons
;
493 /// @throws uno::RuntimeException
494 explicit ScVbaButtonContainer(
495 const uno::Reference
< XHelperInterface
>& rxParent
,
496 const uno::Reference
< uno::XComponentContext
>& rxContext
,
497 const uno::Reference
< frame::XModel
>& rxModel
,
498 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
499 bool bOptionButtons
);
502 virtual ScVbaSheetObjectBase
* implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
) override
;
503 virtual bool implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const override
;
508 ScVbaButtonContainer::ScVbaButtonContainer(
509 const uno::Reference
< XHelperInterface
>& rxParent
,
510 const uno::Reference
< uno::XComponentContext
>& rxContext
,
511 const uno::Reference
< frame::XModel
>& rxModel
,
512 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
513 bool bOptionButtons
) :
514 ScVbaControlContainer(
515 rxParent
, rxContext
, rxModel
, rxSheet
,
516 cppu::UnoType
<excel::XButton
>::get(),
518 OUString( "com.sun.star.form.component.RadioButton" ) :
519 OUString( "com.sun.star.form.component.CommandButton" ) ),
521 form::FormComponentType::RADIOBUTTON
:
522 form::FormComponentType::COMMANDBUTTON
) ),
523 mbOptionButtons(bOptionButtons
)
527 ScVbaSheetObjectBase
* ScVbaButtonContainer::implCreateVbaObject( const uno::Reference
< drawing::XShape
>& rxShape
)
529 uno::Reference
< drawing::XControlShape
> xControlShape( rxShape
, uno::UNO_QUERY_THROW
);
530 return new ScVbaButton( mxParent
, mxContext
, mxModel
, createForm(), xControlShape
);
533 bool ScVbaButtonContainer::implCheckProperties( const uno::Reference
< beans::XPropertySet
>& rxModelProps
) const
538 // do not insert toggle buttons into the 'Buttons' collection
539 bool bToggle
= false;
540 return lclGetProperty( bToggle
, rxModelProps
, "Toggle" ) && !bToggle
;
543 ScVbaButtons::ScVbaButtons(
544 const uno::Reference
< XHelperInterface
>& rxParent
,
545 const uno::Reference
< uno::XComponentContext
>& rxContext
,
546 const uno::Reference
< frame::XModel
>& rxModel
,
547 const uno::Reference
< sheet::XSpreadsheet
>& rxSheet
,
548 bool bOptionButtons
) :
549 ScVbaGraphicObjectsBase( new ScVbaButtonContainer( rxParent
, rxContext
, rxModel
, rxSheet
, bOptionButtons
) )
553 VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtons
, "ooo.vba.excel.Buttons" )
555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */