ctkVTKConnection.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. All rights reserved.
  5. Distributed under a BSD License. See LICENSE.txt file.
  6. This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the above copyright notice for more information.
  9. =========================================================================*/
  10. // Qt includes
  11. #include <QDebug>
  12. #include <QRegExp>
  13. #include <QString>
  14. #include <QTextStream>
  15. // CTK includes
  16. #include "ctkVTKConnection.h"
  17. // VTK includes
  18. #include <vtkObject.h>
  19. #include <vtkSmartPointer.h>
  20. #include <vtkCallbackCommand.h>
  21. //-----------------------------------------------------------------------------
  22. QString convertPointerToString(void* pointer)
  23. {
  24. QString pointerAsString;
  25. QTextStream(&pointerAsString) << pointer;
  26. return pointerAsString;
  27. }
  28. //-----------------------------------------------------------------------------
  29. class ctkVTKConnectionPrivate: public ctkPrivate<ctkVTKConnection>
  30. {
  31. public:
  32. enum
  33. {
  34. ARG_UNKNOWN = 0,
  35. ARG_VTKOBJECT_AND_VTKOBJECT,
  36. ARG_VTKOBJECT_VOID_ULONG_VOID
  37. };
  38. typedef ctkVTKConnectionPrivate Self;
  39. ctkVTKConnectionPrivate();
  40. ~ctkVTKConnectionPrivate();
  41. void connect();
  42. void disconnect();
  43. ///
  44. /// VTK Callback
  45. static void DoCallback(vtkObject* vtk_obj, unsigned long event,
  46. void* client_data, void* call_data);
  47. ///
  48. /// Called by 'DoCallback' to emit signal
  49. void Execute(vtkObject* vtk_obj, unsigned long vtk_event, void* client_data, void* call_data);
  50. vtkSmartPointer<vtkCallbackCommand> Callback;
  51. vtkObject* VTKObject;
  52. const QObject* QtObject;
  53. unsigned long VTKEvent;
  54. QString QtSlot;
  55. float Priority;
  56. int SlotType;
  57. bool Connected;
  58. bool Blocked;
  59. QString Id;
  60. bool AboutToBeDeleted;
  61. };
  62. //-----------------------------------------------------------------------------
  63. // ctkVTKConnectionPrivate methods
  64. //-----------------------------------------------------------------------------
  65. ctkVTKConnectionPrivate::ctkVTKConnectionPrivate()
  66. {
  67. this->Callback = vtkSmartPointer<vtkCallbackCommand>::New();
  68. this->Callback->SetCallback(ctkVTKConnectionPrivate::DoCallback);
  69. this->Callback->SetClientData(this);
  70. this->VTKObject = 0;
  71. this->QtObject = 0;
  72. this->VTKEvent = vtkCommand::NoEvent;
  73. this->Priority = 0.0;
  74. this->SlotType = ARG_UNKNOWN;
  75. this->Connected = false;
  76. this->Blocked = false;
  77. this->Id = convertPointerToString(this);
  78. this->AboutToBeDeleted = false;
  79. }
  80. //-----------------------------------------------------------------------------
  81. ctkVTKConnectionPrivate::~ctkVTKConnectionPrivate()
  82. {
  83. /*
  84. if(this->VTKObject && this->Connected)
  85. {
  86. this->VTKObject->RemoveObserver(this->Callback);
  87. //Qt takes care of disconnecting slots
  88. }
  89. */
  90. }
  91. //-----------------------------------------------------------------------------
  92. void ctkVTKConnectionPrivate::connect()
  93. {
  94. CTK_P(ctkVTKConnection);
  95. if (this->Connected)
  96. {
  97. qDebug() << "ctkVTKConnection already connected.";
  98. return;
  99. }
  100. switch (this->SlotType)
  101. {
  102. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
  103. QObject::connect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
  104. this->QtObject, this->QtSlot.toLatin1().data());
  105. break;
  106. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
  107. QObject::connect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
  108. this->QtObject, this->QtSlot.toLatin1().data());
  109. break;
  110. default:
  111. Q_ASSERT(false);
  112. qCritical() << "Failed to connect - "
  113. << "The slot (" << this->QtSlot << ") owned by "
  114. << "QObject(" << this->QtObject->objectName() << ")"
  115. << " seems to have a wrong signature.";
  116. break;
  117. }
  118. // Make a connection between this and the vtk object
  119. this->VTKObject->AddObserver(this->VTKEvent, this->Callback, this->Priority);
  120. // If necessary, observe vtk DeleteEvent
  121. if(this->VTKEvent != vtkCommand::DeleteEvent)
  122. {
  123. this->VTKObject->AddObserver(vtkCommand::DeleteEvent, this->Callback);
  124. }
  125. // Remove itself from its parent when vtkObject is deleted
  126. QObject::connect(this->QtObject, SIGNAL(destroyed(QObject*)),
  127. p, SLOT(deleteConnection()));
  128. this->Connected = true;
  129. }
  130. //-----------------------------------------------------------------------------
  131. void ctkVTKConnectionPrivate::disconnect()
  132. {
  133. CTK_P(ctkVTKConnection);
  134. if (!this->Connected)
  135. {
  136. Q_ASSERT(this->Connected);
  137. return;
  138. }
  139. this->VTKObject->RemoveObserver(this->Callback);
  140. switch (this->SlotType)
  141. {
  142. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
  143. QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, vtkObject*)),
  144. this->QtObject,this->QtSlot.toLatin1().data());
  145. break;
  146. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
  147. QObject::disconnect(p, SIGNAL(emitExecute(vtkObject*, void*, unsigned long, void*)),
  148. this->QtObject, this->QtSlot.toLatin1().data());
  149. break;
  150. default:
  151. Q_ASSERT(false);
  152. qCritical() << "Failed to disconnect - "
  153. << "The slot (" << this->QtSlot << ") owned by "
  154. << "QObject(" << this->QtObject->objectName() << ")"
  155. << " seems to have a wrong signature.";
  156. break;
  157. }
  158. QObject::disconnect(this->QtObject, SIGNAL(destroyed(QObject*)),
  159. p, SLOT(deleteConnection()));
  160. this->Connected = false;
  161. }
  162. //-----------------------------------------------------------------------------
  163. // ctkVTKConnection methods
  164. //-----------------------------------------------------------------------------
  165. ctkVTKConnection::ctkVTKConnection(QObject* _parent):
  166. Superclass(_parent)
  167. {
  168. CTK_INIT_PRIVATE(ctkVTKConnection);
  169. }
  170. //-----------------------------------------------------------------------------
  171. ctkVTKConnection::~ctkVTKConnection()
  172. {
  173. this->setEnabled(false);
  174. }
  175. //-----------------------------------------------------------------------------
  176. CTK_GET_CXX(ctkVTKConnection, QString, id, Id);
  177. //-----------------------------------------------------------------------------
  178. void ctkVTKConnection::printAdditionalInfo()
  179. {
  180. this->Superclass::dumpObjectInfo();
  181. CTK_D(ctkVTKConnection);
  182. qDebug() << "ctkVTKConnection:" << this << endl
  183. << "Id:" << d->Id << endl
  184. << " VTKObject:" << d->VTKObject->GetClassName()
  185. << "(" << d->VTKObject << ")" << endl
  186. << " QtObject:" << d->QtObject << endl
  187. << " VTKEvent:" << d->VTKEvent << endl
  188. << " QtSlot:" << d->QtSlot << endl
  189. << " SlotType:" << d->SlotType << endl
  190. << " Priority:" << d->Priority << endl
  191. << " Connected:" << d->Connected << endl
  192. << " Blocked:" << d->Blocked;
  193. }
  194. //-----------------------------------------------------------------------------
  195. QString ctkVTKConnection::shortDescription()
  196. {
  197. CTK_D(ctkVTKConnection);
  198. return Self::shortDescription(d->VTKObject, d->VTKEvent, d->QtObject, d->QtSlot);
  199. }
  200. //-----------------------------------------------------------------------------
  201. QString ctkVTKConnection::shortDescription(vtkObject* vtk_obj, unsigned long vtk_event,
  202. const QObject* qt_obj, QString qt_slot)
  203. {
  204. QString ret;
  205. QTextStream ts( &ret );
  206. ts << (vtk_obj ? vtk_obj->GetClassName() : "NULL") << " "
  207. << vtk_event << " " << qt_obj << " " << qt_slot;
  208. return ret;
  209. }
  210. //-----------------------------------------------------------------------------
  211. bool ctkVTKConnection::ValidateParameters(vtkObject* vtk_obj, unsigned long vtk_event,
  212. const QObject* qt_obj, QString qt_slot)
  213. {
  214. Q_UNUSED(vtk_event);
  215. if (!vtk_obj)
  216. {
  217. return false;
  218. }
  219. if (!qt_obj)
  220. {
  221. return false;
  222. }
  223. if (qt_slot.isEmpty())
  224. {
  225. return false;
  226. }
  227. return true;
  228. }
  229. //-----------------------------------------------------------------------------
  230. void ctkVTKConnection::SetParameters(vtkObject* vtk_obj, unsigned long vtk_event,
  231. const QObject* qt_obj, QString qt_slot, float priority)
  232. {
  233. CTK_D(ctkVTKConnection);
  234. if (!Self::ValidateParameters(vtk_obj, vtk_event, qt_obj, qt_slot))
  235. {
  236. return;
  237. }
  238. d->VTKObject = vtk_obj;
  239. d->QtObject = qt_obj;
  240. d->VTKEvent = vtk_event;
  241. d->QtSlot = qt_slot;
  242. d->Priority = priority;
  243. if (qt_slot.contains(QRegExp(QString("\\( ?vtkObject ?\\* ?, ?vtkObject ?\\* ?\\)"))))
  244. {
  245. d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT;
  246. }
  247. else
  248. {
  249. d->SlotType = ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID;
  250. }
  251. }
  252. //-----------------------------------------------------------------------------
  253. void ctkVTKConnection::setEnabled(bool enable)
  254. {
  255. CTK_D(ctkVTKConnection);
  256. if (d->Connected == enable)
  257. {
  258. return;
  259. }
  260. if (enable)
  261. {
  262. d->connect();
  263. }
  264. else
  265. {
  266. d->disconnect();
  267. }
  268. }
  269. //-----------------------------------------------------------------------------
  270. bool ctkVTKConnection::isEnabled()const
  271. {
  272. CTK_D(const ctkVTKConnection);
  273. return d->Connected;
  274. }
  275. //-----------------------------------------------------------------------------
  276. void ctkVTKConnection::setBlocked(bool block)
  277. {
  278. CTK_D(ctkVTKConnection);
  279. d->Blocked = block;
  280. }
  281. //-----------------------------------------------------------------------------
  282. bool ctkVTKConnection::isBlocked()const
  283. {
  284. CTK_D(const ctkVTKConnection);
  285. return d->Blocked;
  286. }
  287. //-----------------------------------------------------------------------------
  288. bool ctkVTKConnection::isEqual(vtkObject* vtk_obj, unsigned long vtk_event,
  289. const QObject* qt_obj, QString qt_slot)const
  290. {
  291. CTK_D(const ctkVTKConnection);
  292. if (d->VTKObject != vtk_obj)
  293. {
  294. return false;
  295. }
  296. if (vtk_event != vtkCommand::NoEvent && d->VTKEvent != vtk_event)
  297. {
  298. return false;
  299. }
  300. if (qt_obj && d->QtObject != qt_obj)
  301. {
  302. return false;
  303. }
  304. if (!qt_slot.isEmpty() &&
  305. (QString(d->QtSlot).remove(' ').compare(
  306. QString(qt_slot).remove(' ')) != 0))
  307. {
  308. return false;
  309. }
  310. return true;
  311. }
  312. //-----------------------------------------------------------------------------
  313. void ctkVTKConnectionPrivate::DoCallback(vtkObject* vtk_obj, unsigned long event,
  314. void* client_data, void* call_data)
  315. {
  316. ctkVTKConnectionPrivate* conn = static_cast<ctkVTKConnectionPrivate*>(client_data);
  317. Q_ASSERT(conn);
  318. conn->Execute(vtk_obj, event, client_data, call_data);
  319. }
  320. //-----------------------------------------------------------------------------
  321. // callback from VTK to emit signal
  322. void ctkVTKConnectionPrivate::Execute(vtkObject* vtk_obj, unsigned long vtk_event,
  323. void* client_data, void* call_data)
  324. {
  325. CTK_P(ctkVTKConnection);
  326. Q_ASSERT(this->Connected);
  327. if (this->Blocked)
  328. {
  329. return;
  330. }
  331. if (vtk_event == vtkCommand::DeleteEvent)
  332. {
  333. this->AboutToBeDeleted = true;
  334. }
  335. if(vtk_event != vtkCommand::DeleteEvent ||
  336. (vtk_event == vtkCommand::DeleteEvent && this->VTKEvent == vtkCommand::DeleteEvent))
  337. {
  338. vtkObject* callDataAsVtkObject = 0;
  339. switch (this->SlotType)
  340. {
  341. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_AND_VTKOBJECT:
  342. if (this->VTKEvent == vtk_event)
  343. {
  344. callDataAsVtkObject = reinterpret_cast<vtkObject*>( call_data );
  345. if (!callDataAsVtkObject)
  346. {
  347. qCritical() << "The VTKEvent(" << this->VTKEvent<< ") triggered by vtkObject("
  348. << this->VTKObject->GetClassName() << ") "
  349. << "doesn't return data of type vtkObject." << endl
  350. << "The slot (" << this->QtSlot << ") owned by "
  351. << "QObject(" << this->QtObject->objectName() << ")"
  352. << " may be incorrect.";
  353. }
  354. emit p->emitExecute(vtk_obj, callDataAsVtkObject);
  355. }
  356. break;
  357. case ctkVTKConnectionPrivate::ARG_VTKOBJECT_VOID_ULONG_VOID:
  358. emit p->emitExecute(vtk_obj, call_data, vtk_event, client_data);
  359. break;
  360. default:
  361. // Should never reach
  362. qCritical() << "Unknown SlotType:" << this->SlotType;
  363. return;
  364. break;
  365. }
  366. }
  367. if(vtk_event == vtkCommand::DeleteEvent)
  368. {
  369. this->AboutToBeDeleted = false;
  370. p->deleteConnection();
  371. }
  372. }
  373. void ctkVTKConnection::deleteConnection()
  374. {
  375. CTK_D(ctkVTKConnection);
  376. if (d->AboutToBeDeleted)
  377. {
  378. return;
  379. }
  380. delete this;
  381. }