/** * @file lllistenerwrapper.h * @author Nat Goodspeed * @date 2009-11-30 * @brief Introduce LLListenerWrapper template * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * 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; * version 2.1 of the License only. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #if ! defined(LL_LLLISTENERWRAPPER_H) #define LL_LLLISTENERWRAPPER_H #include "llevents.h" // LLListenerWrapperBase #include <boost/visit_each.hpp> /** * Template base class for coding wrappers for LLEventPump listeners. * * Derive your listener wrapper from LLListenerWrapper. You must use * LLLISTENER_WRAPPER_SUBCLASS() so your subclass will play nicely with * boost::visit_each (q.v.). That way boost::signals2 can still detect * derivation from LLEventTrackable, and so forth. */ template <typename LISTENER> class LLListenerWrapper: public LLListenerWrapperBase { public: /// Wrap an arbitrary listener object LLListenerWrapper(const LISTENER& listener): mListener(listener) {} /// call virtual bool operator()(const LLSD& event) { return mListener(event); } /// Allow boost::visit_each() to peek at our mListener. template <class V> void accept_visitor(V& visitor) const { using boost::visit_each; visit_each(visitor, mListener, 0); } private: LISTENER mListener; }; /** * Specialize boost::visit_each() (leveraging ADL) to peek inside an * LLListenerWrapper<T> to traverse its LISTENER. We borrow the * accept_visitor() pattern from boost::bind(), avoiding the need to make * mListener public. */ template <class V, typename T> void visit_each(V& visitor, const LLListenerWrapper<T>& wrapper, int) { wrapper.accept_visitor(visitor); } /// use this (sigh!) for each subclass of LLListenerWrapper<T> you write #define LLLISTENER_WRAPPER_SUBCLASS(CLASS) \ template <class V, typename T> \ void visit_each(V& visitor, const CLASS<T>& wrapper, int) \ { \ visit_each(visitor, static_cast<const LLListenerWrapper<T>&>(wrapper), 0); \ } \ \ /* Have to state this explicitly, rather than using LL_TEMPLATE_CONVERTIBLE, */ \ /* because the source type is itself a template. */ \ template <typename T> \ struct ll_template_cast_impl<const LLListenerWrapperBase*, const CLASS<T>*> \ { \ const LLListenerWrapperBase* operator()(const CLASS<T>* wrapper) \ { \ return wrapper; \ } \ } /** * Make an instance of a listener wrapper. Every wrapper class must be a * template accepting a listener object of arbitrary type. In particular, the * type of a boost::bind() expression is deliberately undocumented. So we * can't just write Wrapper<CorrectType>(boost::bind(...)). Instead we must * write llwrap<Wrapper>(boost::bind(...)). */ template <template<typename> class WRAPPER, typename T> WRAPPER<T> llwrap(const T& listener) { return WRAPPER<T>(listener); } /** * This LLListenerWrapper template subclass is used to report entry/exit to an * event listener, by changing this: * @code * someEventPump.listen("MyClass", * boost::bind(&MyClass::method, ptr, _1)); * @endcode * to this: * @code * someEventPump.listen("MyClass", * llwrap<LLCoutListener>( * boost::bind(&MyClass::method, ptr, _1))); * @endcode */ template <class LISTENER> class LLCoutListener: public LLListenerWrapper<LISTENER> { typedef LLListenerWrapper<LISTENER> super; public: /// Wrap an arbitrary listener object LLCoutListener(const LISTENER& listener): super(listener) {} /// call virtual bool operator()(const LLSD& event) { std::cout << "Entering listener " << *super::mName << " with " << event << std::endl; bool handled = super::operator()(event); std::cout << "Leaving listener " << *super::mName; if (handled) { std::cout << " (handled)"; } std::cout << std::endl; return handled; } }; LLLISTENER_WRAPPER_SUBCLASS(LLCoutListener); /** * This LLListenerWrapper template subclass is used to log entry/exit to an * event listener, by changing this: * @code * someEventPump.listen("MyClass", * boost::bind(&MyClass::method, ptr, _1)); * @endcode * to this: * @code * someEventPump.listen("MyClass", * llwrap<LLLogListener>( * boost::bind(&MyClass::method, ptr, _1))); * @endcode */ template <class LISTENER> class LLLogListener: public LLListenerWrapper<LISTENER> { typedef LLListenerWrapper<LISTENER> super; public: /// Wrap an arbitrary listener object LLLogListener(const LISTENER& listener): super(listener) {} /// call virtual bool operator()(const LLSD& event) { LL_DEBUGS("LLLogListener") << "Entering listener " << *super::mName << " with " << event << LL_ENDL; bool handled = super::operator()(event); LL_DEBUGS("LLLogListener") << "Leaving listener " << *super::mName; if (handled) { LL_CONT << " (handled)"; } LL_CONT << LL_ENDL; return handled; } }; LLLISTENER_WRAPPER_SUBCLASS(LLLogListener); #endif /* ! defined(LL_LLLISTENERWRAPPER_H) */