/* Copyright (C) 2009 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_OBSERVABLE #define INCLUDED_OBSERVABLE /* Wrapper around Boost.Signals to make watching objects for changes more convenient. General usage: Observable variable_to_be_watched; ... class Thing { ObservableScopedConnection m_Conn; Thing() { m_Conn = variable_to_be_watched.RegisterObserver(OnChange); } void OnChange(const int& var) { do_something_with(var); } } ... variable_to_be_watched.NotifyObservers(); */ #include #include typedef boost::signals::connection ObservableConnection; typedef boost::signals::scoped_connection ObservableScopedConnection; template class Observable : public T { public: Observable() {} template explicit Observable(const T1& a1) : T(a1) {} template explicit Observable(T1& a1, T2 a2) : T(a1, a2) {} template ObservableConnection RegisterObserver(int order, void (C::*callback) (const T&), C* obj) { return m_Signal.connect(order, boost::bind(std::mem_fun(callback), obj, _1)); } ObservableConnection RegisterObserver(int order, void (*callback) (const T&)) { return m_Signal.connect(order, callback); } void RemoveObserver(const ObservableConnection& conn) { conn.disconnect(); } void NotifyObservers() { m_Signal(*this); } // Use when an object is changing something that it's also observing, // because it already knows about the change and doesn't need to be notified // again (particularly since that may cause infinite loops). void NotifyObserversExcept(ObservableConnection& conn) { if (conn.blocked()) { // conn is already blocked and won't see anything NotifyObservers(); } else { // Temporarily disable conn conn.block(); NotifyObservers(); conn.unblock(); } } Observable* operator=(const T& rhs) { *dynamic_cast(this) = rhs; return this; } private: boost::signal m_Signal; }; class ObservableScopedConnections { public: void Add(const ObservableConnection& conn); ~ObservableScopedConnections(); private: std::vector m_Conns; }; #endif // INCLUDED_OBSERVABLE