summaryrefslogtreecommitdiffstats
path: root/extensions/source/propctrlr/formgeometryhandler.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/propctrlr/formgeometryhandler.cxx')
-rw-r--r--extensions/source/propctrlr/formgeometryhandler.cxx820
1 files changed, 820 insertions, 0 deletions
diff --git a/extensions/source/propctrlr/formgeometryhandler.cxx b/extensions/source/propctrlr/formgeometryhandler.cxx
new file mode 100644
index 000000000..26c432405
--- /dev/null
+++ b/extensions/source/propctrlr/formgeometryhandler.cxx
@@ -0,0 +1,820 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "propertyhandler.hxx"
+#include "formmetadata.hxx"
+#include "formstrings.hxx"
+#include "handlerhelper.hxx"
+#include "cellbindinghelper.hxx"
+
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/container/XMap.hpp>
+#include <com/sun/star/inspection/XNumericControl.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/componentbase.hxx>
+#include <rtl/ref.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace pcr
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::awt::XControlModel;
+ using ::com::sun::star::drawing::XControlShape;
+ using ::com::sun::star::container::XMap;
+ using ::com::sun::star::inspection::LineDescriptor;
+ using ::com::sun::star::inspection::XPropertyControlFactory;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::beans::Optional;
+ using ::com::sun::star::inspection::XNumericControl;
+ using ::com::sun::star::drawing::XShape;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::text::TextContentAnchorType;
+ using ::com::sun::star::text::TextContentAnchorType_AT_PARAGRAPH;
+ using ::com::sun::star::text::TextContentAnchorType_AS_CHARACTER;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::inspection::XObjectInspectorUI;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::sheet::XSpreadsheet;
+ using ::com::sun::star::table::XColumnRowRange;
+ using ::com::sun::star::table::XTableColumns;
+ using ::com::sun::star::table::XTableRows;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::form::XGridColumnFactory;
+
+ namespace MeasureUnit = css::util::MeasureUnit;
+
+ #define ANCHOR_TO_SHEET 0
+ #define ANCHOR_TO_CELL 1
+
+
+ //= BroadcastHelperBase
+
+ namespace {
+
+ class BroadcastHelperBase
+ {
+ protected:
+ explicit BroadcastHelperBase( ::osl::Mutex& _rMutex )
+ :maBHelper( _rMutex )
+ {
+ }
+
+ protected:
+ ::cppu::OBroadcastHelper& getBroadcastHelper() { return maBHelper; }
+
+ private:
+ ::cppu::OBroadcastHelper maBHelper;
+ };
+
+ }
+
+ //= ShapeGeometryChangeNotifier - declaration
+
+ /** helper class to work around the ...unfortunate implementation of property change broadcasts
+ in the XShape implementation, which broadcasts way too generous and unspecified
+ */
+ typedef ::comphelper::ComponentBase ShapeGeometryChangeNotifier_CBase;
+ typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener
+ > ShapeGeometryChangeNotifier_IBase;
+
+ namespace {
+
+ class ShapeGeometryChangeNotifier :public BroadcastHelperBase
+ ,public ShapeGeometryChangeNotifier_CBase
+ ,public ShapeGeometryChangeNotifier_IBase
+ {
+ public:
+ ShapeGeometryChangeNotifier( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rParentMutex, const Reference< XShape >& _shape )
+ :BroadcastHelperBase( _rParentMutex )
+ ,ShapeGeometryChangeNotifier_CBase( BroadcastHelperBase::getBroadcastHelper(), ::comphelper::ComponentBase::NoInitializationNeeded() )
+ ,m_rParent( _rParent )
+ ,m_aPropertyChangeListeners( _rParentMutex )
+ ,m_xShape( _shape )
+ {
+ ENSURE_OR_THROW( m_xShape.is(), "illegal shape!" );
+ impl_init_nothrow();
+ }
+
+ // property change broadcasting
+ void addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ m_aPropertyChangeListeners.addInterface( _listener );
+ }
+ void removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ m_aPropertyChangeListeners.removeInterface( _listener );
+ }
+
+ // XComponent equivalent
+ void dispose()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ impl_dispose_nothrow();
+ }
+
+ // XInterface
+ virtual void SAL_CALL acquire( ) noexcept override
+ {
+ m_rParent.acquire();
+ }
+
+ virtual void SAL_CALL release( ) noexcept override
+ {
+ m_rParent.release();
+ }
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& _event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& _event ) override;
+
+ protected:
+ virtual ~ShapeGeometryChangeNotifier() override
+ {
+ if ( !getBroadcastHelper().bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+ protected:
+ ::cppu::OBroadcastHelper& getBroadcastHelper() { return BroadcastHelperBase::getBroadcastHelper(); }
+
+ private:
+ void impl_init_nothrow();
+ void impl_dispose_nothrow();
+
+ private:
+ ::cppu::OWeakObject& m_rParent;
+ ::comphelper::OInterfaceContainerHelper2 m_aPropertyChangeListeners;
+ Reference< XShape > m_xShape;
+ };
+
+ }
+
+ //= FormGeometryHandler - declaration
+
+ namespace {
+
+ class FormGeometryHandler;
+
+ }
+
+ /** a property handler for any virtual string properties
+ */
+
+ namespace {
+
+ class FormGeometryHandler : public PropertyHandlerComponent
+ {
+ public:
+ explicit FormGeometryHandler(
+ const Reference< XComponentContext >& _rxContext
+ );
+
+ protected:
+ virtual ~FormGeometryHandler() override;
+
+ protected:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XPropertyHandler overriables
+ virtual Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) override;
+ virtual LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override;
+ virtual Sequence< OUString > SAL_CALL getActuatingProperties( ) override;
+ virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override;
+
+ // OComponentHandler overridables
+ virtual void SAL_CALL disposing() override;
+
+ // PropertyHandler overridables
+ virtual Sequence< Property > doDescribeSupportedProperties() const override;
+
+ protected:
+ virtual void onNewComponent() override;
+
+ private:
+ bool impl_haveTextAnchorType_nothrow() const;
+ bool impl_haveSheetAnchorType_nothrow() const;
+ void impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const;
+
+ private:
+ Reference< XControlShape > m_xAssociatedShape;
+ Reference< XPropertySet > m_xShapeProperties;
+ ::rtl::Reference< ShapeGeometryChangeNotifier > m_xChangeNotifier;
+ };
+
+ }
+
+ //= FormGeometryHandler - implementation
+
+
+ FormGeometryHandler::FormGeometryHandler( const Reference< XComponentContext >& _rxContext )
+ :PropertyHandlerComponent( _rxContext )
+ {
+ }
+
+
+ FormGeometryHandler::~FormGeometryHandler( )
+ {
+ if ( !rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+
+ }
+
+
+ void FormGeometryHandler::onNewComponent()
+ {
+ if ( m_xChangeNotifier.is() )
+ {
+ m_xChangeNotifier->dispose();
+ m_xChangeNotifier.clear();
+ }
+ m_xAssociatedShape.clear();
+ m_xShapeProperties.clear();
+
+ PropertyHandlerComponent::onNewComponent();
+
+ try
+ {
+ Reference< XControlModel > xControlModel( m_xComponent, UNO_QUERY );
+ if ( xControlModel.is() )
+ {
+ // do not ask the map for shapes for grid control columns...
+ Reference< XChild > xCompChild( m_xComponent, UNO_QUERY_THROW );
+ Reference< XGridColumnFactory > xCheckGrid( xCompChild->getParent(), UNO_QUERY );
+ if ( !xCheckGrid.is() )
+ {
+ Reference< XMap > xControlMap;
+ Any any = m_xContext->getValueByName( "ControlShapeAccess" );
+ any >>= xControlMap;
+ m_xAssociatedShape.set( xControlMap->get( Any( xControlModel ) ), UNO_QUERY_THROW );
+ m_xShapeProperties.set( m_xAssociatedShape, UNO_QUERY_THROW );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ if ( m_xAssociatedShape.is() )
+ m_xChangeNotifier = new ShapeGeometryChangeNotifier( *this, m_aMutex, m_xAssociatedShape );
+ }
+
+
+ OUString FormGeometryHandler::getImplementationName( )
+ {
+ return "com.sun.star.comp.extensions.FormGeometryHandler";
+ }
+
+
+ Sequence< OUString > FormGeometryHandler::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.inspection.FormGeometryHandler" };
+ }
+
+
+ Any SAL_CALL FormGeometryHandler::getPropertyValue( const OUString& _rPropertyName )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
+ ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: no shape properties!", *this );
+
+ Any aReturn;
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_POSITIONX:
+ aReturn <<= m_xAssociatedShape->getPosition().X;
+ break;
+ case PROPERTY_ID_POSITIONY:
+ aReturn <<= m_xAssociatedShape->getPosition().Y;
+ break;
+ case PROPERTY_ID_WIDTH:
+ aReturn <<= m_xAssociatedShape->getSize().Width;
+ break;
+ case PROPERTY_ID_HEIGHT:
+ aReturn <<= m_xAssociatedShape->getSize().Height;
+ break;
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ aReturn = m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR_TYPE );
+ OSL_ENSURE( aReturn.hasValue(), "FormGeometryHandler::getPropertyValue: illegal anchor type!" );
+ break;
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ {
+ Reference< XSpreadsheet > xAnchorSheet( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ), UNO_QUERY );
+ aReturn <<= sal_Int32( xAnchorSheet.is() ? ANCHOR_TO_SHEET : ANCHOR_TO_CELL );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return aReturn;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this );
+ ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: properties, but no shape!", *this );
+
+ try
+ {
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_POSITIONX:
+ case PROPERTY_ID_POSITIONY:
+ {
+ sal_Int32 nPosition(0);
+ OSL_VERIFY( _rValue >>= nPosition );
+
+ css::awt::Point aPos( m_xAssociatedShape->getPosition() );
+ if ( nPropId == PROPERTY_ID_POSITIONX )
+ aPos.X = nPosition;
+ else
+ aPos.Y = nPosition;
+ m_xAssociatedShape->setPosition( aPos );
+ }
+ break;
+
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HEIGHT:
+ {
+ sal_Int32 nSize(0);
+ OSL_VERIFY( _rValue >>= nSize );
+
+ css::awt::Size aSize( m_xAssociatedShape->getSize() );
+ if ( nPropId == PROPERTY_ID_WIDTH )
+ aSize.Width = nSize;
+ else
+ aSize.Height = nSize;
+ m_xAssociatedShape->setSize( aSize );
+ }
+ break;
+
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR_TYPE, _rValue );
+ break;
+
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ {
+ sal_Int32 nSheetAnchorType = 0;
+ OSL_VERIFY( _rValue >>= nSheetAnchorType );
+ impl_setSheetAnchorType_nothrow( nSheetAnchorType );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ LineDescriptor SAL_CALL FormGeometryHandler::describePropertyLine( const OUString& _rPropertyName,
+ const Reference< XPropertyControlFactory >& _rxControlFactory )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) );
+
+ LineDescriptor aLineDesc( PropertyHandler::describePropertyLine( _rPropertyName, _rxControlFactory ) );
+ try
+ {
+ bool bIsSize = false;
+ switch ( nPropId )
+ {
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HEIGHT:
+ bIsSize = true;
+ [[fallthrough]];
+ case PROPERTY_ID_POSITIONX:
+ case PROPERTY_ID_POSITIONY:
+ {
+ Optional< double > aZero( true, 0 );
+ Optional< double > aValueNotPresent( false, 0 );
+ aLineDesc.Control = PropertyHandlerHelper::createNumericControl(
+ _rxControlFactory, 2, bIsSize ? aZero : aValueNotPresent, aValueNotPresent );
+
+ Reference< XNumericControl > xNumericControl( aLineDesc.Control, UNO_QUERY_THROW );
+ xNumericControl->setValueUnit( MeasureUnit::MM_100TH );
+ xNumericControl->setDisplayUnit( impl_getDocumentMeasurementUnit_throw() );
+ }
+ break;
+
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ case PROPERTY_ID_SHEET_ANCHOR_TYPE:
+ // default handling from PropertyHandler is sufficient
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::describePropertyLine: huh?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return aLineDesc;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::addPropertyChangeListener: no notified, implies no shape!?" );
+ if ( m_xChangeNotifier.is() )
+ m_xChangeNotifier->addPropertyChangeListener( _listener );
+ }
+
+
+ void SAL_CALL FormGeometryHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::removePropertyChangeListener: no notified, implies no shape!?" );
+ if ( m_xChangeNotifier.is() )
+ m_xChangeNotifier->removePropertyChangeListener( _listener );
+ }
+
+
+ Sequence< OUString > SAL_CALL FormGeometryHandler::getActuatingProperties( )
+ {
+ Sequence< OUString > aInterestedIn { PROPERTY_TEXT_ANCHOR_TYPE };
+ return aInterestedIn;
+ }
+
+
+ void SAL_CALL FormGeometryHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ )
+ {
+ if ( !_rxInspectorUI.is() )
+ throw NullPointerException();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ PropertyId nActuatingPropId( impl_getPropertyId_nothrow( _rActuatingPropertyName ) );
+
+ switch ( nActuatingPropId )
+ {
+ case PROPERTY_ID_TEXT_ANCHOR_TYPE:
+ {
+ TextContentAnchorType eAnchorType( TextContentAnchorType_AT_PARAGRAPH );
+ OSL_VERIFY( _rNewValue >>= eAnchorType );
+ _rxInspectorUI->enablePropertyUI( PROPERTY_POSITIONX, eAnchorType != TextContentAnchorType_AS_CHARACTER );
+ }
+ break;
+ case -1:
+ throw RuntimeException();
+ break;
+ default:
+ OSL_FAIL( "FormGeometryHandler::actuatingPropertyChanged: not registered for this property!" );
+ break;
+ }
+ }
+
+
+ Sequence< Property > FormGeometryHandler::doDescribeSupportedProperties() const
+ {
+ if ( !m_xAssociatedShape.is() )
+ return Sequence< Property >();
+
+ std::vector< Property > aProperties;
+
+ addInt32PropertyDescription( aProperties, PROPERTY_POSITIONX );
+ addInt32PropertyDescription( aProperties, PROPERTY_POSITIONY );
+ addInt32PropertyDescription( aProperties, PROPERTY_WIDTH );
+ addInt32PropertyDescription( aProperties, PROPERTY_HEIGHT );
+
+ if ( impl_haveTextAnchorType_nothrow() )
+ implAddPropertyDescription( aProperties, PROPERTY_TEXT_ANCHOR_TYPE, ::cppu::UnoType< TextContentAnchorType >::get() );
+
+ if ( impl_haveSheetAnchorType_nothrow() )
+ addInt32PropertyDescription( aProperties, PROPERTY_SHEET_ANCHOR_TYPE );
+
+ return comphelper::containerToSequence(aProperties);
+ }
+
+
+ void SAL_CALL FormGeometryHandler::disposing()
+ {
+ PropertyHandlerComponent::disposing();
+
+ if ( m_xChangeNotifier.is() )
+ {
+ m_xChangeNotifier->dispose();
+ m_xChangeNotifier.clear();
+ }
+ }
+
+
+ bool FormGeometryHandler::impl_haveTextAnchorType_nothrow() const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( PROPERTY_ANCHOR_TYPE ) )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return false;
+ }
+
+
+ bool FormGeometryHandler::impl_haveSheetAnchorType_nothrow() const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xPSI->hasPropertyByName( PROPERTY_ANCHOR ) )
+ return false;
+ Reference< XServiceInfo > xSI( m_xAssociatedShape, UNO_QUERY_THROW );
+ if ( xSI->supportsService("com.sun.star.sheet.Shape") )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ return false;
+ }
+
+
+ namespace
+ {
+ sal_Int32 lcl_getLowerBoundRowOrColumn( const Reference< XIndexAccess >& _rxRowsOrColumns, const bool _bRows,
+ const css::awt::Point& _rRelativePosition )
+ {
+ sal_Int32 nAccumulated = 0;
+
+ const sal_Int32& rRelativePos = _bRows ? _rRelativePosition.Y : _rRelativePosition.X;
+
+ sal_Int32 nElements = _rxRowsOrColumns->getCount();
+ sal_Int32 currentPos = 0;
+ for ( currentPos=0; currentPos<nElements; ++currentPos )
+ {
+ Reference< XPropertySet > xRowOrColumn( _rxRowsOrColumns->getByIndex( currentPos ), UNO_QUERY_THROW );
+
+ bool bIsVisible = true;
+ OSL_VERIFY( xRowOrColumn->getPropertyValue( PROPERTY_IS_VISIBLE ) >>= bIsVisible );
+ if ( !bIsVisible )
+ continue;
+
+ sal_Int32 nHeightOrWidth( 0 );
+ OSL_VERIFY( xRowOrColumn->getPropertyValue( _bRows ? OUString(PROPERTY_HEIGHT) : OUString(PROPERTY_WIDTH) ) >>= nHeightOrWidth );
+
+ if ( nAccumulated + nHeightOrWidth > rRelativePos )
+ break;
+
+ nAccumulated += nHeightOrWidth;
+ }
+
+ return currentPos;
+ }
+ }
+
+
+ void FormGeometryHandler::impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const
+ {
+ ENSURE_OR_THROW( m_xShapeProperties.is(), "illegal to be called without shape properties." );
+ try
+ {
+ CellBindingHelper aHelper( m_xComponent, impl_getContextDocument_nothrow() );
+ // find the sheet which the control belongs to
+ Reference< XSpreadsheet > xSheet;
+ aHelper.getControlSheetIndex( xSheet );
+
+ switch ( _nAnchorType )
+ {
+ case ANCHOR_TO_SHEET:
+ OSL_ENSURE( xSheet.is(),
+ "FormGeometryHandler::impl_setSheetAnchorType_nothrow: sheet not found!" );
+ if ( xSheet.is() )
+ {
+ css::awt::Point aPreservePosition( m_xAssociatedShape->getPosition() );
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, Any( xSheet ) );
+ m_xAssociatedShape->setPosition( aPreservePosition );
+ }
+ break;
+
+ case ANCHOR_TO_CELL:
+ {
+ Reference< XColumnRowRange > xColsRows( xSheet, UNO_QUERY_THROW );
+
+ // get the current anchor
+ Reference< XSpreadsheet > xCurrentAnchor;
+ OSL_VERIFY( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ) >>= xCurrentAnchor );
+ OSL_ENSURE( xCurrentAnchor.is(), "FormGeometryHandler::impl_setSheetAnchorType_nothrow: only to be called when currently anchored to a sheet!" );
+
+ // get the current position
+ css::awt::Point aRelativePosition( m_xAssociatedShape->getPosition() );
+
+ Reference< XTableColumns > xCols( xColsRows->getColumns(), UNO_SET_THROW );
+ sal_Int32 nNewAnchorCol = lcl_getLowerBoundRowOrColumn( xCols, false, aRelativePosition );
+
+ Reference< XTableRows > xRows( xColsRows->getRows(), UNO_SET_THROW );
+ sal_Int32 nNewAnchorRow = lcl_getLowerBoundRowOrColumn( xRows, true, aRelativePosition );
+
+ Any aNewAnchorCell( xSheet->getCellByPosition( nNewAnchorCol, nNewAnchorRow ) );
+ m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, aNewAnchorCell );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "FormGeometryHandler::impl_setSheetAnchorType_nothrow: illegal anchor type!" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ }
+
+
+ //= ShapeGeometryChangeNotifier - implementation
+
+ namespace
+ {
+ struct EventTranslation
+ {
+ OUString sPropertyName;
+ Any aNewPropertyValue;
+
+ EventTranslation( const OUString& _propertyName, const Any& _newPropertyValue )
+ :sPropertyName( _propertyName )
+ ,aNewPropertyValue( _newPropertyValue )
+ {
+ }
+ };
+ }
+
+
+ void SAL_CALL ShapeGeometryChangeNotifier::propertyChange( const PropertyChangeEvent& _event )
+ {
+ ::comphelper::ComponentMethodGuard aGuard( *this );
+
+ std::vector< EventTranslation > aEventTranslations;
+ aEventTranslations.reserve(2);
+
+ if ( _event.PropertyName == "Position" )
+ {
+ css::awt::Point aPos = m_xShape->getPosition();
+ aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONX, Any( aPos.X ) ) );
+ aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONY, Any( aPos.Y ) ) );
+ }
+ else if ( _event.PropertyName == "Size" )
+ {
+ css::awt::Size aSize = m_xShape->getSize();
+ aEventTranslations.push_back( EventTranslation( PROPERTY_WIDTH, Any( aSize.Width ) ) );
+ aEventTranslations.push_back( EventTranslation( PROPERTY_HEIGHT, Any( aSize.Height ) ) );
+ }
+ else if ( _event.PropertyName == PROPERTY_ANCHOR_TYPE )
+ {
+ aEventTranslations.push_back( EventTranslation( PROPERTY_TEXT_ANCHOR_TYPE, _event.NewValue ) );
+ }
+ else if ( _event.PropertyName == PROPERTY_ANCHOR )
+ {
+ aEventTranslations.push_back( EventTranslation( PROPERTY_SHEET_ANCHOR_TYPE, _event.NewValue ) );
+ }
+
+ PropertyChangeEvent aTranslatedEvent( _event );
+ aTranslatedEvent.Source = m_rParent;
+
+ aGuard.clear();
+ for (auto const& eventTranslation : aEventTranslations)
+ {
+ aTranslatedEvent.PropertyName = eventTranslation.sPropertyName;
+ aTranslatedEvent.NewValue = eventTranslation.aNewPropertyValue;
+ m_aPropertyChangeListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent );
+ }
+ }
+
+
+ void SAL_CALL ShapeGeometryChangeNotifier::disposing( const EventObject& /*_event*/ )
+ {
+ ::comphelper::ComponentMethodGuard aGuard( *this );
+ impl_dispose_nothrow();
+ }
+
+
+ void ShapeGeometryChangeNotifier::impl_init_nothrow()
+ {
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
+ xShapeProperties->addPropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ void ShapeGeometryChangeNotifier::impl_dispose_nothrow()
+ {
+ try
+ {
+ Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW );
+ xShapeProperties->removePropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
+ }
+
+ getBroadcastHelper().bDisposed = true;
+ }
+
+
+} // namespace pcr
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+extensions_propctrlr_FormGeometryHandler_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new pcr::FormGeometryHandler(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */