1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25 ************************************************************************/
26 
27 // MARKER(update_precomp.py): autogen include statement, do not remove
28 #include "precompiled_extensions.hxx"
29 
30 #include "propertyhandler.hxx"
31 #include "formmetadata.hxx"
32 #include "formstrings.hxx"
33 #include "handlerhelper.hxx"
34 #include "cellbindinghelper.hxx"
35 
36 /** === begin UNO includes === **/
37 #include <com/sun/star/inspection/XObjectInspectorUI.hpp>
38 #include <com/sun/star/awt/XControlModel.hpp>
39 #include <com/sun/star/drawing/XControlShape.hpp>
40 #include <com/sun/star/container/XMap.hpp>
41 #include <com/sun/star/inspection/XNumericControl.hpp>
42 #include <com/sun/star/util/MeasureUnit.hpp>
43 #include <com/sun/star/text/TextContentAnchorType.hpp>
44 #include <com/sun/star/lang/XServiceInfo.hpp>
45 #include <com/sun/star/sheet/XSpreadsheet.hpp>
46 #include <com/sun/star/table/XColumnRowRange.hpp>
47 #include <com/sun/star/table/XCellRange.hpp>
48 #include <com/sun/star/container/XChild.hpp>
49 #include <com/sun/star/form/XGridColumnFactory.hpp>
50 /** === end UNO includes === **/
51 
52 #include <cppuhelper/interfacecontainer.hxx>
53 #include <comphelper/componentbase.hxx>
54 #include <tools/debug.hxx>
55 #include <tools/diagnose_ex.h>
56 
57 //........................................................................
58 namespace pcr
59 {
60 //........................................................................
61 
62 	/** === begin UNO using === **/
63 	using ::com::sun::star::uno::Reference;
64 	using ::com::sun::star::uno::XInterface;
65 	using ::com::sun::star::uno::UNO_QUERY;
66 	using ::com::sun::star::uno::UNO_QUERY_THROW;
67 	using ::com::sun::star::uno::UNO_SET_THROW;
68 	using ::com::sun::star::uno::Exception;
69 	using ::com::sun::star::uno::RuntimeException;
70 	using ::com::sun::star::uno::Any;
71 	using ::com::sun::star::uno::makeAny;
72 	using ::com::sun::star::uno::Sequence;
73 	using ::com::sun::star::uno::Type;
74     using ::com::sun::star::uno::XComponentContext;
75     using ::com::sun::star::beans::UnknownPropertyException;
76     using ::com::sun::star::beans::Property;
77     using ::com::sun::star::awt::XControlModel;
78     using ::com::sun::star::drawing::XControlShape;
79     using ::com::sun::star::container::XMap;
80     using ::com::sun::star::inspection::LineDescriptor;
81     using ::com::sun::star::inspection::XPropertyControlFactory;
82     using ::com::sun::star::lang::NullPointerException;
83     using ::com::sun::star::beans::Optional;
84     using ::com::sun::star::inspection::XNumericControl;
85     using ::com::sun::star::drawing::XShape;
86     using ::com::sun::star::beans::PropertyChangeEvent;
87     using ::com::sun::star::lang::EventObject;
88     using ::com::sun::star::beans::XPropertySet;
89     using ::com::sun::star::beans::XPropertyChangeListener;
90     using ::com::sun::star::text::TextContentAnchorType;
91     using ::com::sun::star::text::TextContentAnchorType_AT_PARAGRAPH;
92     using ::com::sun::star::text::TextContentAnchorType_AS_CHARACTER;
93     using ::com::sun::star::beans::XPropertySetInfo;
94     using ::com::sun::star::inspection::XObjectInspectorUI;
95     using ::com::sun::star::lang::XServiceInfo;
96     using ::com::sun::star::sheet::XSpreadsheet;
97     using ::com::sun::star::table::XColumnRowRange;
98     using ::com::sun::star::table::XTableColumns;
99     using ::com::sun::star::table::XTableRows;
100     using ::com::sun::star::table::XCellRange;
101     using ::com::sun::star::container::XIndexAccess;
102     using ::com::sun::star::container::XChild;
103     using ::com::sun::star::form::XGridColumnFactory;
104 	/** === end UNO using === **/
105     namespace MeasureUnit = ::com::sun::star::util::MeasureUnit;
106 
107     typedef ::com::sun::star::awt::Point    AwtPoint;
108     typedef ::com::sun::star::awt::Size     AwtSize;
109 
110     #define ANCHOR_TO_SHEET 0
111     #define ANCHOR_TO_CELL  1
112 
113     //====================================================================
114 	//= BroadcastHelperBase
115 	//====================================================================
116     class BroadcastHelperBase
117     {
118     protected:
119         BroadcastHelperBase( ::osl::Mutex& _rMutex )
120             :maBHelper( _rMutex )
121         {
122         }
123 
124     protected:
125         ::cppu::OBroadcastHelper& getBroadcastHelper() { return maBHelper; }
126 
127     private:
128         ::cppu::OBroadcastHelper    maBHelper;
129     };
130 
131     //====================================================================
132 	//= ShapeGeometryChangeNotifier - declaration
133 	//====================================================================
134     /** helper class to work around the ...unfortunate implementation of property change broadcasts
135         in the XShape implementation, which broadcasts way too generous and unspecified
136     */
137     typedef ::comphelper::ComponentBase ShapeGeometryChangeNotifier_CBase;
138     typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::beans::XPropertyChangeListener
139                                     >   ShapeGeometryChangeNotifier_IBase;
140 
141     class ShapeGeometryChangeNotifier   :public BroadcastHelperBase
142                                         ,public ShapeGeometryChangeNotifier_CBase
143                                         ,public ShapeGeometryChangeNotifier_IBase
144     {
145     public:
146         ShapeGeometryChangeNotifier( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rParentMutex, const Reference< XShape >& _shape )
147             :BroadcastHelperBase( _rParentMutex )
148             ,ShapeGeometryChangeNotifier_CBase( BroadcastHelperBase::getBroadcastHelper(), ::comphelper::ComponentBase::NoInitializationNeeded() )
149             ,ShapeGeometryChangeNotifier_IBase()
150             ,m_rParent( _rParent )
151             ,m_aPropertyChangeListeners( _rParentMutex )
152             ,m_xShape( _shape )
153         {
154             ENSURE_OR_THROW( m_xShape.is(), "illegal shape!" );
155             impl_init_nothrow();
156         }
157 
158         // property change broadcasting
159         void addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
160         {
161             m_aPropertyChangeListeners.addInterface( _listener );
162         }
163         void removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
164         {
165             m_aPropertyChangeListeners.removeInterface( _listener );
166         }
167 
168         // XComponent equivalent
169         void dispose()
170         {
171             ::osl::MutexGuard aGuard( getMutex() );
172             impl_dispose_nothrow();
173         }
174 
175         // XInterface
176         virtual void SAL_CALL acquire(  ) throw ()
177         {
178             m_rParent.acquire();
179         }
180 
181         virtual void SAL_CALL release(  ) throw ()
182         {
183             m_rParent.release();
184         }
185 
186         // XPropertyChangeListener
187         virtual void SAL_CALL propertyChange( const PropertyChangeEvent& _event ) throw (RuntimeException);
188 
189         // XEventListener
190         virtual void SAL_CALL disposing( const EventObject& _event ) throw (RuntimeException);
191 
192     protected:
193         virtual ~ShapeGeometryChangeNotifier()
194         {
195             if ( !getBroadcastHelper().bDisposed )
196             {
197                 acquire();
198                 dispose();
199             }
200         }
201 
202     protected:
203         ::cppu::OBroadcastHelper& getBroadcastHelper() { return BroadcastHelperBase::getBroadcastHelper(); }
204 
205     private:
206         void    impl_init_nothrow();
207         void    impl_dispose_nothrow();
208 
209     private:
210         ::cppu::OWeakObject&                m_rParent;
211         ::cppu::OInterfaceContainerHelper   m_aPropertyChangeListeners;
212         Reference< XShape >                 m_xShape;
213     };
214 
215 	//====================================================================
216 	//= FormGeometryHandler - declaration
217 	//====================================================================
218     class FormGeometryHandler;
219     typedef HandlerComponentBase< FormGeometryHandler > FormGeometryHandler_Base;
220     /** a property handler for any virtual string properties
221     */
222     class FormGeometryHandler : public FormGeometryHandler_Base
223 	{
224     public:
225         FormGeometryHandler(
226             const Reference< XComponentContext >& _rxContext
227         );
228 
229         static ::rtl::OUString SAL_CALL getImplementationName_static(  ) throw (RuntimeException);
230         static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(  ) throw (RuntimeException);
231 
232     protected:
233         ~FormGeometryHandler();
234 
235     protected:
236         // XPropertyHandler overriables
237         virtual Any                         SAL_CALL getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException);
238         virtual void                        SAL_CALL setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw (UnknownPropertyException, RuntimeException);
239         virtual LineDescriptor              SAL_CALL describePropertyLine( const ::rtl::OUString& _rPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::inspection::XPropertyControlFactory >& _rxControlFactory ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::NullPointerException, ::com::sun::star::uno::RuntimeException);
240         virtual void                        SAL_CALL addPropertyChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException);
241         virtual void                        SAL_CALL removePropertyChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException);
242         virtual Sequence< ::rtl::OUString > SAL_CALL getActuatingProperties( ) throw (RuntimeException);
243         virtual void                        SAL_CALL actuatingPropertyChanged( const ::rtl::OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) throw (NullPointerException, RuntimeException);
244 
245         // OComponentHandler overridables
246         virtual void SAL_CALL disposing();
247 
248         // PropertyHandler overridables
249         virtual Sequence< Property >        SAL_CALL doDescribeSupportedProperties() const;
250 
251     protected:
252         virtual void onNewComponent();
253 
254     private:
255         bool    impl_haveTextAnchorType_nothrow() const;
256         bool    impl_haveSheetAnchorType_nothrow() const;
257         void    impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const;
258 
259     private:
260         Reference< XControlShape >                      m_xAssociatedShape;
261         Reference< XPropertySet >                       m_xShapeProperties;
262         ::rtl::Reference< ShapeGeometryChangeNotifier > m_xChangeNotifier;
263 	};
264 
265     //====================================================================
266 	//= FormGeometryHandler - implementation
267 	//====================================================================
268     DBG_NAME( FormGeometryHandler )
269 	//--------------------------------------------------------------------
270     FormGeometryHandler::FormGeometryHandler( const Reference< XComponentContext >& _rxContext )
271         :FormGeometryHandler_Base( _rxContext )
272     {
273         DBG_CTOR( FormGeometryHandler, NULL );
274     }
275 
276 	//--------------------------------------------------------------------
277     FormGeometryHandler::~FormGeometryHandler( )
278     {
279         if ( !rBHelper.bDisposed )
280         {
281             acquire();
282             dispose();
283         }
284 
285         DBG_DTOR( FormGeometryHandler, NULL );
286     }
287 
288     //--------------------------------------------------------------------
289     void FormGeometryHandler::onNewComponent()
290     {
291         if ( m_xChangeNotifier.is() )
292         {
293             m_xChangeNotifier->dispose();
294             m_xChangeNotifier.clear();
295         }
296         m_xAssociatedShape.clear();
297         m_xShapeProperties.clear();
298 
299         FormGeometryHandler_Base::onNewComponent();
300 
301         try
302         {
303             Reference< XControlModel > xControlModel( m_xComponent, UNO_QUERY );
304             if ( xControlModel.is() )
305             {
306                 // do not ask the map for shapes for grid control columns ....
307                 Reference< XChild > xCompChild( m_xComponent, UNO_QUERY_THROW );
308                 Reference< XGridColumnFactory > xCheckGrid( xCompChild->getParent(), UNO_QUERY );
309                 if ( !xCheckGrid.is() )
310                 {
311                     Reference< XMap > xControlMap( m_aContext.getContextValueByAsciiName( "ControlShapeAccess" ), UNO_QUERY_THROW );
312                     m_xAssociatedShape.set( xControlMap->get( makeAny( xControlModel ) ), UNO_QUERY_THROW );
313                     m_xShapeProperties.set( m_xAssociatedShape, UNO_QUERY_THROW );
314                 }
315             }
316         }
317         catch( const Exception& )
318         {
319         	DBG_UNHANDLED_EXCEPTION();
320         }
321 
322         if ( m_xAssociatedShape.is() )
323             m_xChangeNotifier = new ShapeGeometryChangeNotifier( *this, m_aMutex, m_xAssociatedShape.get() );
324     }
325 
326     //--------------------------------------------------------------------
327     ::rtl::OUString SAL_CALL FormGeometryHandler::getImplementationName_static(  ) throw (RuntimeException)
328     {
329         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.FormGeometryHandler" ) );
330     }
331 
332     //--------------------------------------------------------------------
333     Sequence< ::rtl::OUString > SAL_CALL FormGeometryHandler::getSupportedServiceNames_static(  ) throw (RuntimeException)
334     {
335         Sequence< ::rtl::OUString > aSupported( 1 );
336         aSupported[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.inspection.FormGeometryHandler" ) );
337         return aSupported;
338     }
339 
340     //--------------------------------------------------------------------
341     Any SAL_CALL FormGeometryHandler::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
342     {
343         ::osl::MutexGuard aGuard( m_aMutex );
344         PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) );
345 
346         ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
347         ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: no shape properties!", *this );
348 
349         Any aReturn;
350         try
351         {
352             switch ( nPropId )
353             {
354             case PROPERTY_ID_POSITIONX:
355                 aReturn <<= m_xAssociatedShape->getPosition().X;
356                 break;
357             case PROPERTY_ID_POSITIONY:
358                 aReturn <<= m_xAssociatedShape->getPosition().Y;
359                 break;
360             case PROPERTY_ID_WIDTH:
361                 aReturn <<= m_xAssociatedShape->getSize().Width;
362                 break;
363             case PROPERTY_ID_HEIGHT:
364                 aReturn <<= m_xAssociatedShape->getSize().Height;
365                 break;
366             case PROPERTY_ID_TEXT_ANCHOR_TYPE:
367                 aReturn = m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR_TYPE );
368                 OSL_ENSURE( aReturn.hasValue(), "FormGeometryHandler::getPropertyValue: illegal anchor type!" );
369                 break;
370             case PROPERTY_ID_SHEET_ANCHOR_TYPE:
371             {
372                 Reference< XSpreadsheet > xAnchorSheet( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ), UNO_QUERY );
373                 aReturn <<= sal_Int32( xAnchorSheet.is() ? ANCHOR_TO_SHEET : ANCHOR_TO_CELL );
374             }
375             break;
376 
377             default:
378                 OSL_ENSURE( false, "FormGeometryHandler::getPropertyValue: huh?" );
379                 break;
380             }
381         }
382         catch( const Exception& )
383         {
384         	DBG_UNHANDLED_EXCEPTION();
385         }
386         return aReturn;
387     }
388 
389     //--------------------------------------------------------------------
390     void SAL_CALL FormGeometryHandler::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw (UnknownPropertyException, RuntimeException)
391     {
392         ::osl::MutexGuard aGuard( m_aMutex );
393         PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) );
394 
395         ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
396         ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: properties, but no shape!", *this );
397 
398         try
399         {
400             switch ( nPropId )
401             {
402             case PROPERTY_ID_POSITIONX:
403             case PROPERTY_ID_POSITIONY:
404             {
405                 sal_Int32 nPosition(0);
406                 OSL_VERIFY( _rValue >>= nPosition );
407 
408                 AwtPoint aPos( m_xAssociatedShape->getPosition() );
409                 if ( nPropId == PROPERTY_ID_POSITIONX )
410                     aPos.X = nPosition;
411                 else
412                     aPos.Y = nPosition;
413                 m_xAssociatedShape->setPosition( aPos );
414             }
415             break;
416 
417             case PROPERTY_ID_WIDTH:
418             case PROPERTY_ID_HEIGHT:
419             {
420                 sal_Int32 nSize(0);
421                 OSL_VERIFY( _rValue >>= nSize );
422 
423                 AwtSize aSize( m_xAssociatedShape->getSize() );
424                 if ( nPropId == PROPERTY_ID_WIDTH )
425                     aSize.Width = nSize;
426                 else
427                     aSize.Height = nSize;
428 				m_xAssociatedShape->setSize( aSize );
429             }
430             break;
431 
432             case PROPERTY_ID_TEXT_ANCHOR_TYPE:
433                 m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR_TYPE, _rValue );
434                 break;
435 
436             case PROPERTY_ID_SHEET_ANCHOR_TYPE:
437             {
438                 sal_Int32 nSheetAnchorType = 0;
439                 OSL_VERIFY( _rValue >>= nSheetAnchorType );
440                 impl_setSheetAnchorType_nothrow( nSheetAnchorType );
441             }
442             break;
443 
444             default:
445                 OSL_ENSURE( false, "FormGeometryHandler::getPropertyValue: huh?" );
446                 break;
447             }
448         }
449         catch( const Exception& )
450         {
451         	DBG_UNHANDLED_EXCEPTION();
452         }
453     }
454 
455     //--------------------------------------------------------------------
456     LineDescriptor SAL_CALL FormGeometryHandler::describePropertyLine( const ::rtl::OUString& _rPropertyName,
457             const Reference< XPropertyControlFactory >& _rxControlFactory )
458         throw (UnknownPropertyException, NullPointerException, RuntimeException)
459     {
460         ::osl::MutexGuard aGuard( m_aMutex );
461         PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) );
462 
463         LineDescriptor aLineDesc( PropertyHandler::describePropertyLine( _rPropertyName, _rxControlFactory ) );
464         try
465         {
466             bool bIsSize = false;
467             switch ( nPropId )
468             {
469             case PROPERTY_ID_WIDTH:
470             case PROPERTY_ID_HEIGHT:
471                 bIsSize = true;
472                 // NO break!
473             case PROPERTY_ID_POSITIONX:
474             case PROPERTY_ID_POSITIONY:
475             {
476                 Optional< double > aZero( sal_True, 0 );
477                 Optional< double > aValueNotPresent( sal_False, 0 );
478                 aLineDesc.Control = PropertyHandlerHelper::createNumericControl(
479                     _rxControlFactory, 2, bIsSize ? aZero : aValueNotPresent, aValueNotPresent, sal_False );
480 
481                 Reference< XNumericControl > xNumericControl( aLineDesc.Control, UNO_QUERY_THROW );
482                 xNumericControl->setValueUnit( MeasureUnit::MM_100TH );
483                 xNumericControl->setDisplayUnit( impl_getDocumentMeasurementUnit_throw() );
484             }
485             break;
486 
487             case PROPERTY_ID_TEXT_ANCHOR_TYPE:
488             case PROPERTY_ID_SHEET_ANCHOR_TYPE:
489                 // default handling from PropertyHandler is sufficient
490                 break;
491 
492             default:
493                 OSL_ENSURE( false, "FormGeometryHandler::describePropertyLine: huh?" );
494                 break;
495             }
496         }
497         catch( const Exception& )
498         {
499         	DBG_UNHANDLED_EXCEPTION();
500         }
501         return aLineDesc;
502     }
503 
504     //--------------------------------------------------------------------
505     void SAL_CALL FormGeometryHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) throw (RuntimeException)
506     {
507         ::osl::MutexGuard aGuard( m_aMutex );
508         OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::addPropertyChangeListener: no notified, implies no shape!?" );
509         if ( m_xChangeNotifier.is() )
510             m_xChangeNotifier->addPropertyChangeListener( _listener );
511     }
512 
513     //--------------------------------------------------------------------
514     void SAL_CALL FormGeometryHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) throw (RuntimeException)
515     {
516         ::osl::MutexGuard aGuard( m_aMutex );
517         OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::removePropertyChangeListener: no notified, implies no shape!?" );
518         if ( m_xChangeNotifier.is() )
519             m_xChangeNotifier->removePropertyChangeListener( _listener );
520     }
521 
522     //--------------------------------------------------------------------
523     Sequence< ::rtl::OUString > SAL_CALL FormGeometryHandler::getActuatingProperties( ) throw (RuntimeException)
524     {
525         Sequence< ::rtl::OUString > aInterestedIn(1);
526         aInterestedIn[0] = PROPERTY_TEXT_ANCHOR_TYPE;
527         return aInterestedIn;
528     }
529 
530     //--------------------------------------------------------------------
531     void SAL_CALL FormGeometryHandler::actuatingPropertyChanged( const ::rtl::OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ ) throw (NullPointerException, RuntimeException)
532     {
533         if ( !_rxInspectorUI.is() )
534             throw NullPointerException();
535 
536         ::osl::MutexGuard aGuard( m_aMutex );
537         PropertyId nActuatingPropId( impl_getPropertyId_throw( _rActuatingPropertyName ) );
538 
539         switch ( nActuatingPropId )
540         {
541         case PROPERTY_ID_TEXT_ANCHOR_TYPE:
542         {
543             TextContentAnchorType eAnchorType( TextContentAnchorType_AT_PARAGRAPH );
544             OSL_VERIFY( _rNewValue >>= eAnchorType );
545             _rxInspectorUI->enablePropertyUI( PROPERTY_POSITIONX, eAnchorType != TextContentAnchorType_AS_CHARACTER );
546         }
547         break;
548         default:
549             OSL_ENSURE( false, "FormGeometryHandler::actuatingPropertyChanged: not registered for this property!" );
550             break;
551         }
552     }
553 
554     //--------------------------------------------------------------------
555     Sequence< Property > SAL_CALL FormGeometryHandler::doDescribeSupportedProperties() const
556     {
557         if ( !m_xAssociatedShape.is() )
558             return Sequence< Property >();
559 
560         ::std::vector< Property > aProperties;
561 
562         addInt32PropertyDescription( aProperties, PROPERTY_POSITIONX );
563         addInt32PropertyDescription( aProperties, PROPERTY_POSITIONY );
564         addInt32PropertyDescription( aProperties, PROPERTY_WIDTH );
565         addInt32PropertyDescription( aProperties, PROPERTY_HEIGHT );
566 
567         if ( impl_haveTextAnchorType_nothrow() )
568             implAddPropertyDescription( aProperties, PROPERTY_TEXT_ANCHOR_TYPE, ::cppu::UnoType< TextContentAnchorType >::get() );
569 
570         if ( impl_haveSheetAnchorType_nothrow() )
571             addInt32PropertyDescription( aProperties, PROPERTY_SHEET_ANCHOR_TYPE );
572 
573         return Sequence< Property >( &(*aProperties.begin()), aProperties.size() );
574     }
575 
576     //--------------------------------------------------------------------
577     void SAL_CALL FormGeometryHandler::disposing()
578     {
579         FormGeometryHandler_Base::disposing();
580 
581         if ( m_xChangeNotifier.is() )
582         {
583             m_xChangeNotifier->dispose();
584             m_xChangeNotifier.clear();
585         }
586     }
587 
588     //--------------------------------------------------------------------
589     bool FormGeometryHandler::impl_haveTextAnchorType_nothrow() const
590     {
591         ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
592         try
593         {
594             Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
595             if ( xPSI->hasPropertyByName( PROPERTY_ANCHOR_TYPE ) )
596                 return true;
597         }
598         catch( const Exception& )
599         {
600         	DBG_UNHANDLED_EXCEPTION();
601         }
602         return false;
603     }
604 
605     //--------------------------------------------------------------------
606     bool FormGeometryHandler::impl_haveSheetAnchorType_nothrow() const
607     {
608         ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
609         try
610         {
611             Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
612             if ( !xPSI->hasPropertyByName( PROPERTY_ANCHOR ) )
613                 return false;
614             Reference< XServiceInfo > xSI( m_xAssociatedShape, UNO_QUERY_THROW );
615             if ( xSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.Shape" ) ) ) )
616                 return true;
617         }
618         catch( const Exception& )
619         {
620         	DBG_UNHANDLED_EXCEPTION();
621         }
622         return false;
623     }
624 
625     //--------------------------------------------------------------------
626     namespace
627     {
628         static sal_Int32 lcl_getLowerBoundRowOrColumn( const Reference< XIndexAccess >& _rxRowsOrColumns, const bool _bRows,
629             const AwtPoint& _rRelativePosition )
630         {
631             sal_Int32 nAccumulated = 0;
632 
633             const sal_Int32& rRelativePos = _bRows ? _rRelativePosition.Y : _rRelativePosition.X;
634 
635             sal_Int32 nElements = _rxRowsOrColumns->getCount();
636             sal_Int32 currentPos = 0;
637             for ( currentPos=0; currentPos<nElements; ++currentPos )
638             {
639                 Reference< XPropertySet > xRowOrColumn( _rxRowsOrColumns->getByIndex( currentPos ), UNO_QUERY_THROW );
640 
641                 sal_Bool bIsVisible = sal_True;
642                 OSL_VERIFY( xRowOrColumn->getPropertyValue( PROPERTY_IS_VISIBLE ) >>= bIsVisible );
643                 if ( !bIsVisible )
644                     continue;
645 
646                 sal_Int32 nHeightOrWidth( 0 );
647                 OSL_VERIFY( xRowOrColumn->getPropertyValue( _bRows ? PROPERTY_HEIGHT : PROPERTY_WIDTH ) >>= nHeightOrWidth );
648 
649                 if ( nAccumulated + nHeightOrWidth > rRelativePos )
650                     break;
651 
652                 nAccumulated += nHeightOrWidth;
653             }
654 
655             return currentPos;
656         }
657     }
658 
659     //--------------------------------------------------------------------
660     void FormGeometryHandler::impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const
661     {
662         ENSURE_OR_THROW( m_xShapeProperties.is(), "illegal to be called without shape properties." );
663         try
664         {
665             CellBindingHelper aHelper( m_xComponent, impl_getContextDocument_nothrow() );
666             // find the sheet which the control belongs to
667             Reference< XSpreadsheet > xSheet;
668             aHelper.getControlSheetIndex( xSheet );
669 
670             switch ( _nAnchorType )
671             {
672             case ANCHOR_TO_SHEET:
673                 OSL_ENSURE( xSheet.is(),
674                     "FormGeometryHandler::impl_setSheetAnchorType_nothrow: sheet not found!" );
675                 if ( xSheet.is() )
676                 {
677                     AwtPoint aPreservePosition( m_xAssociatedShape->getPosition() );
678                     m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, makeAny( xSheet ) );
679                     m_xAssociatedShape->setPosition( aPreservePosition );
680                 }
681                 break;
682 
683             case ANCHOR_TO_CELL:
684             {
685                 Reference< XColumnRowRange > xColsRows( xSheet, UNO_QUERY_THROW );
686 
687                 // get the current anchor
688                 Reference< XSpreadsheet > xCurrentAnchor;
689                 OSL_VERIFY( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ) >>= xCurrentAnchor );
690                 OSL_ENSURE( xCurrentAnchor.is(), "FormGeometryHandler::impl_setSheetAnchorType_nothrow: only to be called when currently anchored to a sheet!" );
691 
692                 // get the current position
693                 AwtPoint aRelativePosition( m_xAssociatedShape->getPosition() );
694 
695                 Reference< XTableColumns > xCols( xColsRows->getColumns(), UNO_SET_THROW );
696                 sal_Int32 nNewAnchorCol = lcl_getLowerBoundRowOrColumn( xCols.get(), false, aRelativePosition );
697 
698                 Reference< XTableRows > xRows( xColsRows->getRows(), UNO_SET_THROW );
699                 sal_Int32 nNewAnchorRow = lcl_getLowerBoundRowOrColumn( xRows.get(), true, aRelativePosition );
700 
701                 Reference< XCellRange > xSheetCellRange( xSheet, UNO_QUERY_THROW );
702                 Any aNewAnchorCell( xSheetCellRange->getCellByPosition( nNewAnchorCol, nNewAnchorRow ) );
703                 m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, aNewAnchorCell );
704             }
705             break;
706 
707             default:
708                 OSL_ENSURE( false, "FormGeometryHandler::impl_setSheetAnchorType_nothrow: illegal anchor type!" );
709                 break;
710             }
711         }
712         catch( const Exception& )
713         {
714         	DBG_UNHANDLED_EXCEPTION();
715         }
716     }
717 
718     //====================================================================
719 	//= ShapeGeometryChangeNotifier - implementation
720 	//====================================================================
721     namespace
722     {
723         struct EventTranslation
724         {
725             ::rtl::OUString sPropertyName;
726             Any             aNewPropertyValue;
727 
728             EventTranslation( const ::rtl::OUString& _propertyName, const Any& _newPropertyValue )
729                 :sPropertyName( _propertyName )
730                 ,aNewPropertyValue( _newPropertyValue )
731             {
732             }
733         };
734     }
735 
736     //--------------------------------------------------------------------
737     void SAL_CALL ShapeGeometryChangeNotifier::propertyChange( const PropertyChangeEvent& _event ) throw (RuntimeException)
738     {
739         ::comphelper::ComponentMethodGuard aGuard( *this );
740 
741         ::std::vector< EventTranslation > aEventTranslations;
742         aEventTranslations.reserve(2);
743 
744         if ( _event.PropertyName.equalsAscii( "Position" ) )
745         {
746             AwtPoint aPos = m_xShape->getPosition();
747             aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONX, makeAny( aPos.X ) ) );
748             aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONY, makeAny( aPos.Y ) ) );
749         }
750         else if ( _event.PropertyName.equalsAscii( "Size" ) )
751         {
752             AwtSize aSize = m_xShape->getSize();
753             aEventTranslations.push_back( EventTranslation( PROPERTY_WIDTH, makeAny( aSize.Width ) ) );
754             aEventTranslations.push_back( EventTranslation( PROPERTY_HEIGHT, makeAny( aSize.Height ) ) );
755         }
756         else if ( _event.PropertyName == PROPERTY_ANCHOR_TYPE )
757         {
758             aEventTranslations.push_back( EventTranslation( PROPERTY_TEXT_ANCHOR_TYPE, makeAny( _event.NewValue ) ) );
759         }
760         else if ( _event.PropertyName == PROPERTY_ANCHOR )
761         {
762             aEventTranslations.push_back( EventTranslation( PROPERTY_SHEET_ANCHOR_TYPE, makeAny( _event.NewValue ) ) );
763         }
764 
765         PropertyChangeEvent aTranslatedEvent( _event );
766         aTranslatedEvent.Source = m_rParent;
767 
768         aGuard.clear();
769         for ( ::std::vector< EventTranslation >::const_iterator t = aEventTranslations.begin();
770               t != aEventTranslations.end();
771               ++t
772             )
773         {
774             aTranslatedEvent.PropertyName = t->sPropertyName;
775             aTranslatedEvent.NewValue = t->aNewPropertyValue;
776             m_aPropertyChangeListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent );
777         }
778     }
779 
780     //--------------------------------------------------------------------
781     void SAL_CALL ShapeGeometryChangeNotifier::disposing( const EventObject& /*_event*/ ) throw (RuntimeException)
782     {
783         ::comphelper::ComponentMethodGuard aGuard( *this );
784         impl_dispose_nothrow();
785     }
786 
787     //--------------------------------------------------------------------
788     void ShapeGeometryChangeNotifier::impl_init_nothrow()
789     {
790         osl_incrementInterlockedCount( &m_refCount );
791         try
792         {
793             Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
794             xShapeProperties->addPropertyChangeListener( ::rtl::OUString(), this );
795         }
796         catch( const Exception& )
797         {
798         	DBG_UNHANDLED_EXCEPTION();
799         }
800         osl_decrementInterlockedCount( &m_refCount );
801     }
802 
803     //--------------------------------------------------------------------
804     void ShapeGeometryChangeNotifier::impl_dispose_nothrow()
805     {
806         try
807         {
808             Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
809             xShapeProperties->removePropertyChangeListener( ::rtl::OUString(), this );
810         }
811         catch( const Exception& )
812         {
813         	DBG_UNHANDLED_EXCEPTION();
814         }
815 
816         getBroadcastHelper().bDisposed = true;
817     }
818 
819 //........................................................................
820 } // namespace pcr
821 //........................................................................
822 
823 extern "C" void SAL_CALL createRegistryInfo_FormGeometryHandler()
824 {
825     ::pcr::FormGeometryHandler::registerImplementation();
826 }
827