From ccf8bdcf929e842ef42ae968e4f0532282357277 Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Mon, 5 Oct 2015 18:08:02 +0100 Subject: Create a wrapper to make listening for configmgr changes easy. Change-Id: Ib58d04f9e046e604b24e0e338796a7a60aa1d6fd Reviewed-on: https://gerrit.libreoffice.org/19253 Tested-by: Jenkins Reviewed-by: Michael Meeks --- comphelper/source/misc/configuration.cxx | 51 ++++++++++++ configmgr/CppunitTest_configmgr_unit.mk | 4 + configmgr/qa/unit/test.cxx | 47 +++++++++++ include/comphelper/configurationlistener.hxx | 118 +++++++++++++++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 include/comphelper/configurationlistener.hxx diff --git a/comphelper/source/misc/configuration.cxx b/comphelper/source/misc/configuration.cxx index 6280fdc84ac2..e5bf8b84d2d2 100644 --- a/comphelper/source/misc/configuration.cxx +++ b/comphelper/source/misc/configuration.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -209,4 +210,54 @@ comphelper::detail::ConfigurationWrapper::createChanges() const { new ConfigurationChanges(context_)); } +void comphelper::ConfigurationListener::addListener(ConfigurationListenerPropertyBase *pListener) +{ + maListeners.push_back( pListener ); + mxConfig->addPropertyChangeListener( pListener->maName, this ); + pListener->setProperty( mxConfig->getPropertyValue( pListener->maName ) ); +} + +void comphelper::ConfigurationListener::removeListener(ConfigurationListenerPropertyBase *pListener) +{ + auto it = maListeners.begin(); + it = std::find( maListeners.begin(), maListeners.end(), pListener ); + if ( it != maListeners.end() ) + { + maListeners.erase( it ); + mxConfig->removePropertyChangeListener( pListener->maName, this ); + } +} + +void comphelper::ConfigurationListener::dispose() +{ + for (auto it = maListeners.begin(); it != maListeners.end(); ++it) + { + mxConfig->removePropertyChangeListener( (*it)->maName, this ); + (*it)->dispose(); + } + maListeners.clear(); +} + +void SAL_CALL comphelper::ConfigurationListener::disposing(css::lang::EventObject const &) + throw (css::uno::RuntimeException, std::exception) +{ + dispose(); +} + +void SAL_CALL comphelper::ConfigurationListener::propertyChange( + css::beans::PropertyChangeEvent const &rEvt ) + throw (css::uno::RuntimeException, std::exception) +{ + assert( rEvt.Source == mxConfig ); + for ( auto it = maListeners.begin(); it != maListeners.end(); ++it ) + { + if ( (*it)->maName == rEvt.PropertyName ) + { + // ignore rEvt.NewValue - in theory it could be stale => not set. + css::uno::Any aValue = mxConfig->getPropertyValue( (*it)->maName ); + (*it)->setProperty( aValue ); + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/configmgr/CppunitTest_configmgr_unit.mk b/configmgr/CppunitTest_configmgr_unit.mk index e8bddc24bee8..ca9653fd126e 100644 --- a/configmgr/CppunitTest_configmgr_unit.mk +++ b/configmgr/CppunitTest_configmgr_unit.mk @@ -21,6 +21,10 @@ $(eval $(call gb_CppunitTest_use_library_objects,configmgr_unit,configmgr)) $(eval $(call gb_CppunitTest_use_sdk_api,configmgr_unit,)) +$(eval $(call gb_CppunitTest_use_custom_headers,configmgr_unit,\ + officecfg/registry \ +)) + $(eval $(call gb_CppunitTest_use_libraries,configmgr_unit, \ comphelper \ cppu \ diff --git a/configmgr/qa/unit/test.cxx b/configmgr/qa/unit/test.cxx index a9f609bc3677..6985cab57fde 100644 --- a/configmgr/qa/unit/test.cxx +++ b/configmgr/qa/unit/test.cxx @@ -55,7 +55,11 @@ #include #include #include +#include +#include +#include #include +#include namespace { @@ -70,6 +74,7 @@ public: void testSetSetMemberName(); void testInsertSetMember(); void testReadCommands(); + void testListener(); #if 0 void testThreads(); #endif @@ -98,6 +103,7 @@ public: CPPUNIT_TEST(testSetSetMemberName); CPPUNIT_TEST(testInsertSetMember); CPPUNIT_TEST(testReadCommands); + CPPUNIT_TEST(testListener); #if 0 CPPUNIT_TEST(testThreads); #endif @@ -356,6 +362,47 @@ void Test::testReadCommands() access, css::uno::UNO_QUERY_THROW)->dispose(); } +void Test::testListener() +{ + OUString aRandomPath = "/org.openoffice.Office.Math/View"; + + // test with no props. + { + rtl::Reference xListener( + new comphelper::ConfigurationListener(aRandomPath)); + xListener->dispose(); + } + + // test some changes + { + rtl::Reference xListener( + new comphelper::ConfigurationListener(aRandomPath)); + + comphelper::ConfigurationListenerProperty aSetting(xListener, "AutoRedraw"); + CPPUNIT_ASSERT_MESSAGE("check AutoRedraw defaults to true", aSetting.get()); + + // set to false + { + std::shared_ptr< comphelper::ConfigurationChanges > xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Math::View::AutoRedraw::set(false, xChanges); + xChanges->commit(); + } + CPPUNIT_ASSERT_MESSAGE("listener failed to trigger", !aSetting.get()); + + // set to true + { + std::shared_ptr< comphelper::ConfigurationChanges > xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Math::View::AutoRedraw::set(true, xChanges); + xChanges->commit(); + } + CPPUNIT_ASSERT_MESSAGE("listener failed to trigger", aSetting.get()); + + xListener->dispose(); + } +} + void Test::testRecursive() { bool destroyed = false; diff --git a/include/comphelper/configurationlistener.hxx b/include/comphelper/configurationlistener.hxx new file mode 100644 index 000000000000..658b84b8e80d --- /dev/null +++ b/include/comphelper/configurationlistener.hxx @@ -0,0 +1,118 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_COMPHELPER_CONFIGURATIONLISTENER_HXX +#define INCLUDED_COMPHELPER_CONFIGURATIONLISTENER_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace comphelper { + +class ConfigurationListener; + +class COMPHELPER_DLLPUBLIC ConfigurationListenerPropertyBase { +public: + OUString maName; + rtl::Reference mxListener; + + virtual ~ConfigurationListenerPropertyBase() {} + virtual void setProperty(const css::uno::Any &aProperty) = 0; + void dispose() { mxListener.clear(); } +}; + +template< typename uno_type > class ConfigurationListenerProperty : public ConfigurationListenerPropertyBase +{ + uno_type maValue; +protected: + virtual void setProperty(const css::uno::Any &aProperty) SAL_OVERRIDE + { + aProperty >>= maValue; + } +public: + /** + * Provide a mirror of the configmgr's version of this property + * for the lifecycle of this property. The property value tracks + * the same value in the configuration. + */ + inline ConfigurationListenerProperty(const rtl::Reference< ConfigurationListener > &xListener, + const OUString &rProp ); + + inline ~ConfigurationListenerProperty(); + + uno_type get() { return maValue; } +}; + +class COMPHELPER_DLLPUBLIC ConfigurationListener : + public cppu::WeakImplHelper< css::beans::XPropertyChangeListener > +{ + css::uno::Reference< css::beans::XPropertySet > mxConfig; + std::vector< ConfigurationListenerPropertyBase * > maListeners; +public: + /// Public health warning, you -must- dispose this if you use it. + ConfigurationListener(const OUString &rPath, + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > + const & xContext = comphelper::getProcessComponentContext()) + : mxConfig( ConfigurationHelper::openConfig( xContext, rPath, + ConfigurationHelper::EConfigurationModes::E_READONLY ), + css::uno::UNO_QUERY_THROW ) + { } + + virtual ~ConfigurationListener() + { + dispose(); + } + + /// Listen for the specific property denoted by the listener + void addListener(ConfigurationListenerPropertyBase *pListener); + + /// Stop listening. + void removeListener(ConfigurationListenerPropertyBase *pListener); + + /// Release various circular references + void dispose(); + + // XPropertyChangeListener implementation + virtual void SAL_CALL disposing(css::lang::EventObject const &) + throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE; + + /// Notify of the property change + virtual void SAL_CALL propertyChange( + css::beans::PropertyChangeEvent const &rEvt ) + throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE; +}; + +template< typename uno_type > ConfigurationListenerProperty< uno_type >::ConfigurationListenerProperty(const rtl::Reference< ConfigurationListener > &xListener, const OUString &rProp ) +{ + maName = rProp; + mxListener = xListener; + mxListener->addListener(this); +} + +template< typename uno_type > ConfigurationListenerProperty< uno_type >::~ConfigurationListenerProperty() +{ + if (mxListener.is()) + mxListener->removeListener(this); +} + +} // namespace comphelper + +#endif // INCLUDED_COMPHELPER_CONFIGURATIONLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit