// Vaca - Visual Application Components Abstraction // Copyright (c) 2005-2009 David Capello // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the // distribution. // * Neither the name of the author nor the names of its contributors // may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef VACA_SIGNAL_H #define VACA_SIGNAL_H #include "Vaca/base.h" #include "Vaca/Slot.h" #include namespace Vaca { /** @defgroup signal_group Signal Classes @{ */ // ====================================================================== // Signal0_base /** Base class for signals which call functions without parameters. */ template class Signal0_base { public: typedef R ReturnType; typedef Slot0 SlotType; typedef std::vector SlotList; protected: SlotList m_slots; public: Signal0_base() { } Signal0_base(const Signal0_base& s) { copy(s); } ~Signal0_base() { disconnectAll(); } SlotType* addSlot(SlotType* slot) { m_slots.push_back(slot); return slot; } template SlotType* connect(const F& f) { return addSlot(new Slot0_fun(f)); } template SlotType* connect(R (T::*m)(), T* t) { return addSlot(new Slot0_mem(m, t)); } const SlotList& getSlots() const { return m_slots; } void disconnect(SlotType* slot) { remove_from_container(m_slots, slot); } void disconnectAll() { typename SlotList::iterator end = m_slots.end(); for (typename SlotList::iterator it = m_slots.begin(); it != end; ++it) delete *it; m_slots.clear(); } bool empty() const { return m_slots.empty(); } Signal0_base& operator=(const Signal0_base& s) { copy(s); return *this; } private: void copy(const Signal0_base& s) { typename SlotList::const_iterator end = s.m_slots.end(); for (typename SlotList::const_iterator it = s.m_slots.begin(); it != end; ++it) { m_slots.push_back((*it)->clone()); } } }; // ====================================================================== // Signal0 template class Signal0 : public Signal0_base { public: Signal0() { } Signal0(const Signal0& s) : Signal0_base(s) { } R operator()(R default_result = R()) { R result(default_result); typename Signal0_base::SlotList::iterator end = Signal0_base::m_slots.end(); for (typename Signal0_base::SlotList::iterator it = Signal0_base::m_slots.begin(); it != end; ++it) { typename Signal0_base::SlotType* slot = *it; result = (*slot)(); } return result; } template R operator()(R default_result, const Merger& m) { R result(default_result); Merger merger(m); typename Signal0_base::SlotList::iterator end = Signal0_base::m_slots.end(); for (typename Signal0_base::SlotList::iterator it = Signal0_base::m_slots.begin(); it != end; ++it) { typename Signal0_base::SlotType* slot = *it; result = merger(result, (*slot)()); } return result; } }; // ====================================================================== // Signal0 template<> class Signal0 : public Signal0_base { public: Signal0() { } Signal0(const Signal0& s) : Signal0_base(s) { } void operator()() { SlotList::iterator end = m_slots.end(); for (SlotList::iterator it = m_slots.begin(); it != end; ++it) { SlotType* slot = *it; (*slot)(); } } }; // ====================================================================== // Signal1_base /** Base class for signals which call functions with one parameter. */ template class Signal1_base { public: typedef R ReturnType; typedef Slot1 SlotType; typedef std::vector SlotList; protected: SlotList m_slots; public: Signal1_base() { } Signal1_base(const Signal1_base& s) { copy(s); } ~Signal1_base() { disconnectAll(); } SlotType* addSlot(SlotType* slot) { m_slots.push_back(slot); return slot; } template SlotType* connect(const F& f) { return addSlot(new Slot1_fun(f)); } template SlotType* connect(R (T::*m)(A1), T* t) { return addSlot(new Slot1_mem(m, t)); } const SlotList& getSlots() const { return m_slots; } void disconnect(SlotType* slot) { remove_from_container(m_slots, slot); } void disconnectAll() { typename SlotList::iterator end = m_slots.end(); for (typename SlotList::iterator it = m_slots.begin(); it != end; ++it) delete *it; m_slots.clear(); } bool empty() const { return m_slots.empty(); } Signal1_base& operator=(const Signal1_base& s) { copy(s); return *this; } private: void copy(const Signal1_base& s) { typename SlotList::const_iterator end = s.m_slots.end(); for (typename SlotList::const_iterator it = s.m_slots.begin(); it != end; ++it) { m_slots.push_back((*it)->clone()); } } }; // ====================================================================== // Signal1 template class Signal1 : public Signal1_base { public: Signal1() { } Signal1(const Signal1& s) : Signal1_base(s) { } R operator()(A1 a1, R default_result = R()) { R result(default_result); typename Signal1_base::SlotList::iterator end = Signal1_base::m_slots.end(); for (typename Signal1_base::SlotList::iterator it = Signal1_base::m_slots.begin(); it != end; ++it) { typename Signal1_base::SlotType* slot = *it; result = (*slot)(a1); } return result; } template R operator()(A1 a1, R default_result, const Merger& m) { R result(default_result); Merger merger(m); typename Signal1_base::SlotList::iterator end = Signal1_base::m_slots.end(); for (typename Signal1_base::SlotList::iterator it = Signal1_base::m_slots.begin(); it != end; ++it) { typename Signal1_base::SlotType* slot = *it; result = merger(result, (*slot)(a1)); } return result; } }; // ====================================================================== // Signal1 template class Signal1 : public Signal1_base { public: Signal1() { } Signal1(const Signal1& s) : Signal1_base(s) { } void operator()(A1 a1) { typename Signal1_base::SlotList::iterator end = Signal1_base::m_slots.end(); for (typename Signal1_base::SlotList::iterator it = Signal1_base::m_slots.begin(); it != end; ++it) { typename Signal1_base::SlotType* slot = *it; (*slot)(a1); } } }; // ====================================================================== // Signal2_base /** Base class for signals which call functions with two parameters. */ template class Signal2_base { public: typedef R ReturnType; typedef Slot2 SlotType; typedef std::vector SlotList; protected: SlotList m_slots; public: Signal2_base() { } Signal2_base(const Signal2_base& s) { copy(s); } ~Signal2_base() { disconnectAll(); } SlotType* addSlot(SlotType* slot) { m_slots.push_back(slot); return slot; } template SlotType* connect(const F& f) { return addSlot(new Slot2_fun(f)); } template SlotType* connect(R (T::*m)(A1, A2), T* t) { return addSlot(new Slot2_mem(m, t)); } const SlotList& getSlots() const { return m_slots; } void disconnect(SlotType* slot) { remove_from_container(m_slots, slot); } void disconnectAll() { typename SlotList::iterator end = m_slots.end(); for (typename SlotList::iterator it = m_slots.begin(); it != end; ++it) delete *it; m_slots.clear(); } bool empty() const { return m_slots.empty(); } Signal2_base& operator=(const Signal2_base& s) { copy(s); return *this; } private: void copy(const Signal2_base& s) { typename SlotList::const_iterator end = s.m_slots.end(); for (typename SlotList::const_iterator it = s.m_slots.begin(); it != end; ++it) { m_slots.push_back((*it)->clone()); } } }; // ====================================================================== // Signal2 template class Signal2 : public Signal2_base { public: Signal2() { } Signal2(const Signal2& s) : Signal2_base(s) { } R operator()(A1 a1, A2 a2, R default_result = R()) { R result(default_result); typename Signal2_base::SlotList::iterator end = Signal2_base::m_slots.end(); for (typename Signal2_base::SlotList::iterator it = Signal2_base::m_slots.begin(); it != end; ++it) { typename Signal2_base::SlotType* slot = *it; result = (*slot)(a1, a2); } return result; } template R operator()(A1 a1, A2 a2, R default_result, const Merger& m) { R result(default_result); Merger merger(m); typename Signal2_base::SlotList::iterator end = Signal2_base::m_slots.end(); for (typename Signal2_base::SlotList::iterator it = Signal2_base::m_slots.begin(); it != end; ++it) { typename Signal2_base::SlotType* slot = *it; result = merger(result, (*slot)(a1, a2)); } return result; } }; // ====================================================================== // Signal2 template class Signal2 : public Signal2_base { public: Signal2() { } Signal2(const Signal2& s) : Signal2_base(s) { } void operator()(A1 a1, A2 a2) { typename Signal2_base::SlotList::iterator end = Signal2_base::m_slots.end(); for (typename Signal2_base::SlotList::iterator it = Signal2_base::m_slots.begin(); it != end; ++it) { typename Signal2_base::SlotType* slot = *it; (*slot)(a1, a2); } } }; /** @} */ } // namespace Vaca #endif // VACA_SIGNAL_H