Author: mir3x
Date: Tue Aug 16 17:43:49 2016
New Revision: 33625

URL: http://svn.gna.org/viewcvs/freeciv?rev=33625&view=rev
Log:
Qt client - add class to ease wrapping the C API
Patch by Louis Moureaux <louis94>

See patch #7490


Added:
    trunk/client/gui-qt/listener.h
Modified:
    trunk/client/gui-qt/Makefile.am

Modified: trunk/client/gui-qt/Makefile.am
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/client/gui-qt/Makefile.am?rev=33625&r1=33624&r2=33625&view=diff
==============================================================================
--- trunk/client/gui-qt/Makefile.am     (original)
+++ trunk/client/gui-qt/Makefile.am     Tue Aug 16 17:43:49 2016
@@ -72,6 +72,7 @@
        helpdlg.h       \
        inteldlg.cpp    \
        inteldlg.h      \
+       listener.h      \
        luaconsole.cpp  \
        luaconsole.h    \
        mapctrl.cpp     \

Added: trunk/client/gui-qt/listener.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/client/gui-qt/listener.h?rev=33625&view=auto
==============================================================================
--- trunk/client/gui-qt/listener.h      (added)
+++ trunk/client/gui-qt/listener.h      Tue Aug 16 17:43:49 2016
@@ -0,0 +1,201 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either 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; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+***********************************************************************/
+
+#ifndef FC__LISTENER_H
+#define FC__LISTENER_H
+
+#include <set>
+
+/***************************************************************************
+  Helper template to connect C and C++ code.
+
+  This class is a helper to create Java-like "listeners" for "events"
+  generated in C code. If the C interface defines a callback foo() and
+  you want to use it as an event, you first declare a C++ interface:
+
+  ~~~~~{.cpp}
+  class foo_listener : public listener<foo_listener>
+  {
+  public:
+    virtual void foo() = 0;
+  };
+  ~~~~~
+
+  The listener needs some static data. Declaring it is as simple as putting
+  a macro in some source file:
+
+  ~~~~~{.cpp}
+  FC_CPP_DECLARE_LISTENER(foo_listener)
+  ~~~~~
+
+  Then, you call the listeners from the implementation of the C interface:
+
+  ~~~~~{.cpp}
+  void foo()
+  {
+    foo_listener::invoke(&foo_listener::foo);
+  }
+  ~~~~~
+
+  This will invoke foo() on all foo_listener objects.
+
+  == Listening to events
+
+  Listening to events is done by inheriting from a listener. When your
+  object is ready to receive events, it should call the listener's @c listen
+  function. This will typically be done in the constructor:
+
+  ~~~~~{.cpp}
+  class bar : private foo_listener
+  {
+  public:
+    explicit bar();
+    void foo();
+  };
+
+  bar::bar()
+  {
+    // Initialize the object here
+    foo_listener::listen();
+  }
+  ~~~~~
+
+  == Passing arguments
+
+  Passing arguments to the listeners is very simple: you write them after
+  the function pointer. For instance, let's say foo() takes an int. It can
+  be passed to the listeners as follows:
+
+  ~~~~~{.cpp}
+  void foo(int argument)
+  {
+    foo_listener::invoke(&foo_listener::foo, argument);
+  }
+  ~~~~~
+
+  As there may be an arbitrary number of listeners, passing mutable data
+  through invoke() is discouraged.
+
+  == Technical details
+
+  This class achieves its purpose using the Curiously Recurring Template
+  Pattern, hence the weird parent for listeners:
+
+  ~~~~~{.cpp}
+  class foo_listener : public listener<foo_listener>
+  ~~~~~
+
+  The template argument is used to specialize object storage and member
+  function invocation. Compilers should be able to inline calls to invoke(),
+  leaving only the overhead of looping on all instances.
+
+  FIXME Implementation is not thread-safe. I don't know if it's needed.
+***************************************************************************/
+template<class _type_>
+class listener
+{
+public:
+  // The type a given specialization supports.
+  typedef _type_ type_t;
+
+private:
+  // All instances of type_t that have called listen().
+  static std::set<type_t *> instances;
+
+protected:
+  explicit listener();
+  virtual ~listener();
+
+  void listen();
+
+public:
+  template<class _member_fct_>
+  static void invoke(_member_fct_ function);
+
+  template<class _member_fct_, class _arg1_t_>
+  static void invoke(_member_fct_ function, _arg1_t_ arg);
+};
+
+/***************************************************************************
+  Macro to declare the static data needed by listener<> classes
+***************************************************************************/
+#define FC_CPP_DECLARE_LISTENER(_type_) \
+  template<> \
+  std::set<_type_ *> listener<_type_>::instances = std::set<_type_ *>();
+
+/***************************************************************************
+  Constructor
+***************************************************************************/
+template<class _type_>
+listener<_type_>::listener()
+{}
+
+/***************************************************************************
+  Starts listening to events
+***************************************************************************/
+template<class _type_>
+void listener<_type_>::listen()
+{
+  // If you get an error here, your listener likely doesn't inherit from the
+  // listener<> correctly. See the class documentation.
+  instances.insert(static_cast<type_t *>(this));
+}
+
+/***************************************************************************
+  Destructor
+***************************************************************************/
+template<class _type_>
+listener<_type_>::~listener()
+{
+  instances.erase(static_cast<type_t *>(this));
+}
+
+/***************************************************************************
+  Invokes a member function on all instances of an listener type. Template
+  parameters are meant to be automatically deduced.
+
+  Zero-parameter overload.
+
+  @param function The member function to call
+***************************************************************************/
+template<class _type_>
+template<class _member_fct_>
+void listener<_type_>::invoke(_member_fct_ function)
+{
+  typename std::set<type_t *>::iterator it = instances.begin();
+  typename std::set<type_t *>::iterator end = instances.end();
+  for ( ; it != end; ++it) {
+    ((*it)->*function)();
+  }
+}
+
+/***************************************************************************
+  Invokes a member function on all instances of an listener type. Template
+  parameters are meant to be automatically deduced.
+
+  One-parameter overload.
+
+  @param function The member function to call
+  @param arg      The argument to call the function with
+***************************************************************************/
+template<class _type_>
+template<class _member_fct_, class _arg1_t_>
+void listener<_type_>::invoke(_member_fct_ function, _arg1_t_ arg)
+{
+  typename std::set<type_t *>::iterator it = instances.begin();
+  typename std::set<type_t *>::iterator end = instances.end();
+  for ( ; it != end; ++it) {
+    ((*it)->*function)(arg);
+  }
+}
+
+#endif // FC__LISTENER_H


_______________________________________________
Freeciv-commits mailing list
Freeciv-commits@gna.org
https://mail.gna.org/listinfo/freeciv-commits

Reply via email to