Pārlūkot izejas kodu

Signals must now be published under specific topics using EventAdmin.

Sascha Zelzer 13 gadi atpakaļ
vecāks
revīzija
0db2934adf

+ 4 - 4
Libs/PluginFramework/Testing/EventAdminTest/ctkEAScenario1TestSuite.cpp

@@ -220,8 +220,8 @@ void ctkEAScenario1EventPublisher::runTest()
 
   if (useSignalSlot)
   {
-    eventAdmin->publishSignal(this, SIGNAL(syncSignalEvent(ctkEvent)), Qt::DirectConnection);
-    eventAdmin->publishSignal(this, SIGNAL(asyncSignalEvent(ctkEvent)), Qt::QueuedConnection);
+    eventAdmin->publishSignal(this, SIGNAL(syncSignalEvent(ctkDictionary)), "com/acme/timer", Qt::DirectConnection);
+    eventAdmin->publishSignal(this, SIGNAL(asyncSignalEvent(ctkDictionary)), "com/acme/timer", Qt::QueuedConnection);
   }
 
   /* start the delivery thread */
@@ -264,7 +264,7 @@ void ctkEAScenario1EventPublisher::sendEvents()
     ctkEvent event("com/acme/timer", message);
     if (useSignalSlot)
     {
-      emit syncSignalEvent(event);
+      emit syncSignalEvent(message);
     }
     else
     {
@@ -288,7 +288,7 @@ void ctkEAScenario1EventPublisher::postEvents()
     ctkEvent event("com/acme/timer", message);
     if (useSignalSlot)
     {
-      emit asyncSignalEvent(event);
+      emit asyncSignalEvent(message);
     }
     else
     {

+ 2 - 2
Libs/PluginFramework/Testing/EventAdminTest/ctkEAScenario1TestSuite_p.h

@@ -138,8 +138,8 @@ protected slots:
 
 signals:
 
-  void syncSignalEvent(const ctkEvent&);
-  void asyncSignalEvent(const ctkEvent&);
+  void syncSignalEvent(const ctkDictionary&);
+  void asyncSignalEvent(const ctkDictionary&);
 };
 
 /**

+ 2 - 2
Libs/PluginFramework/Testing/EventAdminTest/ctkEATopicWildcardTestSuite.cpp

@@ -78,7 +78,7 @@ void ctkEATopicWildcardTestSuite::init()
 
   if (useSignalSlot)
   {
-    eventAdmin->publishSignal(this, SIGNAL(syncSignal(ctkEvent)), Qt::DirectConnection);
+    eventAdmin->publishSignal(this, SIGNAL(syncSignal(ctkDictionary)), "a/b/c", Qt::DirectConnection);
   }
 }
 
@@ -100,7 +100,7 @@ void ctkEATopicWildcardTestSuite::testEventDeliveryForWildcardTopic1()
   if (useSignalSlot)
   {
     qlonglong id = eventAdmin->subscribeSlot(&handler, SLOT(handleEvent(ctkEvent)), properties);
-    emit syncSignal(event);
+    emit syncSignal(ctkDictionary());
     eventAdmin->unsubscribeSlot(id);
   }
   else

+ 1 - 1
Libs/PluginFramework/Testing/EventAdminTest/ctkEATopicWildcardTestSuite_p.h

@@ -69,7 +69,7 @@ public:
 
 signals:
 
-  void syncSignal(const ctkEvent& event);
+  void syncSignal(const ctkDictionary& event);
 
 private slots:
 

+ 33 - 0
Libs/PluginFramework/service/event/ctkEventAdmin.h

@@ -64,15 +64,48 @@ struct ctkEventAdmin
    * Qt::QueuedConnection and as sendEvent() if <code>type</code> is
    * Qt::DirectConnection.
    *
+   * The signal will be associated with the given topic and must have the
+   * following signature:
+   * \code
+   * someSignal(const ctkDictionary& props)
+   * \endcode
+   * where <code>props</code> will be used to construct a ctkEvent class which
+   * will additionally have the EVENT_TOPIC property set to the given <code>topic</code>.
+   *
+   * This method can be called multiple times for the same signal to publish
+   * it under multiple topics. In that case, emitting the signal will result in
+   * multiple events being send.
+   *
    * @param publisher The owner of the signal.
    * @param signal The signal in normalized form.
+   * @param topic The event topic to use.
    * @param type Qt::QueuedConnection for asynchronous delivery and
    *        Qt::DirectConnection for synchronous delivery.
+   *
+   * @see unpublishSignal()
    */
   virtual void publishSignal(const QObject* publisher, const char* signal,
+                             const QString& topic,
                              Qt::ConnectionType type = Qt::QueuedConnection) = 0;
 
   /**
+   * Unpublish (unregister) a previously published signal. After unpublishing a
+   * signal, no events will be send when the signal is emitted.
+   *
+   * @param publisher The owner of the signal.
+   * @param signal The signal in normalized form. If the signal is <code>NULL</code>
+   *        all signals from the given publisher published under the given
+   *        <code>topic</code> will be unpublished.
+   * @param topic The event topic under which the given <code>signal</code> was
+   *        published. If the <code>topic</code> is empty, the signal is
+   *        unpublished for all topics it was previously pubished under.
+   *
+   * @see publishSlot()
+   */
+  virtual void unpublishSignal(const QObject* publisher, const char* signal = 0,
+                               const QString& topic = "") = 0;
+
+  /**
    * Subsribe for (observe) events. The slot is called whenever an event is sent
    * which matches the topic string and LDAP search expression contained
    * in the properties.

+ 79 - 3
Plugins/org.commontk.eventadmin/ctkEventAdminService.cpp

@@ -33,7 +33,7 @@ ctkEventAdminService::ctkEventAdminService(ctkPluginContext* context,
                                            int timeout,
                                            const QStringList& ignoreTimeout)
   : impl(managers, syncPool, asyncPool, timeout, ignoreTimeout),
-    context(context), signalPublisher(this)
+    context(context)
 {
 
 }
@@ -54,15 +54,37 @@ void ctkEventAdminService::sendEvent(const ctkEvent& event)
 }
 
 void ctkEventAdminService::publishSignal(const QObject* publisher, const char* signal,
+                                         const QString& topic,
                                          Qt::ConnectionType type)
 {
+  if (topic.isEmpty())
+  {
+    throw std::invalid_argument("topic must not be empty");
+  }
+
+  // check if the signal was already registered under the given topic
+  if (signalPublisher.contains(publisher))
+  {
+    const QList<ctkEASignalPublisher*>& signalPublishers = signalPublisher[publisher];
+    for(int i = 0; i < signalPublishers.size(); ++i)
+    {
+      if (signalPublishers[i]->getSignalName() == signal &&
+          signalPublishers[i]->getTopicName() == topic)
+      {
+        return;
+      }
+    }
+  }
+
+  QList<ctkEASignalPublisher*>& signalList = signalPublisher[publisher];
+  signalList.push_back(new ctkEASignalPublisher(this, signal, topic));
   if (type == Qt::DirectConnection)
   {
-    connect(publisher, signal, &signalPublisher, SLOT(publishSyncSignal(ctkEvent)), Qt::DirectConnection);
+    connect(publisher, signal, signalList.back(), SLOT(publishSyncSignal(ctkDictionary)), Qt::DirectConnection);
   }
   else if (type == Qt::QueuedConnection)
   {
-    connect(publisher, signal, &signalPublisher, SLOT(publishAsyncSignal(ctkEvent)), Qt::DirectConnection);
+    connect(publisher, signal, signalList.back(), SLOT(publishAsyncSignal(ctkDictionary)), Qt::DirectConnection);
   }
   else
   {
@@ -70,6 +92,60 @@ void ctkEventAdminService::publishSignal(const QObject* publisher, const char* s
   }
 }
 
+void ctkEventAdminService::unpublishSignal(const QObject* publisher, const char* signal,
+                                           const QString& topic)
+{
+  if (!signalPublisher.contains(publisher)) return;
+
+  if (signal == 0 && topic.isEmpty())
+  {
+    // unpublish everything from the given publisher
+    // this automatically disconnects signals
+    qDeleteAll(signalPublisher.take(publisher));
+  }
+  else
+  {
+    QList<ctkEASignalPublisher*>& list = signalPublisher[publisher];
+    if (signal == 0)
+    {
+      for (int i = 0; i < list.size(); )
+      {
+        if (list[i]->getTopicName() == topic)
+        {
+          // this automatically disconnects the signals
+          delete list.takeAt(i);
+        }
+        else
+        {
+          ++i;
+        }
+      }
+    }
+    else {
+      for (int i = 0; i < list.size(); )
+      {
+        if (list[i]->getSignalName() == signal)
+        {
+          if (topic.isEmpty() || list[i]->getTopicName() == topic)
+          {
+            // this automatically disconnects the signals
+            delete list.takeAt(i);
+          }
+        }
+        else
+        {
+          ++i;
+        }
+      }
+    }
+
+    if (list.isEmpty())
+    {
+      signalPublisher.remove(publisher);
+    }
+  }
+}
+
 qlonglong ctkEventAdminService::subscribeSlot(const QObject* subscriber, const char* member, const ctkDictionary& properties)
 {
   ctkEASlotHandler* handler = new ctkEASlotHandler();

+ 5 - 1
Plugins/org.commontk.eventadmin/ctkEventAdminService_p.h

@@ -71,7 +71,7 @@ private:
   ctkEventAdminImpl<BlacklistingHandlerTasks, SyncDeliverTasks, AsyncDeliverTasks> impl;
 
   ctkPluginContext* context;
-  ctkEASignalPublisher signalPublisher;
+  QHash<const QObject*, QList<ctkEASignalPublisher*> > signalPublisher;
   QHash<qlonglong, ctkEASlotHandler*> slotHandler;
 
 public:
@@ -89,8 +89,12 @@ public:
   void sendEvent(const ctkEvent& event);
 
   void publishSignal(const QObject* publisher, const char* signal,
+                     const QString& topic,
                      Qt::ConnectionType type = Qt::QueuedConnection);
 
+  void unpublishSignal(const QObject* publisher, const char* signal = 0,
+                       const QString& topic = "");
+
   qlonglong subscribeSlot(const QObject* subscriber, const char* member, const ctkDictionary& properties);
 
   void unsubscribeSlot(qlonglong subscriptionId);

+ 23 - 5
Plugins/org.commontk.eventadmin/dispatch/ctkEASignalPublisher.cpp

@@ -22,19 +22,37 @@
 
 #include "ctkEASignalPublisher_p.h"
 
-#include <service/event/ctkEventAdmin.h>
+#include "ctkEventAdminService_p.h"
 
-ctkEASignalPublisher::ctkEASignalPublisher(ctkEventAdmin* eventAdmin)
-  : eventAdmin(eventAdmin)
+ctkEASignalPublisher::ctkEASignalPublisher(ctkEventAdminService* eventAdmin,
+                                           const QString& signal,
+                                           const QString& topic)
+  : eventAdmin(eventAdmin), signal(signal), topic(topic)
 {
 }
 
-void ctkEASignalPublisher::publishSyncSignal(const ctkEvent& event)
+QString ctkEASignalPublisher::getSignalName() const
 {
+  return signal;
+}
+
+QString ctkEASignalPublisher::getTopicName() const
+{
+  return topic;
+}
+
+void ctkEASignalPublisher::publishSyncSignal(const ctkDictionary& eventProps)
+{
+  ctkDictionary props(eventProps);
+  props.insert(ctkEventConstants::EVENT_TOPIC, topic);
+  ctkEvent event(topic, props);
   eventAdmin->sendEvent(event);
 }
 
-void ctkEASignalPublisher::publishAsyncSignal(const ctkEvent& event)
+void ctkEASignalPublisher::publishAsyncSignal(const ctkDictionary& eventProps)
 {
+  ctkDictionary props(eventProps);
+  props.insert(ctkEventConstants::EVENT_TOPIC, topic);
+  ctkEvent event(topic, props);
   eventAdmin->postEvent(event);
 }

+ 11 - 5
Plugins/org.commontk.eventadmin/dispatch/ctkEASignalPublisher_p.h

@@ -27,23 +27,29 @@
 
 #include <service/event/ctkEvent.h>
 
-struct ctkEventAdmin;
+struct ctkEventAdminService;
 
 class ctkEASignalPublisher : public QObject
 {
   Q_OBJECT
 
 public:
-  ctkEASignalPublisher(ctkEventAdmin* eventAdmin);
+  ctkEASignalPublisher(ctkEventAdminService* eventAdmin,
+                       const QString& signal, const QString& topic);
+
+  QString getSignalName() const;
+  QString getTopicName() const;
 
 protected slots:
 
-  void publishSyncSignal(const ctkEvent& event);
-  void publishAsyncSignal(const ctkEvent& event);
+  void publishSyncSignal(const ctkDictionary& eventProps);
+  void publishAsyncSignal(const ctkDictionary& eventProps);
 
 private:
 
-  ctkEventAdmin* eventAdmin;
+  ctkEventAdminService* eventAdmin;
+  const QString signal;
+  const QString topic;
 };
 
 #endif // CTKEASIGNALPUBLISHER_P_H