PageRenderTime 9ms CodeModel.GetById 1ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/lllistenerwrapper.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 198 lines | 96 code | 18 blank | 84 comment | 2 complexity | e286efc55950535cfd85de1808687d51 MD5 | raw file
  1/**
  2 * @file   lllistenerwrapper.h
  3 * @author Nat Goodspeed
  4 * @date   2009-11-30
  5 * @brief  Introduce LLListenerWrapper template
  6 * 
  7 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#if ! defined(LL_LLLISTENERWRAPPER_H)
 30#define LL_LLLISTENERWRAPPER_H
 31
 32#include "llevents.h"               // LLListenerWrapperBase
 33#include <boost/visit_each.hpp>
 34
 35/**
 36 * Template base class for coding wrappers for LLEventPump listeners.
 37 *
 38 * Derive your listener wrapper from LLListenerWrapper. You must use
 39 * LLLISTENER_WRAPPER_SUBCLASS() so your subclass will play nicely with
 40 * boost::visit_each (q.v.). That way boost::signals2 can still detect
 41 * derivation from LLEventTrackable, and so forth.
 42 */
 43template <typename LISTENER>
 44class LLListenerWrapper: public LLListenerWrapperBase
 45{
 46public:
 47    /// Wrap an arbitrary listener object
 48    LLListenerWrapper(const LISTENER& listener):
 49        mListener(listener)
 50    {}
 51
 52    /// call
 53    virtual bool operator()(const LLSD& event)
 54    {
 55        return mListener(event);
 56    }
 57
 58    /// Allow boost::visit_each() to peek at our mListener.
 59    template <class V>
 60    void accept_visitor(V& visitor) const
 61    {
 62        using boost::visit_each;
 63        visit_each(visitor, mListener, 0);
 64    }
 65
 66private:
 67    LISTENER mListener;
 68};
 69
 70/**
 71 * Specialize boost::visit_each() (leveraging ADL) to peek inside an
 72 * LLListenerWrapper<T> to traverse its LISTENER. We borrow the
 73 * accept_visitor() pattern from boost::bind(), avoiding the need to make
 74 * mListener public.
 75 */
 76template <class V, typename T>
 77void visit_each(V& visitor, const LLListenerWrapper<T>& wrapper, int)
 78{
 79    wrapper.accept_visitor(visitor);
 80}
 81
 82/// use this (sigh!) for each subclass of LLListenerWrapper<T> you write
 83#define LLLISTENER_WRAPPER_SUBCLASS(CLASS)                              \
 84template <class V, typename T>                                          \
 85void visit_each(V& visitor, const CLASS<T>& wrapper, int)               \
 86{                                                                       \
 87    visit_each(visitor, static_cast<const LLListenerWrapper<T>&>(wrapper), 0); \
 88}                                                                       \
 89                                                                        \
 90/* Have to state this explicitly, rather than using LL_TEMPLATE_CONVERTIBLE, */ \
 91/* because the source type is itself a template. */                     \
 92template <typename T>                                                   \
 93struct ll_template_cast_impl<const LLListenerWrapperBase*, const CLASS<T>*> \
 94{                                                                       \
 95    const LLListenerWrapperBase* operator()(const CLASS<T>* wrapper)    \
 96    {                                                                   \
 97        return wrapper;                                                 \
 98    }                                                                   \
 99}
100
101/**
102 * Make an instance of a listener wrapper. Every wrapper class must be a
103 * template accepting a listener object of arbitrary type. In particular, the
104 * type of a boost::bind() expression is deliberately undocumented. So we
105 * can't just write Wrapper<CorrectType>(boost::bind(...)). Instead we must
106 * write llwrap<Wrapper>(boost::bind(...)).
107 */
108template <template<typename> class WRAPPER, typename T>
109WRAPPER<T> llwrap(const T& listener)
110{
111    return WRAPPER<T>(listener);
112}
113
114/**
115 * This LLListenerWrapper template subclass is used to report entry/exit to an
116 * event listener, by changing this:
117 * @code
118 * someEventPump.listen("MyClass",
119 *                      boost::bind(&MyClass::method, ptr, _1));
120 * @endcode
121 * to this:
122 * @code
123 * someEventPump.listen("MyClass",
124 *                      llwrap<LLCoutListener>(
125 *                      boost::bind(&MyClass::method, ptr, _1)));
126 * @endcode
127 */
128template <class LISTENER>
129class LLCoutListener: public LLListenerWrapper<LISTENER>
130{
131    typedef LLListenerWrapper<LISTENER> super;
132
133public:
134    /// Wrap an arbitrary listener object
135    LLCoutListener(const LISTENER& listener):
136        super(listener)
137    {}
138
139    /// call
140    virtual bool operator()(const LLSD& event)
141    {
142        std::cout << "Entering listener " << *super::mName << " with " << event << std::endl;
143        bool handled = super::operator()(event);
144        std::cout << "Leaving  listener " << *super::mName;
145        if (handled)
146        {
147            std::cout << " (handled)";
148        }
149        std::cout << std::endl;
150        return handled;
151    }
152};
153
154LLLISTENER_WRAPPER_SUBCLASS(LLCoutListener);
155
156/**
157 * This LLListenerWrapper template subclass is used to log entry/exit to an
158 * event listener, by changing this:
159 * @code
160 * someEventPump.listen("MyClass",
161 *                      boost::bind(&MyClass::method, ptr, _1));
162 * @endcode
163 * to this:
164 * @code
165 * someEventPump.listen("MyClass",
166 *                      llwrap<LLLogListener>(
167 *                      boost::bind(&MyClass::method, ptr, _1)));
168 * @endcode
169 */
170template <class LISTENER>
171class LLLogListener: public LLListenerWrapper<LISTENER>
172{
173    typedef LLListenerWrapper<LISTENER> super;
174
175public:
176    /// Wrap an arbitrary listener object
177    LLLogListener(const LISTENER& listener):
178        super(listener)
179    {}
180
181    /// call
182    virtual bool operator()(const LLSD& event)
183    {
184        LL_DEBUGS("LLLogListener") << "Entering listener " << *super::mName << " with " << event << LL_ENDL;
185        bool handled = super::operator()(event);
186        LL_DEBUGS("LLLogListener") << "Leaving  listener " << *super::mName;
187        if (handled)
188        {
189            LL_CONT << " (handled)";
190        }
191        LL_CONT << LL_ENDL;
192        return handled;
193    }
194};
195
196LLLISTENER_WRAPPER_SUBCLASS(LLLogListener);
197
198#endif /* ! defined(LL_LLLISTENERWRAPPER_H) */