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