Add helper classes to improve callback handling.
This commit is contained in:
parent
453f3d5a8c
commit
49b298b8a5
3 changed files with 211 additions and 0 deletions
|
@ -383,6 +383,7 @@ available space. The documentation of that algorithm is written in
|
|||
doxygen\footnote{\url{http://devdocs.wesnoth.org/layout_algorihm.html}}.
|
||||
|
||||
\section{Event handling and dispatching}
|
||||
\label{event_handling}
|
||||
|
||||
The event handling translates the ``raw'' SDL events to an event structure
|
||||
specific to gui2, effectively decoupling the interface. This also allows adding
|
||||
|
@ -499,5 +500,44 @@ travelling policy, but it won't get cheap}. So in the same spirit that the
|
|||
standard library doesn't add operator[] for std::list I omitted the postfix
|
||||
increment operator.
|
||||
|
||||
|
||||
\section{Callbacks}
|
||||
|
||||
\S~\ref{event_handling} describes the generic event handling for the widgets but
|
||||
in some cases a widget wants to notify other widgets of a state change. Parts of
|
||||
gui2 use simple C-style callbacks for that purpose, but using boost::function
|
||||
makes better replacement. Therefore the code was analysed closer and another
|
||||
problem should be rectified; The callback causes a binding between two objects,
|
||||
but they are not notified of the deletion of the object leaving a hole for
|
||||
calling a destroyed object.
|
||||
|
||||
In order to fix the problem two classes are defined:
|
||||
|
||||
\begin{description}
|
||||
\item[tnotifier] The class sending the wanted notification.
|
||||
\item[tnotifiee] The class to manage the lifetime of the connection.
|
||||
\end{description}
|
||||
|
||||
The tnotifiee is a small class that holds a pointer to the receiver its
|
||||
connected to, upon destruction it uses this pointer to deregister itself by the
|
||||
receiver. There after the callback function will no longer be called.
|
||||
|
||||
The class should be used as member of a class so it can manage the lifetime of
|
||||
the connection with the tnotifier.
|
||||
|
||||
\paragraph{}
|
||||
|
||||
The tnotifier is the main class, when a callback is registered it stores the
|
||||
callbacks in an internal list and updates the pointer in the tnotifiee to
|
||||
itself.
|
||||
|
||||
Upon destruction it clears the pointer in all tnotifiees that point to use, that
|
||||
way upon destruction of the tnotifiee it won't try to deregister itself with
|
||||
this destroyed object.
|
||||
|
||||
Subclasses of the tnotifier should add an notification function so the notifier
|
||||
can call all callbacks in the list. The notifier should take care of this
|
||||
calling.
|
||||
|
||||
\end{document}
|
||||
|
||||
|
|
56
src/gui/auxiliary/notifiee.hpp
Normal file
56
src/gui/auxiliary/notifiee.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 by Mark de Wever <koraq@xs4all.nl>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef GUI_WIDGETS_AUXILIARY_NOTIFIEE_HPP_INCLUDED
|
||||
#define GUI_WIDGETS_AUXILIARY_NOTIFIEE_HPP_INCLUDED
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
template<class T>
|
||||
class tnotifier;
|
||||
|
||||
/**
|
||||
* Helper class to implement callbacks with lifetime management.
|
||||
*
|
||||
* This part manages the lifetime off the callback.
|
||||
*/
|
||||
template<class FUNCTOR>
|
||||
class tnotifiee
|
||||
{
|
||||
public:
|
||||
typedef FUNCTOR tfunctor;
|
||||
friend class tnotifier<tfunctor>;
|
||||
|
||||
tnotifiee()
|
||||
: notifier_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~tnotifiee()
|
||||
{
|
||||
if(notifier_) {
|
||||
notifier_->disconnect_notifiee(*this);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** Pointer the the tnotifier that's linked to us. */
|
||||
tnotifier<tfunctor> *notifier_;
|
||||
};
|
||||
|
||||
} //namespace gui2
|
||||
|
||||
#endif
|
||||
|
115
src/gui/auxiliary/notifier.hpp
Normal file
115
src/gui/auxiliary/notifier.hpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 by Mark de Wever <koraq@xs4all.nl>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef GUI_WIDGETS_AUXILIARY_NOTIFIER_HPP_INCLUDED
|
||||
#define GUI_WIDGETS_AUXILIARY_NOTIFIER_HPP_INCLUDED
|
||||
|
||||
#include "foreach.hpp"
|
||||
|
||||
#include "gui/auxiliary/notifiee.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
/**
|
||||
* Helper class to implement callbacks with lifetime management.
|
||||
*
|
||||
* This part manages the connecting and disconnecting of the callbacks.
|
||||
*
|
||||
* Subclasses should implement a way to call all callback.
|
||||
*/
|
||||
template<class FUNCTOR>
|
||||
class tnotifier
|
||||
{
|
||||
public:
|
||||
|
||||
typedef FUNCTOR tfunctor;
|
||||
|
||||
tnotifier()
|
||||
: notifiees_()
|
||||
{
|
||||
}
|
||||
|
||||
~tnotifier()
|
||||
{
|
||||
typedef std::pair<tnotifiee<tfunctor>* const, tfunctor> thack;
|
||||
foreach(thack& item, notifiees_) {
|
||||
assert(item.first);
|
||||
assert((*item.first).notifier_ == this);
|
||||
|
||||
(*item.first).notifier_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a callback.
|
||||
*
|
||||
* @param notifiee The notifiee controlling the lifetime of
|
||||
* the callback.
|
||||
* @param functor The callback to call.
|
||||
*/
|
||||
void connect_notifiee(
|
||||
tnotifiee<tfunctor>& notifiee
|
||||
, tfunctor functor)
|
||||
{
|
||||
notifiees_.insert(std::make_pair(¬ifiee, functor));
|
||||
|
||||
assert(!notifiee.notifier_);
|
||||
|
||||
notifiee.notifier_ = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disonnects a callback.
|
||||
*
|
||||
* @param notifiee The notifiee controlling the lifetime of
|
||||
* the callback. Uses since its address is an
|
||||
* unique key.
|
||||
*/
|
||||
void disconnect_notifiee(tnotifiee<tfunctor>& notifiee)
|
||||
{
|
||||
typename std::map<tnotifiee<tfunctor>*, tfunctor>::iterator
|
||||
itor = notifiees_.find(¬ifiee);
|
||||
|
||||
if(itor != notifiees_.end()) {
|
||||
|
||||
assert(notifiee.notifier_ == this);
|
||||
|
||||
notifiee.notifier_ = NULL;
|
||||
|
||||
notifiees_.erase(itor);
|
||||
}
|
||||
}
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
const std::map<tnotifiee<tfunctor>*, tfunctor>& notifiees() const
|
||||
{
|
||||
return notifiees_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** List of registered callbacks. */
|
||||
std::map<tnotifiee<tfunctor>*, tfunctor> notifiees_;
|
||||
|
||||
};
|
||||
|
||||
} //namespace gui2
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue