1*9f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*9f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*9f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*9f62ea84SAndrew Rist * distributed with this work for additional information 6*9f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*9f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*9f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 9*9f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*9f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*9f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*9f62ea84SAndrew Rist * software distributed under the License is distributed on an 15*9f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*9f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 17*9f62ea84SAndrew Rist * specific language governing permissions and limitations 18*9f62ea84SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*9f62ea84SAndrew Rist *************************************************************/ 21*9f62ea84SAndrew Rist 22*9f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "precompiled_vcl.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include "vcl/wpropset.hxx" 27cdf0e10cSrcweir #include "vcl/window.hxx" 28cdf0e10cSrcweir #include "vcl/vclevent.hxx" 29cdf0e10cSrcweir 30cdf0e10cSrcweir #include "svdata.hxx" 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include "com/sun/star/lang/XMultiServiceFactory.hpp" 33cdf0e10cSrcweir #include "com/sun/star/beans/PropertyValue.hpp" 34cdf0e10cSrcweir #include "com/sun/star/beans/PropertyAttribute.hpp" 35cdf0e10cSrcweir #include "com/sun/star/beans/XPropertySet.hpp" 36cdf0e10cSrcweir #include "com/sun/star/beans/XPropertyContainer.hpp" 37cdf0e10cSrcweir #include "com/sun/star/beans/XPropertyAccess.hpp" 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include "cppuhelper/basemutex.hxx" 40cdf0e10cSrcweir #include "cppuhelper/compbase1.hxx" 41cdf0e10cSrcweir 42cdf0e10cSrcweir #include <map> 43cdf0e10cSrcweir 44cdf0e10cSrcweir using namespace vcl; 45cdf0e10cSrcweir using namespace com::sun::star; 46cdf0e10cSrcweir 47cdf0e10cSrcweir /* 48cdf0e10cSrcweir 49cdf0e10cSrcweir TODO: 50cdf0e10cSrcweir - release solarmutex during outside UNO calls 51cdf0e10cSrcweir - in ChildEventListener protect against reentry by using PostUserEvent 52cdf0e10cSrcweir 53cdf0e10cSrcweir */ 54cdf0e10cSrcweir 55cdf0e10cSrcweir class vcl::WindowPropertySetListener : 56cdf0e10cSrcweir public cppu::BaseMutex, 57cdf0e10cSrcweir public cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >, 58cdf0e10cSrcweir private boost::noncopyable 59cdf0e10cSrcweir { 60cdf0e10cSrcweir WindowPropertySet* mpParent; 61cdf0e10cSrcweir bool mbSuspended; 62cdf0e10cSrcweir public: 63cdf0e10cSrcweir WindowPropertySetListener( WindowPropertySet* pParent ) 64cdf0e10cSrcweir : cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >( m_aMutex ) 65cdf0e10cSrcweir , mpParent( pParent ) 66cdf0e10cSrcweir , mbSuspended( false ) 67cdf0e10cSrcweir {} 68cdf0e10cSrcweir 69cdf0e10cSrcweir virtual ~WindowPropertySetListener() 70cdf0e10cSrcweir { 71cdf0e10cSrcweir } 72cdf0e10cSrcweir 73cdf0e10cSrcweir using cppu::WeakComponentImplHelperBase::disposing; 74cdf0e10cSrcweir virtual void SAL_CALL disposing( const lang::EventObject& ) throw() 75cdf0e10cSrcweir { 76cdf0e10cSrcweir } 77cdf0e10cSrcweir 78cdf0e10cSrcweir virtual void SAL_CALL propertyChange( const beans::PropertyChangeEvent& i_rEvent ) throw() 79cdf0e10cSrcweir { 80cdf0e10cSrcweir if( ! mbSuspended ) 81cdf0e10cSrcweir mpParent->propertyChange( i_rEvent ); 82cdf0e10cSrcweir } 83cdf0e10cSrcweir 84cdf0e10cSrcweir void suspend( bool i_bSuspended ) 85cdf0e10cSrcweir { 86cdf0e10cSrcweir mbSuspended = i_bSuspended; 87cdf0e10cSrcweir } 88cdf0e10cSrcweir }; 89cdf0e10cSrcweir 90cdf0e10cSrcweir class vcl::WindowPropertySetData 91cdf0e10cSrcweir { 92cdf0e10cSrcweir public: 93cdf0e10cSrcweir 94cdf0e10cSrcweir struct PropertyMapEntry 95cdf0e10cSrcweir { 96cdf0e10cSrcweir Window* mpWindow; 97cdf0e10cSrcweir boost::shared_ptr<WindowArranger> mpLayout; 98cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > maSavedValues; 99cdf0e10cSrcweir 100cdf0e10cSrcweir PropertyMapEntry( Window* i_pWindow = NULL, 101cdf0e10cSrcweir const boost::shared_ptr<WindowArranger>& i_pLayout = boost::shared_ptr<WindowArranger>() ) 102cdf0e10cSrcweir : mpWindow( i_pWindow ) 103cdf0e10cSrcweir , mpLayout( i_pLayout ) 104cdf0e10cSrcweir {} 105cdf0e10cSrcweir 106cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > getProperties() const 107cdf0e10cSrcweir { 108cdf0e10cSrcweir if( mpWindow ) 109cdf0e10cSrcweir return mpWindow->getProperties(); 110cdf0e10cSrcweir else if( mpLayout.get() ) 111cdf0e10cSrcweir return mpLayout->getProperties(); 112cdf0e10cSrcweir return uno::Sequence< beans::PropertyValue >(); 113cdf0e10cSrcweir } 114cdf0e10cSrcweir 115cdf0e10cSrcweir void setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) const 116cdf0e10cSrcweir { 117cdf0e10cSrcweir if( mpWindow ) 118cdf0e10cSrcweir mpWindow->setProperties( i_rProps ); 119cdf0e10cSrcweir else if( mpLayout.get() ) 120cdf0e10cSrcweir mpLayout->setProperties( i_rProps ); 121cdf0e10cSrcweir } 122cdf0e10cSrcweir }; 123cdf0e10cSrcweir 124cdf0e10cSrcweir Window* mpTopWindow; 125cdf0e10cSrcweir bool mbOwner; 126cdf0e10cSrcweir std::map< rtl::OUString, PropertyMapEntry > maProperties; 127cdf0e10cSrcweir uno::Reference< beans::XPropertySet > mxPropSet; 128cdf0e10cSrcweir uno::Reference< beans::XPropertyAccess > mxPropSetAccess; 129cdf0e10cSrcweir uno::Reference< beans::XPropertyChangeListener > mxListener; 130cdf0e10cSrcweir vcl::WindowPropertySetListener* mpListener; 131cdf0e10cSrcweir 132cdf0e10cSrcweir WindowPropertySetData() 133cdf0e10cSrcweir : mpTopWindow( NULL ) 134cdf0e10cSrcweir , mbOwner( false ) 135cdf0e10cSrcweir , mpListener( NULL ) 136cdf0e10cSrcweir {} 137cdf0e10cSrcweir 138cdf0e10cSrcweir ~WindowPropertySetData() 139cdf0e10cSrcweir { 140cdf0e10cSrcweir // release layouters, possibly interface properties before destroying 141cdf0e10cSrcweir // the involved parent to be on the safe side 142cdf0e10cSrcweir maProperties.clear(); 143cdf0e10cSrcweir if( mbOwner ) 144cdf0e10cSrcweir delete mpTopWindow; 145cdf0e10cSrcweir } 146cdf0e10cSrcweir }; 147cdf0e10cSrcweir 148cdf0e10cSrcweir static rtl::OUString getIdentifiedPropertyName( const rtl::OUString& i_rIdentifier, const rtl::OUString& i_rName ) 149cdf0e10cSrcweir { 150cdf0e10cSrcweir rtl::OUStringBuffer aBuf( i_rIdentifier.getLength() + 1 + i_rName.getLength() ); 151cdf0e10cSrcweir aBuf.append( i_rIdentifier ); 152cdf0e10cSrcweir aBuf.append( sal_Unicode( '#' ) ); 153cdf0e10cSrcweir aBuf.append( i_rName ); 154cdf0e10cSrcweir return aBuf.makeStringAndClear(); 155cdf0e10cSrcweir } 156cdf0e10cSrcweir 157cdf0e10cSrcweir static void spliceIdentifiedPropertyName( const rtl::OUString& i_rIdentifiedPropName, 158cdf0e10cSrcweir rtl::OUString& o_rIdentifier, 159cdf0e10cSrcweir rtl::OUString& o_rPropName ) 160cdf0e10cSrcweir { 161cdf0e10cSrcweir sal_Int32 nIndex = 0; 162cdf0e10cSrcweir o_rIdentifier = i_rIdentifiedPropName.getToken( 0, sal_Unicode( '#' ), nIndex ); 163cdf0e10cSrcweir if( nIndex != -1 ) 164cdf0e10cSrcweir o_rPropName = i_rIdentifiedPropName.copy( nIndex ); 165cdf0e10cSrcweir else 166cdf0e10cSrcweir o_rPropName = rtl::OUString(); 167cdf0e10cSrcweir } 168cdf0e10cSrcweir 169cdf0e10cSrcweir WindowPropertySet::WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ) 170cdf0e10cSrcweir : mpImpl( new vcl::WindowPropertySetData ) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir mpImpl->mpTopWindow = i_pTopWindow; 173cdf0e10cSrcweir mpImpl->mbOwner = i_bTakeOwnership; 174cdf0e10cSrcweir 175cdf0e10cSrcweir mpImpl->mpTopWindow->AddChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); 176cdf0e10cSrcweir 177cdf0e10cSrcweir mpImpl->mxPropSet = uno::Reference< beans::XPropertySet >( 178cdf0e10cSrcweir ImplGetSVData()->maAppData.mxMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.PropertyBag" ) ) ), 179cdf0e10cSrcweir uno::UNO_QUERY ); 180cdf0e10cSrcweir OSL_ENSURE( mpImpl->mxPropSet.is(), "could not create instance of com.sun.star.beans.PropertyBag" ); 181cdf0e10cSrcweir mpImpl->mxPropSetAccess = uno::Reference< beans::XPropertyAccess >( mpImpl->mxPropSet, uno::UNO_QUERY ); 182cdf0e10cSrcweir OSL_ENSURE( mpImpl->mxPropSet.is(), "could not query XPropertyAccess interface" ); 183cdf0e10cSrcweir if( ! mpImpl->mxPropSetAccess.is() ) 184cdf0e10cSrcweir mpImpl->mxPropSet.clear(); 185cdf0e10cSrcweir 186cdf0e10cSrcweir addWindowToSet( i_pTopWindow ); 187cdf0e10cSrcweir 188cdf0e10cSrcweir setupProperties(); 189cdf0e10cSrcweir 190cdf0e10cSrcweir if( mpImpl->mxPropSet.is() ) 191cdf0e10cSrcweir { 192cdf0e10cSrcweir mpImpl->mxListener.set( mpImpl->mpListener = new WindowPropertySetListener( this ) ); 193cdf0e10cSrcweir } 194cdf0e10cSrcweir } 195cdf0e10cSrcweir 196cdf0e10cSrcweir WindowPropertySet::~WindowPropertySet() 197cdf0e10cSrcweir { 198cdf0e10cSrcweir mpImpl->mpTopWindow->RemoveChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); 199cdf0e10cSrcweir 200cdf0e10cSrcweir delete mpImpl; 201cdf0e10cSrcweir mpImpl = NULL; 202cdf0e10cSrcweir } 203cdf0e10cSrcweir 204cdf0e10cSrcweir uno::Reference< beans::XPropertySet > WindowPropertySet::getPropertySet() const 205cdf0e10cSrcweir { 206cdf0e10cSrcweir return mpImpl->mxPropSet; 207cdf0e10cSrcweir } 208cdf0e10cSrcweir 209cdf0e10cSrcweir void WindowPropertySet::addLayoutToSet( const boost::shared_ptr< WindowArranger >& i_pLayout ) 210cdf0e10cSrcweir { 211cdf0e10cSrcweir if( i_pLayout.get() ) 212cdf0e10cSrcweir { 213cdf0e10cSrcweir if( i_pLayout->getIdentifier().getLength() ) 214cdf0e10cSrcweir { 215cdf0e10cSrcweir WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pLayout->getIdentifier() ]; 216cdf0e10cSrcweir OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted layout has duplicate name" ); 217cdf0e10cSrcweir rEntry.mpWindow = NULL; 218cdf0e10cSrcweir rEntry.mpLayout = i_pLayout; 219cdf0e10cSrcweir rEntry.maSavedValues = i_pLayout->getProperties(); 220cdf0e10cSrcweir } 221cdf0e10cSrcweir // insert child layouts 222cdf0e10cSrcweir size_t nChildren = i_pLayout->countElements(); 223cdf0e10cSrcweir for( size_t i = 0; i < nChildren; i++ ) 224cdf0e10cSrcweir addLayoutToSet( i_pLayout->getChild( i ) ); 225cdf0e10cSrcweir } 226cdf0e10cSrcweir } 227cdf0e10cSrcweir 228cdf0e10cSrcweir void WindowPropertySet::addWindowToSet( Window* i_pWindow ) 229cdf0e10cSrcweir { 230cdf0e10cSrcweir if( i_pWindow->getIdentifier().getLength() ) // no name, no properties 231cdf0e10cSrcweir { 232cdf0e10cSrcweir WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pWindow->getIdentifier() ]; 233cdf0e10cSrcweir OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted window has duplicate name" ); 234cdf0e10cSrcweir rEntry.mpWindow = i_pWindow; 235cdf0e10cSrcweir rEntry.mpLayout.reset(); 236cdf0e10cSrcweir rEntry.maSavedValues = i_pWindow->getProperties(); 237cdf0e10cSrcweir } 238cdf0e10cSrcweir addLayoutToSet( i_pWindow->getLayout() ); 239cdf0e10cSrcweir 240cdf0e10cSrcweir Window* pWin = i_pWindow->GetWindow( WINDOW_FIRSTCHILD ); 241cdf0e10cSrcweir while( pWin ) 242cdf0e10cSrcweir { 243cdf0e10cSrcweir addWindowToSet( pWin ); 244cdf0e10cSrcweir pWin = pWin->GetWindow( WINDOW_NEXT ); 245cdf0e10cSrcweir } 246cdf0e10cSrcweir } 247cdf0e10cSrcweir 248cdf0e10cSrcweir void WindowPropertySet::setupProperties() 249cdf0e10cSrcweir { 250cdf0e10cSrcweir uno::Reference< beans::XPropertyContainer > xCont( mpImpl->mxPropSet, uno::UNO_QUERY ); 251cdf0e10cSrcweir OSL_ENSURE( xCont.is(), "could not get XPropertyContainer interface" ); 252cdf0e10cSrcweir if( ! xCont.is() ) 253cdf0e10cSrcweir return; 254cdf0e10cSrcweir 255cdf0e10cSrcweir for( std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it 256cdf0e10cSrcweir = mpImpl->maProperties.begin(); it != mpImpl->maProperties.end(); ++it ) 257cdf0e10cSrcweir { 258cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aOutsideValues( it->second.maSavedValues ); 259cdf0e10cSrcweir beans::PropertyValue* pVal = aOutsideValues.getArray(); 260cdf0e10cSrcweir for( sal_Int32 i = 0; i < aOutsideValues.getLength(); i++ ) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir pVal[i].Name = getIdentifiedPropertyName( it->first, pVal[i].Name ); 263cdf0e10cSrcweir xCont->addProperty( pVal[i].Name, 264cdf0e10cSrcweir beans::PropertyAttribute::BOUND | beans:: PropertyAttribute::CONSTRAINED, 265cdf0e10cSrcweir pVal[i].Value 266cdf0e10cSrcweir ); 267cdf0e10cSrcweir } 268cdf0e10cSrcweir } 269cdf0e10cSrcweir } 270cdf0e10cSrcweir 271cdf0e10cSrcweir void WindowPropertySet::propertyChange( const beans::PropertyChangeEvent& i_rEvent ) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir rtl::OUString aIdentifier, aProperty; 274cdf0e10cSrcweir spliceIdentifiedPropertyName( i_rEvent.PropertyName, aIdentifier, aProperty ); 275cdf0e10cSrcweir std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it = 276cdf0e10cSrcweir mpImpl->maProperties.find( aIdentifier ); 277cdf0e10cSrcweir if( it != mpImpl->maProperties.end() ) 278cdf0e10cSrcweir { 279cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aSet( 1 ); 280cdf0e10cSrcweir aSet[0].Name = aProperty; 281cdf0e10cSrcweir aSet[0].Value = i_rEvent.NewValue; 282cdf0e10cSrcweir it->second.setProperties( aSet ); 283cdf0e10cSrcweir } 284cdf0e10cSrcweir } 285cdf0e10cSrcweir 286cdf0e10cSrcweir IMPL_LINK( vcl::WindowPropertySet, ChildEventListener, VclWindowEvent*, pEvent ) 287cdf0e10cSrcweir { 288cdf0e10cSrcweir // find window in our properties 289cdf0e10cSrcweir std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it 290cdf0e10cSrcweir = mpImpl->maProperties.find( pEvent->GetWindow()->getIdentifier() ); 291cdf0e10cSrcweir if( it != mpImpl->maProperties.end() ) // this is valid, some unnamed child may have sent an event 292cdf0e10cSrcweir { 293cdf0e10cSrcweir sal_uLong nId = pEvent->GetId(); 294cdf0e10cSrcweir // check if anything interesting happened 295cdf0e10cSrcweir if( 296cdf0e10cSrcweir // general windowy things 297cdf0e10cSrcweir nId == VCLEVENT_WINDOW_SHOW || 298cdf0e10cSrcweir nId == VCLEVENT_WINDOW_HIDE || 299cdf0e10cSrcweir nId == VCLEVENT_WINDOW_ENABLED || 300cdf0e10cSrcweir nId == VCLEVENT_WINDOW_DISABLED || 301cdf0e10cSrcweir // button thingies 302cdf0e10cSrcweir nId == VCLEVENT_BUTTON_CLICK || 303cdf0e10cSrcweir nId == VCLEVENT_PUSHBUTTON_TOGGLE || 304cdf0e10cSrcweir nId == VCLEVENT_RADIOBUTTON_TOGGLE || 305cdf0e10cSrcweir nId == VCLEVENT_CHECKBOX_TOGGLE || 306cdf0e10cSrcweir // listbox 307cdf0e10cSrcweir nId == VCLEVENT_LISTBOX_SELECT || 308cdf0e10cSrcweir // edit 309cdf0e10cSrcweir nId == VCLEVENT_EDIT_MODIFY 310cdf0e10cSrcweir ) 311cdf0e10cSrcweir { 312cdf0e10cSrcweir WindowPropertySetData::PropertyMapEntry& rEntry = it->second; 313cdf0e10cSrcweir // collect changes 314cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aNewProps( rEntry.getProperties() ); 315cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aNewPropsOut( aNewProps ); 316cdf0e10cSrcweir 317cdf0e10cSrcweir // translate to identified properties 318cdf0e10cSrcweir beans::PropertyValue* pValues = aNewPropsOut.getArray(); 319cdf0e10cSrcweir for( sal_Int32 i = 0; i < aNewPropsOut.getLength(); i++ ) 320cdf0e10cSrcweir pValues[i].Name = getIdentifiedPropertyName( it->first, pValues[i].Name ); 321cdf0e10cSrcweir 322cdf0e10cSrcweir // broadcast changes 323cdf0e10cSrcweir bool bWasVeto = false; 324cdf0e10cSrcweir mpImpl->mpListener->suspend( true ); 325cdf0e10cSrcweir try 326cdf0e10cSrcweir { 327cdf0e10cSrcweir mpImpl->mxPropSetAccess->setPropertyValues( aNewPropsOut ); 328cdf0e10cSrcweir } 329cdf0e10cSrcweir catch( beans::PropertyVetoException& ) 330cdf0e10cSrcweir { 331cdf0e10cSrcweir bWasVeto = true; 332cdf0e10cSrcweir } 333cdf0e10cSrcweir mpImpl->mpListener->suspend( false ); 334cdf0e10cSrcweir 335cdf0e10cSrcweir if( ! bWasVeto ) // changes accepted ? 336cdf0e10cSrcweir rEntry.maSavedValues = rEntry.getProperties(); 337cdf0e10cSrcweir else // no, reset 338cdf0e10cSrcweir rEntry.setProperties( rEntry.maSavedValues ); 339cdf0e10cSrcweir } 340cdf0e10cSrcweir } 341cdf0e10cSrcweir 342cdf0e10cSrcweir return 0; 343cdf0e10cSrcweir } 344