]> git.mxchange.org Git - simgear.git/commitdiff
HTTPRequest/pkg::Install: do not replace callbacks.
authorThomas Geymayer <tomgey@gmail.com>
Mon, 30 Jun 2014 16:22:24 +0000 (18:22 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Mon, 30 Jun 2014 16:22:24 +0000 (18:22 +0200)
Keep a list of callbacks to allow registering multiple callbacks
to the same event. This is consistent with eg. jQuery.Deferred
and is needed for example to open multiple dialogs showing the
progress of installing a package at the same time.

simgear/io/HTTPRequest.cxx
simgear/io/HTTPRequest.hxx
simgear/package/Install.cxx
simgear/package/Install.hxx
simgear/structure/CMakeLists.txt
simgear/structure/detail/function_list_template.hxx [new file with mode: 0644]
simgear/structure/function_list.hxx [new file with mode: 0644]
simgear/structure/function_list_test.cxx [new file with mode: 0644]

index 900b7fc29f9178ea9d2a572752e8af0b2bbe9bc5..0809c70a4194128f1ddbc9d7b3908835e264e712 100644 (file)
@@ -39,7 +39,7 @@ Request* Request::done(const Callback& cb)
   if( _ready_state == DONE )
     cb(this);
   else
-    _cb_done = cb;
+    _cb_done.push_back(cb);
 
   return this;
 }
@@ -50,7 +50,7 @@ Request* Request::fail(const Callback& cb)
   if( _ready_state == FAILED )
     cb(this);
   else
-    _cb_fail = cb;
+    _cb_fail.push_back(cb);
 
   return this;
 }
@@ -61,7 +61,7 @@ Request* Request::always(const Callback& cb)
   if( isComplete() )
     cb(this);
   else
-    _cb_always = cb;
+    _cb_always.push_back(cb);
 
   return this;
 }
@@ -321,22 +321,19 @@ void Request::setReadyState(ReadyState state)
     onDone();
     onAlways();
 
-    if( _cb_done )
-      _cb_done(this);
+    _cb_done(this);
   }
   else if( state == FAILED )
   {
     onFail();
     onAlways();
 
-    if( _cb_fail )
-      _cb_fail(this);
+    _cb_fail(this);
   }
   else
     return;
 
-  if( _cb_always )
-    _cb_always(this);
+  _cb_always(this);
 }
 
 //------------------------------------------------------------------------------
index ef101b3f3e9fb8b26e55b3ac49bcea1cb17bdbac..f739d2b8f1640c425de8ab88ebd1091295f8fc77 100644 (file)
@@ -3,13 +3,13 @@
 
 #include <map>
 
+#include <simgear/structure/function_list.hxx>
 #include <simgear/structure/map.hxx>
 #include <simgear/structure/SGReferenced.hxx>
 #include <simgear/structure/SGSharedPtr.hxx>
 #include <simgear/math/sg_types.hxx>
 
 #include <boost/bind.hpp>
-#include <boost/function.hpp>
 
 class SGPropertyNode;
 
