ctkEventDispatcher.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * ctkEventDispatcher.cpp
  3. * ctkEventBus
  4. *
  5. * Created by Paolo Quadrani on 27/03/09.
  6. * Copyright 2009 B3C. All rights reserved.
  7. *
  8. * See Licence at: http://tiny.cc/QXJ4D
  9. *
  10. */
  11. #include "ctkEventDispatcher.h"
  12. #include "ctkBusEvent.h"
  13. #define CALLBACK_SIGNATURE "1"
  14. #define SIGNAL_SIGNATURE "2"
  15. using namespace ctkEventBus;
  16. ctkEventDispatcher::ctkEventDispatcher() {
  17. }
  18. ctkEventDispatcher::~ctkEventDispatcher() {
  19. }
  20. bool ctkEventDispatcher::isLocalSignalPresent(const QString topic) const {
  21. return m_SignalsHash.values(topic).size() != 0;
  22. }
  23. void ctkEventDispatcher::resetHashes() {
  24. // delete all lists present into the hash.
  25. QHash<QString, ctkBusEvent *>::iterator i;
  26. for (i = m_CallbacksHash.begin(); i != m_CallbacksHash.end(); ++i) {
  27. delete i.value();
  28. }
  29. m_CallbacksHash.clear();
  30. for (i = m_SignalsHash.begin(); i != m_SignalsHash.end(); ++i) {
  31. delete i.value();
  32. }
  33. m_SignalsHash.clear();
  34. }
  35. void ctkEventDispatcher::initializeGlobalEvents() {
  36. ctkBusEvent *remote_done = new ctkBusEvent("ctk/local/eventBus/remoteCommunicationDone",ctkEventTypeLocal,ctkSignatureTypeSignal,this,"remoteCommunicationDone()");
  37. /*QString eventId = "ctk/local/eventBus/remoteCommunicationDone";
  38. (*remote_done)[TOPIC] = eventId;
  39. (*remote_done)[TYPE] = ctkEventTypeLocal;
  40. (*remote_done)[SIGTYPE] = mafSignatureTypeSignal;
  41. QVariant var;
  42. var.setValue((QObject*)this);
  43. (*remote_done)[OBJECT] = var;
  44. (*remote_done)[SIGNATURE] = "remoteCommunicationDone()";*/
  45. this->registerSignal(*remote_done);
  46. ctkBusEvent *remote_failed = new ctkBusEvent("ctk/local/eventBus/remoteCommunicationFailed",ctkEventTypeLocal,ctkSignatureTypeSignal,this, "remoteCommunicationFailed()");
  47. /*(*remote_failed)[TOPIC] = "ctk/local/eventBus/remoteCommunicationFailed";
  48. (*remote_failed)[TYPE] = ctkEventTypeLocal;
  49. (*remote_failed)[SIGTYPE] = mafSignatureTypeSignal;
  50. var.setValue((QObject*)this);
  51. (*remote_failed)[OBJECT] = var;
  52. (*remote_failed)[SIGNATURE] = "remoteCommunicationFailed()";*/
  53. this->registerSignal(*remote_failed);
  54. }
  55. bool ctkEventDispatcher::isSignaturePresent(ctkBusEvent &props) const {
  56. QString topic = props[TOPIC].toString();
  57. ctkEventItemListType itemEventPropList;
  58. ctkBusEvent *itemEventProp;
  59. if(props[SIGTYPE].toInt() == ctkSignatureTypeCallback) {
  60. itemEventPropList = m_CallbacksHash.values(topic);
  61. } else {
  62. itemEventPropList = m_SignalsHash.values(topic);
  63. }
  64. QObject *objParameter = props[OBJECT].value<QObject *>();
  65. foreach(itemEventProp, itemEventPropList) {
  66. QObject *objInList = (*itemEventProp)[OBJECT].value<QObject *>();
  67. if(objInList == objParameter && (*itemEventProp)[SIGNATURE].toString() == props[SIGNATURE].toString()) {
  68. return true;
  69. }
  70. }
  71. return false;
  72. }
  73. bool ctkEventDispatcher::disconnectSignal(ctkBusEvent &props) {
  74. QObject *obj_signal = props[OBJECT].value<QObject*>();
  75. QString sig = props[SIGNATURE].toString();
  76. QString event_sig = SIGNAL_SIGNATURE;
  77. event_sig.append(sig);
  78. bool result = obj_signal->disconnect(obj_signal, event_sig.toAscii(), 0, 0);
  79. return result;
  80. }
  81. bool ctkEventDispatcher::disconnectCallback(ctkBusEvent &props) {
  82. //need to disconnect observer from the signal
  83. QString observer_sig = CALLBACK_SIGNATURE;
  84. observer_sig.append(props[SIGNATURE].toString());
  85. ctkBusEvent *itemSignal = m_SignalsHash.value(props[TOPIC].toString());
  86. QString event_sig = SIGNAL_SIGNATURE;
  87. event_sig.append((*itemSignal)[SIGNATURE].toString());
  88. QObject *objSignal = (*itemSignal)[OBJECT].value<QObject *>();
  89. QObject *objSlot = props[OBJECT].value<QObject *>();
  90. return disconnect(objSignal, event_sig.toAscii(), objSlot, observer_sig.toAscii());
  91. }
  92. bool ctkEventDispatcher::removeEventItem(ctkBusEvent &props) {
  93. bool isDisconnected = false;
  94. bool isPresent = isSignaturePresent(props);
  95. if(isPresent == true) {
  96. //ctkEventItemListType itemEventPropList;
  97. if(props[SIGTYPE].toInt() == ctkSignatureTypeCallback) {
  98. isDisconnected = disconnectCallback(props);
  99. //iterator for erasing hash entry
  100. ctkEventsHashType::iterator i = m_CallbacksHash.find(props[TOPIC].toString());
  101. while (i != m_CallbacksHash.end() && i.key() == props[TOPIC]) {
  102. QObject *obj = (*(i.value()))[OBJECT].value<QObject *>();
  103. QObject *objCheck = props[OBJECT].value<QObject *>();
  104. if (obj == objCheck && (*(i.value()))[SIGNATURE].toString() == props[SIGNATURE].toString()) {
  105. delete i.value();
  106. i = m_CallbacksHash.erase(i);
  107. } else {
  108. ++i;
  109. }
  110. }
  111. } else {
  112. //itemEventPropList = m_SignalsHash.values();
  113. isDisconnected = disconnectSignal(props);
  114. ctkEventsHashType::iterator i = m_CallbacksHash.find(props[TOPIC].toString());
  115. while (i != m_CallbacksHash.end() && i.key() == props[TOPIC].toString()) {
  116. delete i.value();
  117. i++;
  118. }
  119. i = m_SignalsHash.find(props[TOPIC].toString());
  120. while (i != m_SignalsHash.end() && i.key() == props[TOPIC].toString()) {
  121. delete i.value();
  122. i++;
  123. }
  124. m_SignalsHash.remove(props[TOPIC].toString()); //in signal hash the id is unique
  125. m_CallbacksHash.remove(props[TOPIC].toString()); //remove also all the id associated in callback
  126. }
  127. //itemEventPropList.removeAt(idx);
  128. }
  129. return isDisconnected;
  130. }
  131. bool ctkEventDispatcher::addObserver(ctkBusEvent &props) {
  132. QString topic = props[TOPIC].toString();
  133. // check if the object has been already registered with the same signature to avoid duplicates.
  134. if(m_CallbacksHash.contains(topic) && this->isSignaturePresent(props) == true) {
  135. return false;
  136. }
  137. QVariant sigVariant = props[SIGNATURE];
  138. QString sig = sigVariant.toString();
  139. QObject *objSlot = props[OBJECT].value<QObject *>();
  140. if(sig.length() > 0 && objSlot != NULL) {
  141. ctkBusEvent *itemEventProp;
  142. //bool testRes = this->isLocalSignalPresent(topic);
  143. itemEventProp = m_SignalsHash.value(topic);
  144. if(itemEventProp == NULL) {
  145. qDebug() << tr("Signal not present for topic %1, create only the entry in CallbacksHash").arg(topic);
  146. ctkBusEvent *dict = const_cast<ctkBusEvent *>(&props);
  147. this->m_CallbacksHash.insertMulti(topic, dict);
  148. return true;
  149. }
  150. QString observer_sig = CALLBACK_SIGNATURE;
  151. observer_sig.append(props[SIGNATURE].toString());
  152. QString event_sig = SIGNAL_SIGNATURE;
  153. event_sig.append((*itemEventProp)[SIGNATURE].toString());
  154. // Add the new observer to the Hash.
  155. ctkBusEvent *dict = const_cast<ctkBusEvent *>(&props);
  156. this->m_CallbacksHash.insertMulti(topic, dict);
  157. QObject *objSignal = (*itemEventProp)[OBJECT].value<QObject *>();
  158. return connect(objSignal, event_sig.toAscii(), objSlot, observer_sig.toAscii());
  159. }
  160. qDebug() << tr("Signal not valid for topic: %1").arg(topic);
  161. QString objValid = objSlot ? "YES":"NO";
  162. qDebug() << tr("Object valid Address: %1").arg(objValid);
  163. qDebug() << tr("Signature: %1").arg(sig);
  164. return false;
  165. }
  166. bool ctkEventDispatcher::removeObserver(const QObject *obj, const QString topic, bool qt_disconnect) {
  167. if(obj == NULL) {
  168. return false;
  169. }
  170. return removeFromHash(&m_CallbacksHash, obj, topic, qt_disconnect);
  171. }
  172. bool ctkEventDispatcher::removeSignal(const QObject *obj, const QString topic, bool qt_disconnect) {
  173. if(obj == NULL) {
  174. return false;
  175. }
  176. return removeFromHash(&m_SignalsHash, obj, topic, qt_disconnect);
  177. }
  178. bool ctkEventDispatcher::removeFromHash(ctkEventsHashType *hash, const QObject *obj, const QString topic, bool qt_disconnect) {
  179. bool disconnectItem = true;
  180. if(topic.length() > 0 && hash->contains(topic)) {
  181. // Remove the observer from the given topic.
  182. ctkEventsHashType::iterator i = hash->find(topic);
  183. while(i != hash->end() && i.key() == topic) {
  184. QObject *item = (*(i.value()))[OBJECT].value<QObject *>();
  185. if(item == obj) {
  186. ctkBusEvent *prop = i.value();
  187. bool currentDisconnetFlag = false;
  188. if(qt_disconnect) {
  189. if(*hash == m_CallbacksHash) {
  190. currentDisconnetFlag = disconnectCallback(*prop);
  191. } else {
  192. currentDisconnetFlag = disconnectSignal(*prop);
  193. }
  194. } else {
  195. currentDisconnetFlag = true;
  196. }
  197. disconnectItem = disconnectItem && currentDisconnetFlag;
  198. if(currentDisconnetFlag) {
  199. delete i.value();
  200. i = hash->erase(i);
  201. } else {
  202. qDebug() << tr("Unable to disconnect object %1 on topic %2").arg(obj->objectName(), topic);
  203. ++i;
  204. }
  205. } else {
  206. ++i;
  207. }
  208. }
  209. return disconnectItem;
  210. }
  211. if(topic.isEmpty()) {
  212. ctkEventsHashType::iterator i = hash->begin();
  213. while(i != hash->end()) {
  214. QObject *item = (*(i.value()))[OBJECT].value<QObject *>();
  215. if(item == obj) {
  216. ctkBusEvent *prop = i.value();
  217. bool currentDisconnetFlag = false;
  218. if(qt_disconnect) {
  219. if(*hash == m_CallbacksHash) {
  220. currentDisconnetFlag = disconnectCallback(*prop);
  221. } else {
  222. currentDisconnetFlag = disconnectSignal(*prop);
  223. }
  224. } else {
  225. currentDisconnetFlag = true;
  226. }
  227. disconnectItem = disconnectItem && currentDisconnetFlag;
  228. if(currentDisconnetFlag) {
  229. delete i.value();
  230. i = hash->erase(i);
  231. } else {
  232. qDebug() << tr("Unable to disconnect object %1 from topic %2").arg(obj->objectName(), (*prop)[TOPIC].toString());
  233. ++i;
  234. }
  235. } else {
  236. ++i;
  237. }
  238. }
  239. return disconnectItem;
  240. }
  241. return false; //need to enter in one of the conditions
  242. }
  243. bool ctkEventDispatcher::removeObserver(ctkBusEvent &props) {
  244. return removeEventItem(props);
  245. }
  246. bool ctkEventDispatcher::registerSignal(ctkBusEvent &props) {
  247. // check if the object has been already registered with the same signature to avoid duplicates.
  248. if(props["Signature"].toString().length() == 0) {
  249. QVariant var;
  250. var.setValue((QObject *)this);
  251. props[OBJECT] = var;
  252. props[SIGNATURE] = "notifyDefaultEvent()";
  253. }
  254. QString topic = props[TOPIC].toString();
  255. // Check if a signal (corresponding to a mafID) already is present.
  256. if(m_SignalsHash.contains(topic)) {// && (this->isSignaturePresent(signal_props) == true)) {
  257. // Only one signal for a given id can be registered!!
  258. QObject *obj = props[OBJECT].value<QObject *>();
  259. if(obj != NULL) {
  260. qWarning("%s", tr("Object %1 is trying to register a signal with Topic '%2' that has been already registered!!").arg(obj->metaObject()->className(), topic).toAscii().data());
  261. } else {
  262. qWarning("%s", tr("NULL is trying to register a signal with Topic '%2' that has been already registered!!").arg(topic).toAscii().data());
  263. }
  264. return false;
  265. }
  266. ctkEventItemListType itemEventPropList;
  267. itemEventPropList = m_CallbacksHash.values(topic);
  268. if(itemEventPropList.count() == 0) {
  269. qDebug() << tr("Callbacks not present for topic %1, create only the entry in SignalsHash").arg(topic);
  270. // Add the new signal to the Hash.
  271. ctkBusEvent *dict = const_cast<ctkBusEvent *>(&props);
  272. this->m_SignalsHash.insert(topic, dict);
  273. return true;
  274. }
  275. QObject *objSignal = props[OBJECT].value<QObject *>();
  276. QVariant sigVariant = props[SIGNATURE];
  277. QString sig = sigVariant.toString();
  278. ctkBusEvent *currentEvent;
  279. bool cumulativeConnect = true;
  280. if(sig.length() > 0 && objSignal != NULL) {
  281. foreach(currentEvent, itemEventPropList) {
  282. QString observer_sig = CALLBACK_SIGNATURE;
  283. observer_sig.append((*currentEvent)[SIGNATURE].toString());
  284. QString event_sig = SIGNAL_SIGNATURE;
  285. event_sig.append(sig);
  286. QObject *objSlot = (*currentEvent)[OBJECT].value<QObject *>();
  287. cumulativeConnect = cumulativeConnect && connect(objSignal, event_sig.toAscii(), objSlot, observer_sig.toAscii());
  288. }
  289. ctkBusEvent *dict = const_cast<ctkBusEvent *>(&props);
  290. this->m_SignalsHash.insert(topic, dict);
  291. }
  292. return cumulativeConnect;
  293. }
  294. bool ctkEventDispatcher::removeSignal(ctkBusEvent &props) {
  295. return removeEventItem(props);
  296. }
  297. void ctkEventDispatcher::notifyEvent(ctkBusEvent &event_dictionary, ctkEventArgumentsList *argList, ctkGenericReturnArgument *returnArg) const {
  298. Q_UNUSED(event_dictionary);
  299. Q_UNUSED(argList);
  300. Q_UNUSED(returnArg);
  301. }