diff options
author | Philipp Lohmann [pl] <Philipp.Lohmann@Sun.COM> | 2010-04-01 16:51:09 +0200 |
---|---|---|
committer | Philipp Lohmann [pl] <Philipp.Lohmann@Sun.COM> | 2010-04-01 16:51:09 +0200 |
commit | ff9196d0581845f8e7cb686bf93930676ba301fe (patch) | |
tree | 82ccaa087cf88460ab2ccd8868b97ecf1ffac2f6 | |
parent | 96c1ee636435baf4ea84e7bffd9acb0bc0e9b787 (diff) |
gozer1: #161853# provide access to Window class and WindowArranger through XPropertySet
-rw-r--r-- | vcl/inc/vcl/arrange.hxx | 11 | ||||
-rw-r--r-- | vcl/inc/vcl/window.hxx | 44 | ||||
-rw-r--r-- | vcl/inc/vcl/wpropset.hxx | 66 | ||||
-rw-r--r-- | vcl/prj/d.lst | 4 | ||||
-rw-r--r-- | vcl/source/window/arrange.cxx | 62 | ||||
-rw-r--r-- | vcl/source/window/makefile.mk | 1 | ||||
-rw-r--r-- | vcl/source/window/window4.cxx | 150 | ||||
-rw-r--r-- | vcl/source/window/wpropset.cxx | 345 |
8 files changed, 581 insertions, 102 deletions
diff --git a/vcl/inc/vcl/arrange.hxx b/vcl/inc/vcl/arrange.hxx index 72e33f3c4bf8..24775995b013 100644 --- a/vcl/inc/vcl/arrange.hxx +++ b/vcl/inc/vcl/arrange.hxx @@ -104,6 +104,8 @@ namespace vcl Rectangle m_aManagedArea; long m_nOuterBorder; + rtl::OUString m_aIdentifier; + virtual Element* getElement( size_t i_nIndex ) = 0; const Element* getConstElement( size_t i_nIndex ) const { return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); } @@ -149,6 +151,9 @@ namespace vcl virtual bool isVisible() const; // true if any element is visible + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const; + virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& ); + sal_Int32 getExpandPriority( size_t i_nIndex ) const { const Element* pEle = getConstElement( i_nIndex ); @@ -195,6 +200,12 @@ namespace vcl m_nOuterBorder = i_nBorder; resize(); } + + const rtl::OUString getIdentifier() const + { return m_aIdentifier; } + + void setIdentifier( const rtl::OUString& i_rId ) + { m_aIdentifier = i_rId; } }; class VCL_DLLPUBLIC RowOrColumn : public WindowArranger diff --git a/vcl/inc/vcl/window.hxx b/vcl/inc/vcl/window.hxx index c757a20aece9..9516350527df 100644 --- a/vcl/inc/vcl/window.hxx +++ b/vcl/inc/vcl/window.hxx @@ -99,6 +99,13 @@ namespace accessibility { namespace com { namespace sun { namespace star { +namespace beans { + class PropertyValue; +}}}} + +namespace com { +namespace sun { +namespace star { namespace rendering { class XCanvas; class XSpriteCanvas; @@ -1156,15 +1163,11 @@ public: // ExtImpl // layouting - boost::shared_ptr< vcl::WindowArranger > getLayout(); + boost::shared_ptr< vcl::WindowArranger > getLayout(); /* add a child Window addWindow will do the following things - insert the passed window into the child list (equivalent to i_pWin->SetParent( this )) - - assign a name to the passed window for identification purposes - the name is basically free style, only the '/' character must not be used as it is - used for concatenation to form hierarchical names - caution: the last non empty token repsctive to '/' will be the actual name used - mark the window as "owned", meaning that the added Window will be destroyed by the parent's desctructor. This means: do not pass in member windows or stack objects here. Do not cause @@ -1172,7 +1175,7 @@ public: to avoid ownership pass i_bTakeOwnership as "false" */ - void addWindow( Window* i_pWin, const rtl::OUString& i_rName, bool i_bTakeOwnership = true ); + void addWindow( Window* i_pWin, bool i_bTakeOwnership = true ); /* remove a child Window the remove window functions will @@ -1181,20 +1184,31 @@ public: caution: ownership passes to the new parent or the caller, if the new parent was NULL */ Window* removeWindow( Window* i_pWin, Window* i_pNewParent = NULL ); - /* removeWindow by name will only work for direct children. if i_rName - is a hierachical name, the last non empty token will be used to get the child window + + /* return the identifier of this window + */ + const rtl::OUString& getIdentifier() const; + /* set an identifier + identifiers have only loosely defined rules per se + in context of Window they must be unique over the window + hierarchy you'd like to find them again using the findWindow method */ - Window* removeWindow( const rtl::OUString& i_rName, Window* i_pNewParent = NULL ); + void setIdentifier( const rtl::OUString& ); - /* find a child window by name - the name passed here can be hierarchical to find descendants in any depth - path delimiter is '/' + /* returns the first found descendant that matches + the passed identifier or NULL */ - Window* findWindow( const rtl::OUString& i_rName ) const; + Window* findWindow( const rtl::OUString& ) const; - /* return the name of this window + /* get/set properties + this will contain window properties (like visible, enabled) + as well as properties of derived classes (e.g. text of Edit fields) */ - const rtl::OUString& getName() const; + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const; + /* + */ + virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& ); + }; diff --git a/vcl/inc/vcl/wpropset.hxx b/vcl/inc/vcl/wpropset.hxx new file mode 100644 index 000000000000..409b629496e6 --- /dev/null +++ b/vcl/inc/vcl/wpropset.hxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef VCL_WPROPSET_HXX +#define VCL_WPROPSET_HXX + +#include "vcl/dllapi.h" + +#include "tools/link.hxx" +#include "vcl/arrange.hxx" + +#include "com/sun/star/beans/XPropertySet.hpp" + +class VclWindowEvent; + +namespace vcl +{ + class WindowPropertySetData; + class WindowPropertySetListener; + + class VCL_DLLPUBLIC WindowPropertySet + { + WindowPropertySetData* mpImpl; + + void addWindowToSet( Window* ); + void addLayoutToSet( const boost::shared_ptr<WindowArranger>& ); + void setupProperties(); + + DECL_LINK( ChildEventListener, VclWindowEvent* ); + + void propertyChange( const com::sun::star::beans::PropertyChangeEvent& ); + friend class vcl::WindowPropertySetListener; + + public: + WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ); + ~WindowPropertySet(); + + com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > getPropertySet() const; + }; +} + +#endif diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst index 8345b155ce58..0f429d0f5ec6 100644 --- a/vcl/prj/d.lst +++ b/vcl/prj/d.lst @@ -153,4 +153,6 @@ mkdir: %_DEST%\inc%_EXT%\vcl ..\inc\vcl\ppdparser.hxx %_DEST%\inc%_EXT%\vcl\ppdparser.hxx ..\inc\vcl\helper.hxx %_DEST%\inc%_EXT%\vcl\helper.hxx ..\inc\vcl\strhelper.hxx %_DEST%\inc%_EXT%\vcl\strhelper.hxx -..\inc\vcl\lazydelete.hxx %_DEST%\inc%_EXT%\vcl\lazydelete.hxx
\ No newline at end of file +..\inc\vcl\lazydelete.hxx %_DEST%\inc%_EXT%\vcl\lazydelete.hxx +..\inc\vcl\arrange.hxx %_DEST%\inc%_EXT%\vcl\arrange.hxx +..\inc\vcl\wpropset.hxx %_DEST%\inc%_EXT%\vcl\wpropset.hxx
\ No newline at end of file diff --git a/vcl/source/window/arrange.cxx b/vcl/source/window/arrange.cxx index 64db5426dc5b..2a01758220ed 100644 --- a/vcl/source/window/arrange.cxx +++ b/vcl/source/window/arrange.cxx @@ -35,9 +35,13 @@ #include "vcl/svdata.hxx" #include "vcl/svapp.hxx" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/awt/Rectangle.hpp" + #include "osl/diagnose.h" using namespace vcl; +using namespace com::sun::star; // ---------------------------------------- // vcl::WindowArranger @@ -206,6 +210,64 @@ void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSi m_pChild->setManagedArea( Rectangle( aPoint, aSize ) ); } +uno::Sequence< beans::PropertyValue > WindowArranger::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aRet( 3 ); + aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OuterBorder" ) ); + aRet[0].Value = uno::makeAny( sal_Int32( getBorderValue( m_nOuterBorder ) ) ); + aRet[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ManagedArea" ) ); + awt::Rectangle aArea( m_aManagedArea.getX(), m_aManagedArea.getY(), m_aManagedArea.getWidth(), m_aManagedArea.getHeight() ); + aRet[1].Value = uno::makeAny( aArea ); + aRet[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aRet[2].Value = uno::makeAny( sal_Bool( isVisible() ) ); + return aRet; +} + +void WindowArranger::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pProps = i_rProps.getConstArray(); + bool bResize = false; + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) + { + if( pProps[i].Name.equalsAscii( "OuterBorder" ) ) + { + sal_Int32 nVal = 0; + if( pProps[i].Value >>= nVal ) + { + if( getBorderValue( m_nOuterBorder ) != nVal ) + { + m_nOuterBorder = nVal; + bResize = true; + } + } + } + else if( pProps[i].Name.equalsAscii( "ManagedArea" ) ) + { + awt::Rectangle aArea( 0, 0, 0, 0 ); + if( pProps[i].Value >>= aArea ) + { + m_aManagedArea.setX( aArea.X ); + m_aManagedArea.setY( aArea.Y ); + m_aManagedArea.setWidth( aArea.Width ); + m_aManagedArea.setHeight( aArea.Height ); + bResize = true; + } + } + else if( pProps[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_False; + if( pProps[i].Value >>= bVal ) + { + show( bVal, false ); + bResize = true; + } + } + } + if( bResize ) + resize(); +} + + // ---------------------------------------- // vcl::RowOrColumn //----------------------------------------- diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk index e74623ad0a03..3614e166537c 100644 --- a/vcl/source/window/makefile.mk +++ b/vcl/source/window/makefile.mk @@ -90,6 +90,7 @@ SLOFILES= \ $(SLO)$/window2.obj \ $(SLO)$/window3.obj \ $(SLO)$/window4.obj \ + $(SLO)$/wpropset.obj \ $(SLO)$/wrkwin.obj # --- Targets ------------------------------------------------------ diff --git a/vcl/source/window/window4.cxx b/vcl/source/window/window4.cxx index 587a99376943..577a573c2015 100644 --- a/vcl/source/window/window4.cxx +++ b/vcl/source/window/window4.cxx @@ -29,9 +29,15 @@ #include "vcl/window.hxx" #include "vcl/window.h" +#include "vcl/svdata.hxx" #include "vcl/arrange.hxx" +#include "com/sun/star/beans/PropertyValue.hpp" + #include <map> +#include <vector> + +using namespace com::sun::star; namespace vcl { @@ -45,60 +51,8 @@ namespace vcl boost::shared_ptr< WindowArranger > mxLayout; bool mbOwnedByParent; - rtl::OUString maName; - std::map< rtl::OUString, Window* > maNameToWindow; - std::map< Window*, rtl::OUString > maWindowToName; - - void insertName( const rtl::OUString& i_rName, Window* i_pWin ); - void removeWindow( Window* ); - Window* findName( const rtl::OUString& ) const; + rtl::OUString maIdentifier; }; - - void ExtWindowImpl::insertName( const rtl::OUString& i_rName, Window* i_pWin ) - { - OSL_ENSURE( maNameToWindow.find( i_rName ) == maNameToWindow.end(), "duplicate named window inserted" ); - maNameToWindow[ i_rName ] = i_pWin; - maWindowToName[ i_pWin ] = i_rName; - } - - void ExtWindowImpl::removeWindow( Window* i_pWin ) - { - std::map< Window*, rtl::OUString >::iterator it = maWindowToName.find( i_pWin ); - if( it != maWindowToName.end() ) - { - maNameToWindow.erase( it->second ); - maWindowToName.erase( it ); - } - } - - Window* ExtWindowImpl::findName( const rtl::OUString& i_rName ) const - { - std::map< rtl::OUString, Window* >::const_iterator it = maNameToWindow.find( i_rName ); - return it != maNameToWindow.end() ? it->second : NULL; - } -} - -static rtl::OUString getLastNameToken( const rtl::OUString& i_rName ) -{ - sal_Int32 nIndex = i_rName.lastIndexOf( sal_Unicode('/') ); - if( nIndex != -1 ) - { - // if this is not an empty token, that is the name - if( nIndex < i_rName.getLength()-1 ) - return i_rName.copy( nIndex+1 ); - // we need to search backward - const sal_Unicode* pStr = i_rName.getStr(); - while( nIndex >= 0 && pStr[nIndex] == '/' ) - nIndex--; - if( nIndex < 0 ) // give up - return rtl::OUString(); - // search backward to next '/' or beginning - sal_Int32 nBeginIndex = nIndex-1; - while( nBeginIndex >= 0 && pStr[nBeginIndex] != '/' ) - nBeginIndex--; - return i_rName.copy( nBeginIndex+1, nIndex-nBeginIndex ); - } - return rtl::OUString( i_rName ); } void Window::ImplDeleteOwnedChildren() @@ -163,7 +117,7 @@ boost::shared_ptr< vcl::WindowArranger > Window::getLayout() return xRet; } -void Window::addWindow( Window* i_pWin, const rtl::OUString& i_rName, bool i_bTakeOwnership ) +void Window::addWindow( Window* i_pWin, bool i_bTakeOwnership ) { vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); if( pImpl && i_pWin ) @@ -173,11 +127,6 @@ void Window::addWindow( Window* i_pWin, const rtl::OUString& i_rName, bool i_bTa { i_pWin->SetParent( this ); pChildImpl->mbOwnedByParent = i_bTakeOwnership; - rtl::OUString aName( getLastNameToken( i_rName ) ); - if( aName.getLength() ) - { - pImpl->insertName( aName, i_pWin ); - } } } } @@ -195,7 +144,6 @@ Window* Window::removeWindow( Window* i_pWin, Window* i_pNewParent ) { if( ! i_pNewParent ) pChildImpl->mbOwnedByParent = false; - pImpl->removeWindow( i_pWin ); i_pWin->SetParent( i_pNewParent ); pRet = i_pWin; } @@ -204,43 +152,73 @@ Window* Window::removeWindow( Window* i_pWin, Window* i_pNewParent ) return pRet; } -Window* Window::removeWindow( const rtl::OUString& i_rName, Window* i_pNewParent ) +Window* Window::findWindow( const rtl::OUString& i_rIdentifier ) const { - Window* pRet = NULL; - vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); - if( pImpl ) + if( getIdentifier() == i_rIdentifier ) + return const_cast<Window*>(this); + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) { - rtl::OUString aName( getLastNameToken( i_rName ) ); - pRet = pImpl->findName( aName ); - pRet = removeWindow( pRet, i_pNewParent ); + Window* pResult = pChild->findWindow( i_rIdentifier ); + if( pResult ) + return pResult; + pChild = pChild->mpWindowImpl->mpNext; } - return pRet; + + return NULL; +} + +const rtl::OUString& Window::getIdentifier() const +{ + static rtl::OUString aEmptyStr; + + return (mpWindowImpl && mpWindowImpl->mpExtImpl) ? mpWindowImpl->mpExtImpl->maIdentifier : aEmptyStr; } -Window* Window::findWindow( const rtl::OUString& i_rName ) const +void Window::setIdentifier( const rtl::OUString& i_rIdentifier ) { vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); - Window* pSearch = const_cast<Window*>(this); if( pImpl ) + pImpl->maIdentifier = i_rIdentifier; +} + +void Window::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pVals = i_rProps.getConstArray(); + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) { - sal_Int32 nIndex = 0; - while( nIndex && pSearch ) + if( pVals[i].Name.equalsAscii( "Enabled" ) ) { - rtl::OUString aName( i_rName.getToken( 0, '/', nIndex ) ); - if( aName.getLength() ) - { - pSearch = pImpl->findName( aName ); - if( pSearch ) - { - pImpl = pSearch->ImplGetExtWindowImpl(); - if( ! pImpl ) - pSearch = NULL; - } - } + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Enable( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Show( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Text" ) ) + { + rtl::OUString aText; + if( pVals[i].Value >>= aText ) + SetText( aText ); } } - else - pSearch = NULL; - return pSearch != this ? pSearch : NULL; +} + +uno::Sequence< beans::PropertyValue > Window::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aProps( 3 ); + aProps[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); + aProps[0].Value = uno::makeAny( sal_Bool( IsEnabled() ) ); + aProps[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aProps[1].Value = uno::makeAny( sal_Bool( IsVisible() ) ); + aProps[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); + aProps[2].Value = uno::makeAny( rtl::OUString( GetText() ) ); + + return aProps; } diff --git a/vcl/source/window/wpropset.cxx b/vcl/source/window/wpropset.cxx new file mode 100644 index 000000000000..98c8a5b1dcfb --- /dev/null +++ b/vcl/source/window/wpropset.cxx @@ -0,0 +1,345 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/wpropset.hxx" +#include "vcl/window.hxx" +#include "vcl/vclevent.hxx" +#include "vcl/svdata.hxx" + +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/beans/PropertyAttribute.hpp" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/beans/XPropertyContainer.hpp" +#include "com/sun/star/beans/XPropertyAccess.hpp" + +#include "cppuhelper/basemutex.hxx" +#include "cppuhelper/compbase1.hxx" + +#include <map> + +using namespace vcl; +using namespace com::sun::star; + +/* + +TODO: +- release solarmutex during outside UNO calls +- in ChildEventListener protect against reentry by using PostUserEvent + +*/ + +class vcl::WindowPropertySetListener : + public cppu::BaseMutex, + public cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >, + private boost::noncopyable +{ + WindowPropertySet* mpParent; + bool mbSuspended; +public: + WindowPropertySetListener( WindowPropertySet* pParent ) + : cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >( m_aMutex ) + , mpParent( pParent ) + , mbSuspended( false ) + {} + + virtual ~WindowPropertySetListener() + { + } + + virtual void SAL_CALL disposing( const lang::EventObject& ) throw() + { + } + + virtual void SAL_CALL propertyChange( const beans::PropertyChangeEvent& i_rEvent ) throw() + { + if( ! mbSuspended ) + mpParent->propertyChange( i_rEvent ); + } + + void suspend( bool i_bSuspended ) + { + mbSuspended = i_bSuspended; + } +}; + +class vcl::WindowPropertySetData +{ +public: + + struct PropertyMapEntry + { + Window* mpWindow; + boost::shared_ptr<WindowArranger> mpLayout; + uno::Sequence< beans::PropertyValue > maSavedValues; + + PropertyMapEntry( Window* i_pWindow = NULL, + const boost::shared_ptr<WindowArranger>& i_pLayout = boost::shared_ptr<WindowArranger>() ) + : mpWindow( i_pWindow ) + , mpLayout( i_pLayout ) + {} + + uno::Sequence< beans::PropertyValue > getProperties() const + { + if( mpWindow ) + return mpWindow->getProperties(); + else if( mpLayout.get() ) + return mpLayout->getProperties(); + return uno::Sequence< beans::PropertyValue >(); + } + + void setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) const + { + if( mpWindow ) + mpWindow->setProperties( i_rProps ); + else if( mpLayout.get() ) + mpLayout->setProperties( i_rProps ); + } + }; + + Window* mpTopWindow; + bool mbOwner; + std::map< rtl::OUString, PropertyMapEntry > maProperties; + uno::Reference< beans::XPropertySet > mxPropSet; + uno::Reference< beans::XPropertyAccess > mxPropSetAccess; + uno::Reference< beans::XPropertyChangeListener > mxListener; + vcl::WindowPropertySetListener* mpListener; + + WindowPropertySetData() + : mpTopWindow( NULL ) + , mbOwner( false ) + , mpListener( NULL ) + {} + + ~WindowPropertySetData() + { + // release layouters, possibly interface properties before destroying + // the involved parent to be on the safe side + maProperties.clear(); + if( mbOwner ) + delete mpTopWindow; + } +}; + +static rtl::OUString getIdentifiedPropertyName( const rtl::OUString& i_rIdentifier, const rtl::OUString& i_rName ) +{ + rtl::OUStringBuffer aBuf( i_rIdentifier.getLength() + 1 + i_rName.getLength() ); + aBuf.append( i_rIdentifier ); + aBuf.append( sal_Unicode( '#' ) ); + aBuf.append( i_rName ); + return aBuf.makeStringAndClear(); +} + +static void spliceIdentifiedPropertyName( const rtl::OUString& i_rIdentifiedPropName, + rtl::OUString& o_rIdentifier, + rtl::OUString& o_rPropName ) +{ + sal_Int32 nIndex = 0; + o_rIdentifier = i_rIdentifiedPropName.getToken( 0, sal_Unicode( '#' ), nIndex ); + if( nIndex != -1 ) + o_rPropName = i_rIdentifiedPropName.copy( nIndex ); + else + o_rPropName = rtl::OUString(); +} + +WindowPropertySet::WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ) +: mpImpl( new vcl::WindowPropertySetData ) +{ + mpImpl->mpTopWindow = i_pTopWindow; + mpImpl->mbOwner = i_bTakeOwnership; + + mpImpl->mpTopWindow->AddChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + mpImpl->mxPropSet = uno::Reference< beans::XPropertySet >( + ImplGetSVData()->maAppData.mxMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.PropertyBag" ) ) ), + uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not create instance of com.sun.star.beans.PropertyBag" ); + mpImpl->mxPropSetAccess = uno::Reference< beans::XPropertyAccess >( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not query XPropertyAccess interface" ); + if( ! mpImpl->mxPropSetAccess.is() ) + mpImpl->mxPropSet.clear(); + + addWindowToSet( i_pTopWindow ); + + setupProperties(); + + if( mpImpl->mxPropSet.is() ) + { + mpImpl->mxListener.set( mpImpl->mpListener = new WindowPropertySetListener( this ) ); + } +} + +WindowPropertySet::~WindowPropertySet() +{ + mpImpl->mpTopWindow->RemoveChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + delete mpImpl; + mpImpl = NULL; +} + +uno::Reference< beans::XPropertySet > WindowPropertySet::getPropertySet() const +{ + return mpImpl->mxPropSet; +} + +void WindowPropertySet::addLayoutToSet( const boost::shared_ptr< WindowArranger >& i_pLayout ) +{ + if( i_pLayout.get() ) + { + if( i_pLayout->getIdentifier().getLength() ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pLayout->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted layout has duplicate name" ); + rEntry.mpWindow = NULL; + rEntry.mpLayout = i_pLayout; + rEntry.maSavedValues = i_pLayout->getProperties(); + } + // insert child layouts + size_t nChildren = i_pLayout->countElements(); + for( size_t i = 0; i < nChildren; i++ ) + addLayoutToSet( i_pLayout->getChild( i ) ); + } +} + +void WindowPropertySet::addWindowToSet( Window* i_pWindow ) +{ + if( i_pWindow->getIdentifier().getLength() ) // no name, no properties + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pWindow->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted window has duplicate name" ); + rEntry.mpWindow = i_pWindow; + rEntry.mpLayout.reset(); + rEntry.maSavedValues = i_pWindow->getProperties(); + } + addLayoutToSet( i_pWindow->getLayout() ); + + Window* pWin = i_pWindow->GetWindow( WINDOW_FIRSTCHILD ); + while( pWin ) + { + addWindowToSet( pWin ); + pWin = pWin->GetWindow( WINDOW_NEXT ); + } +} + +void WindowPropertySet::setupProperties() +{ + uno::Reference< beans::XPropertyContainer > xCont( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( xCont.is(), "could not get XPropertyContainer interface" ); + if( ! xCont.is() ) + return; + + for( std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.begin(); it != mpImpl->maProperties.end(); ++it ) + { + uno::Sequence< beans::PropertyValue > aOutsideValues( it->second.maSavedValues ); + beans::PropertyValue* pVal = aOutsideValues.getArray(); + for( sal_Int32 i = 0; i < aOutsideValues.getLength(); i++ ) + { + pVal[i].Name = getIdentifiedPropertyName( it->first, pVal[i].Name ); + xCont->addProperty( pVal[i].Name, + beans::PropertyAttribute::BOUND | beans:: PropertyAttribute::CONSTRAINED, + pVal[i].Value + ); + } + } +} + +void WindowPropertySet::propertyChange( const beans::PropertyChangeEvent& i_rEvent ) +{ + rtl::OUString aIdentifier, aProperty; + spliceIdentifiedPropertyName( i_rEvent.PropertyName, aIdentifier, aProperty ); + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it = + mpImpl->maProperties.find( aIdentifier ); + if( it != mpImpl->maProperties.end() ) + { + uno::Sequence< beans::PropertyValue > aSet( 1 ); + aSet[0].Name = aProperty; + aSet[0].Value = i_rEvent.NewValue; + it->second.setProperties( aSet ); + } +} + +IMPL_LINK( vcl::WindowPropertySet, ChildEventListener, VclWindowEvent*, pEvent ) +{ + // find window in our properties + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.find( pEvent->GetWindow()->getIdentifier() ); + if( it != mpImpl->maProperties.end() ) // this is valid, some unnamed child may have sent an event + { + ULONG nId = pEvent->GetId(); + // check if anything interesting happened + if( + // general windowy things + nId == VCLEVENT_WINDOW_SHOW || + nId == VCLEVENT_WINDOW_HIDE || + nId == VCLEVENT_WINDOW_ENABLED || + nId == VCLEVENT_WINDOW_DISABLED || + // button thingies + nId == VCLEVENT_BUTTON_CLICK || + nId == VCLEVENT_PUSHBUTTON_TOGGLE || + nId == VCLEVENT_RADIOBUTTON_TOGGLE || + nId == VCLEVENT_CHECKBOX_TOGGLE || + // listbox + nId == VCLEVENT_LISTBOX_SELECT || + // edit + nId == VCLEVENT_EDIT_MODIFY + ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = it->second; + // collect changes + uno::Sequence< beans::PropertyValue > aNewProps( rEntry.getProperties() ); + uno::Sequence< beans::PropertyValue > aNewPropsOut( aNewProps ); + + // translate to identified properties + beans::PropertyValue* pValues = aNewPropsOut.getArray(); + for( sal_Int32 i = 0; i < aNewPropsOut.getLength(); i++ ) + pValues[i].Name = getIdentifiedPropertyName( it->first, pValues[i].Name ); + + // broadcast changes + bool bWasVeto = false; + mpImpl->mpListener->suspend( true ); + try + { + mpImpl->mxPropSetAccess->setPropertyValues( aNewPropsOut ); + } + catch( beans::PropertyVetoException& ) + { + bWasVeto = true; + } + mpImpl->mpListener->suspend( false ); + + if( ! bWasVeto ) // changes accepted ? + rEntry.maSavedValues = rEntry.getProperties(); + else // no, reset + rEntry.setProperties( rEntry.maSavedValues ); + } + } + + return 0; +} |