@@ -47,7 +47,7 @@ public:
                                             { return _request_headers.get(key); }
 
     /**
-     * Set the handler to be called when the request successfully completes.
+     * Add a handler to be called when the request successfully completes.
      *
      * @note If the request is already complete, the handler is called
      *       immediately.
@@ -61,7 +61,7 @@ public:
     }
 
     /**
-     * Set the handler to be called when the request completes or aborts with an
+     * Add a handler to be called when the request completes or aborts with an
      * error.
      *
      * @note If the request has already failed, the handler is called
@@ -76,8 +76,8 @@ public:
     }
 
     /**
-     * Set the handler to be called when the request either successfully
-     * completes or fails.
+     * Add a handler to be called when the request either successfully completes
+     * or fails.
      *
      * @note If the request is already complete or has already failed, the
      *       handler is called immediately.
@@ -224,9 +224,9 @@ private:
     unsigned int  _responseLength;
     unsigned int  _receivedBodyBytes;
 
-    Callback      _cb_done,
-                  _cb_fail,
-                  _cb_always;
+    function_list<Callback> _cb_done,
+                            _cb_fail,
+                            _cb_always;
 
     ReadyState    _ready_state;
     bool          _willClose;
index b5c9487d5f185fc616446a8ce5cea2dc2ebe4ced..659511ffd7cc14c0b7fcbdfcf08b7f6d8c08e1e3 100644 (file)
@@ -325,7 +325,7 @@ Install* Install::done(const Callback& cb)
   if( _status == Delegate::FAIL_SUCCESS )
     cb(this);
   else
-    _cb_done = cb;
+    _cb_done.push_back(cb);
 
   return this;
 }
@@ -337,7 +337,7 @@ Install* Install::fail(const Callback& cb)
       && _status != Delegate::FAIL_IN_PROGRESS )
     cb(this);
   else
-    _cb_fail = cb;
+    _cb_fail.push_back(cb);
 
   return this;
 }
@@ -348,7 +348,7 @@ Install* Install::always(const Callback& cb)
   if( _status != Delegate::FAIL_IN_PROGRESS )
     cb(this);
   else
-    _cb_always = cb;
+    _cb_always.push_back(cb);
 
   return this;
 }
@@ -356,7 +356,7 @@ Install* Install::always(const Callback& cb)
 //------------------------------------------------------------------------------
 Install* Install::progress(const ProgressCallback& cb)
 {
-  _cb_progress = cb;
+  _cb_progress.push_back(cb);
   return this;
 }
 
@@ -365,24 +365,20 @@ void Install::installResult(Delegate::FailureCode aReason)
 {
     if (aReason == Delegate::FAIL_SUCCESS) {
         m_package->catalog()->root()->finishInstall(this);
-        if( _cb_done )
-          _cb_done(this);
+        _cb_done(this);
     } else {
         m_package->catalog()->root()->failedInstall(this, aReason);
-        if( _cb_fail )
-          _cb_fail(this);
+        _cb_fail(this);
     }
 
-    if( _cb_always )
-      _cb_always(this);
+    _cb_always(this);
 }
 
 //------------------------------------------------------------------------------
 void Install::installProgress(unsigned int aBytes, unsigned int aTotal)
 {
-    m_package->catalog()->root()->installProgress(this, aBytes, aTotal);
-    if( _cb_progress )
-      _cb_progress(this, aBytes, aTotal);
+  m_package->catalog()->root()->installProgress(this, aBytes, aTotal);
+  _cb_progress(this, aBytes, aTotal);
 }
 
 
index 81cf580adee46d82e87f30f6aac878e39a453d92..e65789c4b33e0375a794b8fda399330e92505cbe 100644 (file)
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/package/Delegate.hxx>
 
+#include <simgear/structure/function_list.hxx>
 #include <simgear/structure/SGReferenced.hxx>
 #include <simgear/structure/SGSharedPtr.hxx>
 
 #include <boost/bind.hpp>
-#include <boost/function.hpp>
 
 namespace simgear
 {
@@ -156,11 +156,10 @@ private:
 
     Delegate::FailureCode _status;
 
-    Callback          _cb_done,
-                      _cb_fail,
-                      _cb_always;
-    ProgressCallback  _cb_progress;
-
+    function_list<Callback>         _cb_done,
+                                    _cb_fail,
+                                    _cb_always;
+    function_list<ProgressCallback> _cb_progress;
 };
     
     
index 7679588c2da830f52f652b9626591087cc47b8a0..0c41b6225a1ae98da9b801adf1b5295532dcd996 100644 (file)
@@ -21,12 +21,17 @@ set(HEADERS
     commands.hxx
     event_mgr.hxx
     exception.hxx
+    function_list.hxx
     intern.hxx
     map.hxx
     subsystem_mgr.hxx
     StateMachine.hxx
     )
 
+set(DETAIL_HEADERS
+  detail/function_list_template.hxx
+)
+
 set(SOURCES
     SGAtomic.cxx
     SGBinding.cxx
@@ -43,6 +48,7 @@ set(SOURCES
     )
 
 simgear_component(structure structure "${SOURCES}" "${HEADERS}")
+simgear_component(structure/detail structure/detail "" "${DETAIL_HEADERS}")
 
 if(ENABLE_TESTS)
 
@@ -56,6 +62,11 @@ add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions)
 
 endif(ENABLE_TESTS)
 
+add_boost_test(function_list
+  SOURCES function_list_test.cxx
+  LIBRARIES ${TEST_LIBS}
+)
+
 add_boost_test(shared_ptr
   SOURCES shared_ptr_test.cpp
   LIBRARIES ${TEST_LIBS}
diff --git a/simgear/structure/detail/function_list_template.hxx b/simgear/structure/detail/function_list_template.hxx
new file mode 100644 (file)
index 0000000..92a10a2
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SG_FUNCTION_LIST_HXX_
+# error function_list - do not include this file!
+#endif
+
+#ifndef SG_DONT_DO_ANYTHING
+#define n BOOST_PP_ITERATION()
+#define SG_FUNC_TYPE boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
+#define SG_LIST_TYPE std::vector<SG_FUNC_TYPE >
+
+template<class Ret BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)>
+class function_list<Ret (BOOST_PP_ENUM_PARAMS(n, A))>:
+  public SG_LIST_TYPE
+{
+  public:
+    typedef SG_FUNC_TYPE function_type;
+    typedef typename SG_LIST_TYPE::iterator iterator;
+    typedef typename SG_LIST_TYPE::const_iterator const_iterator;
+
+    Ret operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, A, a)) const
+    {
+      if( this->empty() )
+        return Ret();
+
+      const_iterator list_end = --this->end();
+      for(const_iterator f = this->begin(); f != list_end; ++f)
+        if( *f )
+          (*f)(BOOST_PP_ENUM_PARAMS(n, a));
+
+      return (*list_end) ? (*list_end)(BOOST_PP_ENUM_PARAMS(n, a)) : Ret();
+    }
+};
+
+#undef n
+#undef SG_FUNC_TYPE
+#undef SG_LIST_TYPE
+
+#endif // SG_DONT_DO_ANYTHING
diff --git a/simgear/structure/function_list.hxx b/simgear/structure/function_list.hxx
new file mode 100644 (file)
index 0000000..28ef08e
--- /dev/null
@@ -0,0 +1,51 @@
+///@file Handle a list of callbacks like a single boost::function
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef SG_FUNCTION_LIST_HXX_
+#define SG_FUNCTION_LIST_HXX_
+
+#include <boost/function.hpp>
+#include <boost/preprocessor/iteration/iterate.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <vector>
+
+namespace simgear
+{
+  template<typename Sig> class function_list;
+
+  // Build dependency for CMake, gcc, etc.
+# define SG_DONT_DO_ANYTHING
+#  include <simgear/structure/detail/function_list_template.hxx>
+# undef SG_DONT_DO_ANYTHING
+
+# define BOOST_PP_ITERATION_LIMITS (0, 3)
+# define BOOST_PP_FILENAME_1 <simgear/structure/detail/function_list_template.hxx>
+# include BOOST_PP_ITERATE()
+
+  template<typename Sig>
+  class function_list<boost::function<Sig> >:
+    public function_list<Sig>
+  {
+
+  };
+
+} // namespace simgear
+
+#endif /* SG_FUNCTION_LIST_HXX_ */
diff --git a/simgear/structure/function_list_test.cxx b/simgear/structure/function_list_test.cxx
new file mode 100644 (file)
index 0000000..58202c9
--- /dev/null
@@ -0,0 +1,77 @@
+#define BOOST_TEST_MODULE structurce
+#include <BoostTestTargetConfig.h>
+
+#include "function_list.hxx"
+
+static int func_called = 0,
+           func2_called = 0;
+
+int func(int x)
+{
+  ++func_called;
+  return x;
+}
+
+int func2(int x)
+{
+  ++func2_called;
+  return 2 * x;
+}
+
+int func_add(int x, int y)
+{
+  return func(x) + y;
+}
+
+int func2_add(int x, int y)
+{
+  return func2(x) + y;
+}
+
+static int func_void_called = 0;
+void func_void()
+{
+  ++func_void_called;
+}
+
+BOOST_AUTO_TEST_CASE( create_and_call )
+{
+  using namespace simgear;
+
+  function_list<int (int)> func_list;
+
+  BOOST_REQUIRE(func_list.empty());
+
+  func_list.push_back(&func);
+  BOOST_REQUIRE_EQUAL(func_list(2), 2);
+  BOOST_REQUIRE_EQUAL(func_called, 1);
+
+  func_list.push_back(&func2);
+  BOOST_REQUIRE_EQUAL(func_list(2), 4);
+  BOOST_REQUIRE_EQUAL(func_called, 2);
+  BOOST_REQUIRE_EQUAL(func2_called, 1);
+
+  function_list<boost::function<int (int)> > func_list2;
+  func_list2.push_back(&func);
+  func_list2.push_back(&func2);
+  func_list2.push_back(&func2);
+
+  BOOST_REQUIRE_EQUAL(func_list2(2), 4);
+  BOOST_REQUIRE_EQUAL(func_called, 3);
+  BOOST_REQUIRE_EQUAL(func2_called, 3);
+
+  // two parameters
+  function_list<boost::function<int (int, int)> > func_list3;
+  func_list3.push_back(&func_add);
+  func_list3.push_back(&func2_add);
+
+  BOOST_REQUIRE_EQUAL(func_list3(2, 3), 7);
+  BOOST_REQUIRE_EQUAL(func_called, 4);
+  BOOST_REQUIRE_EQUAL(func2_called, 4);
+
+  // returning void/no params
+  function_list<void()> void_func_list;
+  void_func_list.push_back(&func_void);
+  void_func_list();
+  BOOST_REQUIRE_EQUAL(func_void_called, 1);
+}