/// This file is part of the X3DToolKit library /// Copyright (C) 2002-2004 Yannick Le Goc (legoc@imag.fr) /// http://artis.imag.fr/Members/Yannick.Legoc/X3D/ /// This library is free software; you can redistribute it and/or /// modify it under the terms of the GNU Lesser General Public /// License as published by the Free Software Foundation; either /// version 2.1 of the License, or (at your option) any later version. /// This library 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 /// Lesser General Public License for more details. /// You should have received a copy of the GNU Lesser General Public /// License along with this library; if not, write to the Free Software /// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// /// Signal.h /// //////////////////////////////////////////////////////////////////////////////// #ifndef SIGNAL_H #define SIGNAL_H #include "Platform.h" #include #include #include namespace RC { template class TSignal; template class SignalSender; /*! \brief Class declared in providing a signal-slot mechanism. * * Indeed Qt doesn't allow to write template Q_OBJECT. * * \ingroup base */ class Signal { public: virtual ~Signal() {} virtual void transmit() = 0; #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED /// Connects two objects. template inline static void connect(A *a, T (SA:: *getPtr)() const, B *b, void (SB:: *setPtr)(T t)) { //std::cout << "connecting..." << std::endl; SignalSender::connect(a, getPtr, static_cast(b), setPtr); }; /// Connects two objects which don't exchange datas. template inline static void connect(A *a, void (SA:: *getPtr)() const, B *b, void (SB:: *setPtr)()) { //std::cout << "connecting..." << std::endl; SignalSender::connect(a, getPtr, static_cast(b), setPtr); }; /// Disconnects two connected objects. template inline static void disconnect(A *a, T (SA:: *getPtr)() const, B *b, void (SB:: *setPtr)(T t)) { //std::cout << "disconnecting..."; SignalSender::disconnect(a, getPtr, static_cast(b), setPtr); }; /// Disconnects two connected objects which don't exchange datas. template inline static void disconnect(A *a, void (SA:: *getPtr)() const, B *b, void (SB:: *setPtr)()) { //std::cout << "disconnecting..."; SignalSender::disconnect(a, getPtr, static_cast(b), setPtr); }; /// Sends the datas from the object a to all the connected objects to a by the /// method of which pointer is getPtr. template inline static void send(A *a, T (SA:: *getPtr)() const) { SignalSender::send(a, getPtr); }; #endif }; #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED //////////////////////////////////////////////////////////////////////////////// /// SignalSender template class SignalSender { private: typedef std::list > SignalMap; typedef std::map SignalMapMap; public: template static void connect(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)); template static void disconnect(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)); static void send(A *a, T (A:: *getPtr)() const); private: static SignalMapMap _signalMap; }; template class SignalSender { private: typedef std::list > SignalMap; typedef std::map SignalMapMap; public: template static void connect(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()); template static void disconnect(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()); static void send(A *a, void (A:: *getPtr)() const); private: static SignalMapMap _signalMap; }; //////////////////////////////////////////////////////////////////////////////// /// TSignal template class TSignal : public Signal { template friend class SignalSender; public: TSignal(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)); void transmit(); private: A *_a; T (A:: *_getPtr)() const; B *_b; void (B:: *_setPtr)(T t); }; template class TSignal : public Signal { template friend class SignalSender; public: TSignal(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()); void transmit(); private: A *_a; void (A:: *_getPtr)() const; B *_b; void (B:: *_setPtr)(); }; template template void SignalSender::connect(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)) { Signal *r = new TSignal(a, getPtr, b, setPtr); _signalMap[a].push_back(std::pair(reinterpret_cast(getPtr), r)); } template template void SignalSender::disconnect(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)) { for (typename SignalMap::iterator it = _signalMap[a].begin(); it != _signalMap[a].end(); ++it) { if ((*it).first == reinterpret_cast(getPtr)) { TSignal *tr = dynamic_cast *>((*it).second); if ((tr != 0) && (b == tr->_b) && (setPtr == tr->_setPtr)) { _signalMap[a].erase(it); delete tr; if (_signalMap[a].empty()) _signalMap.erase(a); return; } } } } template void SignalSender::send(A *a, T (A:: *getPtr)() const) { //std::cout << "sending..." << std::endl; for (typename SignalMap::iterator it = _signalMap[a].begin(); it != _signalMap[a].end(); ++it) { if ((*it).first == reinterpret_cast(getPtr)) (*it).second->transmit(); } } template template void SignalSender::connect(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()) { Signal *r = new TSignal(a, getPtr, b, setPtr); _signalMap[a].push_back(std::pair(reinterpret_cast(getPtr), r)); } template template void SignalSender::disconnect(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()) { for (typename SignalMap::iterator it = _signalMap[a].begin(); it != _signalMap[a].end(); ++it) { if ((*it).first == reinterpret_cast(getPtr)) { TSignal *tr = dynamic_cast *>((*it).second); if ((tr != 0) && (b == tr->_b) && (setPtr == tr->_setPtr)) { _signalMap[a].erase(it); delete tr; if (_signalMap[a].empty()) _signalMap.erase(a); return; } } } } template void SignalSender::send(A *a, void (A:: *getPtr)() const) { //std::cout << "sending void..." << std::endl; for (typename SignalMap::iterator it = _signalMap[a].begin(); it != _signalMap[a].end(); ++it) { if ((*it).first == reinterpret_cast(getPtr)) (*it).second->transmit(); } } template typename SignalSender::SignalMapMap SignalSender::_signalMap; template typename SignalSender::SignalMapMap SignalSender::_signalMap; //////////////////////////////////////////////////////////////////////////////// /// TSignal template TSignal::TSignal(A *a, T (A:: *getPtr)() const, B *b, void (B:: *setPtr)(T t)) : _a(a), _getPtr(getPtr), _b(b), _setPtr(setPtr) { } template void TSignal::transmit() { //std::cout << "transmitting..." << std::endl; (_b->*_setPtr)((_a->*_getPtr)()); } template TSignal::TSignal(A *a, void (A:: *getPtr)() const, B *b, void (B:: *setPtr)()) : _a(a), _getPtr(getPtr), _b(b), _setPtr(setPtr) { } template void TSignal::transmit() { //std::cout << "transmitting..." << std::endl; (_a->*_getPtr)(); (_b->*_setPtr)(); } #endif } #endif