diff --git a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h index f61cdf86e1427654f64395e64a79c5dd490dc799..98c159f9031645d7f6b423401138b6921c40e49c 100644 --- a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h @@ -10,6 +10,10 @@ #include <map> #include <set> +#include <Poco/Notification.h> +#include <Poco/NotificationCenter.h> +#include <Poco/AutoPtr.h> + //---------------------------------------------------------------------- // Forward declarations //---------------------------------------------------------------------- @@ -65,6 +69,45 @@ namespace Mantid class EXPORT_OPT_MANTID_KERNEL ConfigServiceImpl { public: + + /** + * This is the base class for POCO Notifications sent out from the Config Service. + * It does nothing. + */ + class ConfigServiceNotification : public Poco::Notification + { + public: + /// Empty constructor for ConfigServiceNotification Base Class + ConfigServiceNotification() : Poco::Notification() {} + }; + + /** + * This is the class for the notification that is to be sent when a value has been changed in + * config service. + */ + class ValueChanged : public ConfigServiceNotification + { + public: + /** Creates the Notification object with the required values + * @param name property that has been changed + * @param newvalue new value of property + * @param prevvalue previous value of property + */ + ValueChanged(const std::string name, const std::string newvalue, const std::string prevvalue) : ConfigServiceNotification(), m_name(name), m_value(newvalue), m_prev(prevvalue) {} + /// The name of the user property that has changed, as it appears in the user.properties file + const std::string & key() const { return this->m_name; } ///< @return The name of the changed the property + /// The new value for the property + const std::string & curValue() const { return this->m_value; } ///< @return The new value for the property + /// The previous value for the property + const std::string & preValue() const { return this->m_prev; } ///< @return The previous value for the property + private: + std::string m_name; ///< The name of the changed the property + std::string m_value; ///< The new value for the property + std::string m_prev; ///< The previous value for the property + }; + + + /// Wipe out the current configuration and load a new one void updateConfig(const std::string& filename, const bool append=false, const bool update_caches=true); /// Save the configuration to the user file @@ -104,9 +147,17 @@ namespace Mantid /// Get a facility const FacilityInfo& Facility(const std::string& fName)const; + /// Add an observer for a notification + void addObserver(const Poco::AbstractObserver& observer)const; + + /// Remove an observer + void removeObserver(const Poco::AbstractObserver& observer)const; + private: friend struct Mantid::Kernel::CreateUsingNew<ConfigServiceImpl>; + mutable Poco::NotificationCenter m_notificationCenter; + // Private constructors and destructor for singleton class ConfigServiceImpl(); /// Private copy constructor. Prevents singleton being copied. @@ -176,6 +227,9 @@ namespace Mantid template class EXPORT_OPT_MANTID_KERNEL Mantid::Kernel::SingletonHolder<ConfigServiceImpl>; typedef EXPORT_OPT_MANTID_KERNEL Mantid::Kernel::SingletonHolder<ConfigServiceImpl> ConfigService; + typedef Mantid::Kernel::ConfigServiceImpl::ValueChanged ConfigValChangeNotification; + typedef const Poco::AutoPtr<Mantid::Kernel::ConfigServiceImpl::ValueChanged>& ConfigValChangeNotification_ptr; + } // namespace Kernel } // namespace Mantid diff --git a/Code/Mantid/Kernel/src/ConfigService.cpp b/Code/Mantid/Kernel/src/ConfigService.cpp index 6c7a3f3c9438e8ad0d55d5196fd89021e3f2dac8..ad05e1f7913b6754466e116c4b1ebc600f4b45ea 100644 --- a/Code/Mantid/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Kernel/src/ConfigService.cpp @@ -20,6 +20,7 @@ #include "Poco/DOM/Document.h" #include "Poco/DOM/Element.h" #include "Poco/DOM/NodeList.h" +#include "Poco/Notification.h" #include <fstream> #include <sstream> @@ -666,6 +667,16 @@ std::string ConfigServiceImpl::getString(const std::string& keyName, bool use_ca */ void ConfigServiceImpl::setString(const std::string & key, const std::string & value) { + std::string old; + try + { + old = m_pConf->getString(key); + } + catch ( Poco::NotFoundException & ) + { + old = ""; + } + //Ensure we keep a correct full path std::map<std::string, bool>::const_iterator itr = m_ConfigPaths.find(key); if (itr != m_ConfigPaths.end()) @@ -686,6 +697,9 @@ void ConfigServiceImpl::setString(const std::string & key, const std::string & v } m_pConf->setString(key, value); + + if ( value != old ) + m_notificationCenter.postNotification(new ValueChanged(key, value, old)); } /** Searches for a string within the currently loaded configuaration values and @@ -902,6 +916,23 @@ const FacilityInfo& ConfigServiceImpl::Facility() const return Facility(defFacility); } +/** Add an observer to a notification + @param observer Reference to the observer to add + */ +void ConfigServiceImpl::addObserver(const Poco::AbstractObserver& observer)const +{ + m_notificationCenter.addObserver(observer); +} + +/** Remove an observer + @param observer Reference to the observer to remove + */ +void ConfigServiceImpl::removeObserver(const Poco::AbstractObserver& observer)const +{ + m_notificationCenter.removeObserver(observer); +} + + /** * Get a facility * @param fName Facility name diff --git a/Code/Mantid/Kernel/test/ConfigServiceTest.h b/Code/Mantid/Kernel/test/ConfigServiceTest.h index dc5083b75807138ce277893843ec125eb46d6591..cf37d5a0cc75243631cb7c68a19f8dff3cf0a73b 100644 --- a/Code/Mantid/Kernel/test/ConfigServiceTest.h +++ b/Code/Mantid/Kernel/test/ConfigServiceTest.h @@ -12,13 +12,15 @@ #include <string> #include <fstream> +#include <Poco/NObserver.h> + using namespace Mantid::Kernel; class ConfigServiceTest : public CxxTest::TestSuite { public: - ConfigServiceTest() + ConfigServiceTest() : m_changeObserver(*this, &ConfigServiceTest::handleConfigChange) { ConfigService::Instance().updateConfig("MantidTest.properties"); } @@ -253,6 +255,41 @@ public: prop_file.remove(); } + // Test that the ValueChanged notification is sent + void testNotifications() + { + m_valueChangedSent = false; + + ConfigServiceImpl& settings = ConfigService::Instance(); + + TS_ASSERT_THROWS_NOTHING(settings.addObserver(m_changeObserver)); + + settings.setString("default.facility", "SNS"); + + TS_ASSERT(m_valueChangedSent); + TS_ASSERT_EQUALS(m_key, "default.facility"); + TS_ASSERT_DIFFERS(m_preValue, m_curValue); + TS_ASSERT_EQUALS(m_curValue, "SNS"); + + // Need to set back to ISIS for later tests + settings.setString("default.facility", "ISIS"); + } + + +protected: + bool m_valueChangedSent; + Poco::NObserver<ConfigServiceTest, Mantid::Kernel::ConfigServiceImpl::ValueChanged> m_changeObserver; + std::string m_key; + std::string m_preValue; + std::string m_curValue; + void handleConfigChange(const Poco::AutoPtr<Mantid::Kernel::ConfigServiceImpl::ValueChanged>& pNf) + { + m_valueChangedSent = true; + m_key = pNf->key(); + m_preValue = pNf->preValue(); + m_curValue = pNf->curValue(); + } + private: void runSaveTest(const std::string& filename) { diff --git a/Code/qtiplot/MantidQt/MantidWidgets/inc/InstrumentSelector.h b/Code/qtiplot/MantidQt/MantidWidgets/inc/InstrumentSelector.h index cafa27a2047da77160a3d028b2d4dd11e9bbecc4..11d4ab761592727ef9eb384d4781f260445dae91 100644 --- a/Code/qtiplot/MantidQt/MantidWidgets/inc/InstrumentSelector.h +++ b/Code/qtiplot/MantidQt/MantidWidgets/inc/InstrumentSelector.h @@ -4,6 +4,10 @@ #include "WidgetDllOption.h" #include <QComboBox> #include <QStringList> +#include "MantidKernel/ConfigService.h" + +#include <Poco/AutoPtr.h> +#include <Poco/NObserver.h> //---------------------------------------------------------------- // Forward declarations @@ -59,6 +63,11 @@ namespace MantidQt /// Set the list of techniques void setTechniques(const QStringList & techniques); + protected: + + void handleConfigChange(Mantid::Kernel::ConfigValChangeNotification_ptr pNf); + Poco::NObserver<InstrumentSelector, Mantid::Kernel::ConfigValChangeNotification> m_changeObserver; + public slots: /// Update list for a new facility void fillWithInstrumentsFromFacility(const QString & name = QString()); diff --git a/Code/qtiplot/MantidQt/MantidWidgets/src/InstrumentSelector.cpp b/Code/qtiplot/MantidQt/MantidWidgets/src/InstrumentSelector.cpp index 2bbdfb4eee94fb9a6fba9c79d34a2bef4fd40164..decb9b3a3556ee97996632cc5521c2762e455497 100644 --- a/Code/qtiplot/MantidQt/MantidWidgets/src/InstrumentSelector.cpp +++ b/Code/qtiplot/MantidQt/MantidWidgets/src/InstrumentSelector.cpp @@ -7,6 +7,13 @@ #include "MantidKernel/InstrumentInfo.h" #include "MantidKernel/Exception.h" +#include <QMessageBox> + +#include <Poco/Notification.h> +#include <Poco/NotificationCenter.h> +#include <Poco/AutoPtr.h> +#include <Poco/NObserver.h> + namespace MantidQt { namespace MantidWidgets @@ -22,7 +29,8 @@ namespace MantidQt * @param parent A widget to act as this widget's parent (default = NULL) * @param init If true then the widget will be populated with the instrument list (default = true) */ - InstrumentSelector::InstrumentSelector(QWidget *parent, bool init) : QComboBox(parent), m_techniques(), m_currentFacility(NULL) + InstrumentSelector::InstrumentSelector(QWidget *parent, bool init) : QComboBox(parent), m_techniques(), m_currentFacility(NULL), + m_changeObserver(*this, &InstrumentSelector::handleConfigChange) { setEditable(false); if( init ) @@ -30,6 +38,9 @@ namespace MantidQt fillWithInstrumentsFromFacility(); connect(this, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(updateDefaultInstrument(const QString &))); connect(this, SIGNAL(currentIndexChanged(const QString &)), this, SIGNAL(instrumentSelectionChanged(const QString &))); + + Mantid::Kernel::ConfigServiceImpl& config = Mantid::Kernel::ConfigService::Instance(); + config.addObserver(m_changeObserver); } } @@ -54,6 +65,26 @@ namespace MantidQt filterByTechniquesAtFacility(techniques, *m_currentFacility); } } + + void InstrumentSelector::handleConfigChange(Mantid::Kernel::ConfigValChangeNotification_ptr pNf) + { + QString prop = QString::fromStdString(pNf->key()); + QString newV = QString::fromStdString(pNf->curValue()); + QString oldV = QString::fromStdString(pNf->preValue()); + if ( newV != oldV ) + { + if ( prop == "default.facility" ) + { + // QMessageBox::information(this, "MantidPlot", "Default facility has changed to: " + newV + " from " + oldV); + fillWithInstrumentsFromFacility(newV); + } + else if ( ( prop == "default.instrument" ) && ( newV != this->currentText() ) ) + { + // QMessageBox::information(this, "MantidPlot", "Default instrument has changed to: " + newV + " from " + oldV); + this->setCurrentIndex(this->findText(newV)); + } + } + } //------------------------------------------------------ // Public slot member functions