ctkVTKObjectEventsObserver.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QStringList>
  16. #include <QVariant>
  17. #include <QList>
  18. #include <QHash>
  19. #include <QDebug>
  20. // CTK includes
  21. #include "ctkVTKObjectEventsObserver.h"
  22. #include "ctkVTKConnection.h"
  23. // VTK includes
  24. #include <vtkObject.h>
  25. //-----------------------------------------------------------------------------
  26. CTK_SINGLETON_DEFINE(ctkVTKConnectionFactory)
  27. //-----------------------------------------------------------------------------
  28. // ctkVTKConnectionFactory
  29. //-----------------------------------------------------------------------------
  30. ctkVTKConnectionFactory* ctkVTKConnectionFactory::instance()
  31. {
  32. return Self::Instance;
  33. }
  34. //-----------------------------------------------------------------------------
  35. void ctkVTKConnectionFactory::setInstance(ctkVTKConnectionFactory* newInstance)
  36. {
  37. if (!newInstance)
  38. {
  39. qCritical() << "ctkVTKConnectionFactory::setInstance - Failed to set a null instance !";
  40. return;
  41. }
  42. delete Self::Instance;
  43. Self::Instance = newInstance;
  44. }
  45. //-----------------------------------------------------------------------------
  46. ctkVTKConnectionFactory::ctkVTKConnectionFactory()
  47. {
  48. }
  49. //-----------------------------------------------------------------------------
  50. ctkVTKConnectionFactory::~ctkVTKConnectionFactory()
  51. {
  52. }
  53. //-----------------------------------------------------------------------------
  54. ctkVTKConnection* ctkVTKConnectionFactory::createConnection(ctkVTKObjectEventsObserver* parent)const
  55. {
  56. return new ctkVTKConnection(parent);
  57. }
  58. //-----------------------------------------------------------------------------
  59. // ctkVTKObjectEventsObserverPrivate
  60. //-----------------------------------------------------------------------------
  61. class ctkVTKObjectEventsObserverPrivate
  62. {
  63. Q_DECLARE_PUBLIC(ctkVTKObjectEventsObserver);
  64. protected:
  65. ctkVTKObjectEventsObserver* const q_ptr;
  66. public:
  67. typedef std::multimap<unsigned long, ctkVTKConnection*> ConnectionIndexType; // first: originating vtkObject, second: QT connection object name
  68. ctkVTKObjectEventsObserverPrivate(ctkVTKObjectEventsObserver& object);
  69. ///
  70. /// Return a reference toward the corresponding connection or 0 if doesn't exist
  71. ctkVTKConnection* findConnection(const QString& id)const;
  72. ///
  73. /// Return a reference toward the corresponding connection or 0 if doesn't exist
  74. ctkVTKConnection* findConnection(vtkObject* vtk_obj, unsigned long vtk_event,
  75. const QObject* qt_obj, const char* qt_slot)const;
  76. ///
  77. /// Return all the references that match the given parameters
  78. QList<ctkVTKConnection*> findConnections(vtkObject* vtk_obj, unsigned long vtk_event,
  79. const QObject* qt_obj, const char* qt_slot)const;
  80. inline QList<ctkVTKConnection*> connections()const
  81. {
  82. Q_Q(const ctkVTKObjectEventsObserver);
  83. return q->findChildren<ctkVTKConnection*>();
  84. }
  85. static unsigned long generateConnectionIndexHash(vtkObject* vtk_obj, unsigned long vtk_event,
  86. const QObject* qt_obj, const char* qt_slot)
  87. {
  88. return (unsigned char*)vtk_obj-(unsigned char*)qt_obj+vtk_event;
  89. }
  90. bool StrictTypeCheck;
  91. bool AllBlocked;
  92. bool ObserveDeletion;
  93. mutable ConnectionIndexType ConnectionIndex;
  94. };
  95. //-----------------------------------------------------------------------------
  96. // ctkVTKObjectEventsObserverPrivate methods
  97. //-----------------------------------------------------------------------------
  98. ctkVTKObjectEventsObserverPrivate::ctkVTKObjectEventsObserverPrivate(ctkVTKObjectEventsObserver& object)
  99. :q_ptr(&object)
  100. {
  101. this->StrictTypeCheck = false;
  102. this->AllBlocked = false;
  103. // ObserveDeletion == false hasn't been that well tested...
  104. this->ObserveDeletion = true;
  105. }
  106. //-----------------------------------------------------------------------------
  107. ctkVTKConnection*
  108. ctkVTKObjectEventsObserverPrivate::findConnection(const QString& id)const
  109. {
  110. foreach(ctkVTKConnection* connection, this->connections())
  111. {
  112. if (connection->id() == id)
  113. {
  114. return connection;
  115. }
  116. }
  117. return 0;
  118. }
  119. //-----------------------------------------------------------------------------
  120. ctkVTKConnection*
  121. ctkVTKObjectEventsObserverPrivate::findConnection(
  122. vtkObject* vtk_obj, unsigned long vtk_event,
  123. const QObject* qt_obj, const char* qt_slot)const
  124. {
  125. // Linear search for connections is prohibitively slow when observing many objects
  126. Q_Q(const ctkVTKObjectEventsObserver);
  127. std::pair<ConnectionIndexType::iterator, ConnectionIndexType::iterator> rangeConnectionsForObject;
  128. rangeConnectionsForObject = this->ConnectionIndex.equal_range(generateConnectionIndexHash(vtk_obj, vtk_event, qt_obj, qt_slot));
  129. for (ConnectionIndexType::iterator connectionForObjectIt = rangeConnectionsForObject.first;
  130. connectionForObjectIt != rangeConnectionsForObject.second;
  131. /*upon deletion the increment is done already, so don't increment here*/)
  132. {
  133. ctkVTKConnection* connection=connectionForObjectIt->second;
  134. if (!q->children().contains(connection))
  135. {
  136. // connection has been deleted, so remove it from the index
  137. connectionForObjectIt=this->ConnectionIndex.erase(connectionForObjectIt);
  138. continue;
  139. }
  140. if (connection->isEqual(vtk_obj, vtk_event, qt_obj, qt_slot))
  141. {
  142. return connection;
  143. }
  144. ++connectionForObjectIt;
  145. }
  146. /*
  147. foreach (ctkVTKConnection* connection, this->connections())
  148. {
  149. if (connection->isEqual(vtk_obj, vtk_event, qt_obj, qt_slot))
  150. {
  151. return connection;
  152. }
  153. }
  154. */
  155. return 0;
  156. }
  157. //-----------------------------------------------------------------------------
  158. QList<ctkVTKConnection*>
  159. ctkVTKObjectEventsObserverPrivate::findConnections(
  160. vtkObject* vtk_obj, unsigned long vtk_event,
  161. const QObject* qt_obj, const char* qt_slot)const
  162. {
  163. Q_Q(const ctkVTKObjectEventsObserver);
  164. bool all_info = true;
  165. if(vtk_obj == NULL || qt_slot == NULL ||
  166. qt_obj == NULL || vtk_event == vtkCommand::NoEvent)
  167. {
  168. all_info = false;
  169. }
  170. QList<ctkVTKConnection*> foundConnections;
  171. std::pair<ConnectionIndexType::iterator, ConnectionIndexType::iterator> rangeConnectionsForObject;
  172. rangeConnectionsForObject = this->ConnectionIndex.equal_range(generateConnectionIndexHash(vtk_obj, vtk_event, qt_obj, qt_slot));
  173. for (ConnectionIndexType::iterator connectionForObjectIt = rangeConnectionsForObject.first;
  174. connectionForObjectIt != rangeConnectionsForObject.second;
  175. /*upon deletion the increment is done already, so don't increment here*/
  176. )
  177. {
  178. ctkVTKConnection* connection=connectionForObjectIt->second;
  179. if (!q->children().contains(connection))
  180. {
  181. // connection has been deleted, so remove it from the index
  182. connectionForObjectIt=this->ConnectionIndex.erase(connectionForObjectIt);
  183. continue;
  184. }
  185. if (connection->isEqual(vtk_obj, vtk_event, qt_obj, qt_slot))
  186. {
  187. foundConnections.append(connection);
  188. if (all_info)
  189. {
  190. break;
  191. }
  192. }
  193. ++connectionForObjectIt;
  194. }
  195. /*
  196. // Loop through all connection
  197. foreach (ctkVTKConnection* connection, this->connections())
  198. {
  199. if (connection->isEqual(vtk_obj, vtk_event, qt_obj, qt_slot))
  200. {
  201. foundConnections.append(connection);
  202. if (all_info)
  203. {
  204. break;
  205. }
  206. }
  207. }
  208. */
  209. return foundConnections;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // ctkVTKObjectEventsObserver methods
  213. //-----------------------------------------------------------------------------
  214. ctkVTKObjectEventsObserver::ctkVTKObjectEventsObserver(QObject* _parent):Superclass(_parent)
  215. , d_ptr(new ctkVTKObjectEventsObserverPrivate(*this))
  216. {
  217. this->setProperty("QVTK_OBJECT", true);
  218. }
  219. //-----------------------------------------------------------------------------
  220. ctkVTKObjectEventsObserver::~ctkVTKObjectEventsObserver()
  221. {
  222. }
  223. //-----------------------------------------------------------------------------
  224. void ctkVTKObjectEventsObserver::printAdditionalInfo()
  225. {
  226. this->Superclass::dumpObjectInfo();
  227. Q_D(ctkVTKObjectEventsObserver);
  228. qDebug() << "ctkVTKObjectEventsObserver:" << this << endl
  229. << " AllBlocked:" << d->AllBlocked << endl
  230. << " Parent:" << (this->parent()?this->parent()->objectName():"NULL") << endl
  231. << " Connection count:" << d->connections().count();
  232. // Loop through all connection
  233. foreach (const ctkVTKConnection* connection, d->connections())
  234. {
  235. qDebug() << *connection;
  236. }
  237. }
  238. //-----------------------------------------------------------------------------
  239. bool ctkVTKObjectEventsObserver::strictTypeCheck()const
  240. {
  241. Q_D(const ctkVTKObjectEventsObserver);
  242. return d->StrictTypeCheck;
  243. }
  244. //-----------------------------------------------------------------------------
  245. void ctkVTKObjectEventsObserver::setStrictTypeCheck(bool check)
  246. {
  247. Q_D(ctkVTKObjectEventsObserver);
  248. d->StrictTypeCheck = check;
  249. }
  250. //-----------------------------------------------------------------------------
  251. QString ctkVTKObjectEventsObserver::addConnection(vtkObject* old_vtk_obj, vtkObject* vtk_obj,
  252. unsigned long vtk_event, const QObject* qt_obj, const char* qt_slot, float priority,
  253. Qt::ConnectionType connectionType)
  254. {
  255. Q_D(ctkVTKObjectEventsObserver);
  256. if (old_vtk_obj)
  257. {
  258. // Check that old_object and new_object are the same type
  259. // If you have a crash when accessing old_vtk_obj->GetClassName(), that means
  260. // old_vtk_obj has been deleted and you should probably have keep
  261. // old_vtk_obj into a vtkWeakPointer:
  262. // vtkWeakPointer<vtkObject> obj1 = myobj1;
  263. // this->addConnection(obj1, vtkCommand::Modified...)
  264. // myobj1->Delete();
  265. // vtkWeakPointer<vtkObject> obj2 = myobj2;
  266. // this->addConnection(obj1, obj2, vtkCommand::Modified...)
  267. // ...
  268. // Or just call addConnection with a new
  269. // vtk_obj of 0 before the vtk_obj is deleted.
  270. // vtkObject* obj1 = vtkObject::New();
  271. // this->addConnection(obj1, vtkCommand::Modified...)
  272. // this->addConnection(obj1, 0, vtkCommand::Modified...)
  273. // obj1->Delete();
  274. // vtkObject* obj2 = vtkObject::New();
  275. // this->addConnection(0, obj2, vtkCommand::Modified...)
  276. // ...
  277. if (d->StrictTypeCheck && vtk_obj
  278. && !vtk_obj->IsA(old_vtk_obj->GetClassName()))
  279. {
  280. qWarning() << "Previous vtkObject (type:" << old_vtk_obj->GetClassName()
  281. << ") to disconnect"
  282. << "and new vtkObject (type:" << vtk_obj->GetClassName()
  283. << ") to connect"
  284. << "have a different type.";
  285. return QString();
  286. }
  287. // Disconnect old vtkObject
  288. this->removeConnection(old_vtk_obj, vtk_event, qt_obj, qt_slot);
  289. }
  290. return this->addConnection(
  291. vtk_obj, vtk_event, qt_obj, qt_slot, priority, connectionType);
  292. }
  293. //-----------------------------------------------------------------------------
  294. QString ctkVTKObjectEventsObserver::reconnection(vtkObject* vtk_obj,
  295. unsigned long vtk_event, const QObject* qt_obj,
  296. const char* qt_slot, float priority, Qt::ConnectionType connectionType)
  297. {
  298. this->removeConnection(0, vtk_event, qt_obj, qt_slot);
  299. return this->addConnection(
  300. vtk_obj, vtk_event, qt_obj, qt_slot, priority, connectionType);
  301. }
  302. //-----------------------------------------------------------------------------
  303. QString ctkVTKObjectEventsObserver::addConnection(vtkObject* vtk_obj, unsigned long vtk_event,
  304. const QObject* qt_obj, const char* qt_slot, float priority, Qt::ConnectionType connectionType)
  305. {
  306. Q_D(ctkVTKObjectEventsObserver);
  307. // If no vtk_obj is provided, there is no way we can create a connection.
  308. if (!vtk_obj)
  309. {
  310. return QString();
  311. }
  312. if (!ctkVTKConnection::isValid(vtk_obj, vtk_event, qt_obj, qt_slot))
  313. {
  314. qDebug() << "ctkVTKObjectEventsObserver::addConnection(...) - Invalid parameters - "
  315. << ctkVTKConnection::shortDescription(vtk_obj, vtk_event, qt_obj, qt_slot);
  316. return QString();
  317. }
  318. // Check if such event is already observed
  319. if (this->containsConnection(vtk_obj, vtk_event, qt_obj, qt_slot))
  320. {
  321. // if you need to have more than 1 connection, then it's probably time to
  322. // add the same mechanism than Qt does: Qt::UniqueConnection
  323. //qWarning() << "ctkVTKObjectEventsObserver::addConnection - [vtkObject:"
  324. // << vtk_obj->GetClassName()
  325. // << ", event:" << vtk_event << "]"
  326. // << " is already connected with [qObject:" << qt_obj->objectName()
  327. // << ", slot:" << qt_slot << "]";
  328. return QString();
  329. }
  330. // Instantiate a new connection, set its parameters and add it to the list
  331. ctkVTKConnection * connection = ctkVTKConnectionFactory::instance()->createConnection(this);
  332. QString objName=connection->objectName();
  333. d->ConnectionIndex.insert(ctkVTKObjectEventsObserverPrivate::ConnectionIndexType::value_type(
  334. ctkVTKObjectEventsObserverPrivate::generateConnectionIndexHash(vtk_obj, vtk_event, qt_obj, qt_slot), connection));
  335. connection->observeDeletion(d->ObserveDeletion);
  336. connection->setup(vtk_obj, vtk_event, qt_obj, qt_slot, priority, connectionType);
  337. // If required, establish connection
  338. connection->setBlocked(d->AllBlocked);
  339. return connection->id();
  340. }
  341. //-----------------------------------------------------------------------------
  342. bool ctkVTKObjectEventsObserver::blockAllConnections(bool block)
  343. {
  344. Q_D(ctkVTKObjectEventsObserver);
  345. if (d->AllBlocked == block)
  346. {
  347. return d->AllBlocked;
  348. }
  349. bool oldAllBlocked = d->AllBlocked;
  350. foreach (ctkVTKConnection* connection, d->connections())
  351. {
  352. connection->setBlocked(block);
  353. }
  354. d->AllBlocked = block;
  355. return oldAllBlocked;
  356. }
  357. //-----------------------------------------------------------------------------
  358. bool ctkVTKObjectEventsObserver::connectionsBlocked()const
  359. {
  360. Q_D(const ctkVTKObjectEventsObserver);
  361. return d->AllBlocked;
  362. }
  363. //-----------------------------------------------------------------------------
  364. bool ctkVTKObjectEventsObserver::blockConnection(const QString& id, bool blocked)
  365. {
  366. Q_D(ctkVTKObjectEventsObserver);
  367. ctkVTKConnection* connection = d->findConnection(id);
  368. if (connection == 0)
  369. {
  370. qWarning() << "no connection for id " << id;
  371. return false;
  372. }
  373. bool oldBlocked = connection->isBlocked();
  374. connection->setBlocked(blocked);
  375. return oldBlocked;
  376. }
  377. //-----------------------------------------------------------------------------
  378. int ctkVTKObjectEventsObserver::blockConnection(bool block, vtkObject* vtk_obj,
  379. unsigned long vtk_event, const QObject* qt_obj)
  380. {
  381. Q_D(ctkVTKObjectEventsObserver);
  382. if (!vtk_obj)
  383. {
  384. qDebug() << "ctkVTKObjectEventsObserver::blockConnectionRecursive"
  385. << "- Failed to " << (block?"block":"unblock") <<" connection"
  386. << "- vtkObject is NULL";
  387. return 0;
  388. }
  389. QList<ctkVTKConnection*> connections =
  390. d->findConnections(vtk_obj, vtk_event, qt_obj, 0);
  391. foreach (ctkVTKConnection* connection, connections)
  392. {
  393. connection->setBlocked(block);
  394. }
  395. return connections.size();
  396. }
  397. //-----------------------------------------------------------------------------
  398. int ctkVTKObjectEventsObserver::removeConnection(vtkObject* vtk_obj, unsigned long vtk_event,
  399. const QObject* qt_obj, const char* qt_slot)
  400. {
  401. Q_D(ctkVTKObjectEventsObserver);
  402. QList<ctkVTKConnection*> connections =
  403. d->findConnections(vtk_obj, vtk_event, qt_obj, qt_slot);
  404. foreach (ctkVTKConnection* connection, connections)
  405. {
  406. // no need to update the index, it'll be updated on-the fly when searching for connections
  407. delete connection;
  408. }
  409. return connections.count();
  410. }
  411. //-----------------------------------------------------------------------------
  412. int ctkVTKObjectEventsObserver::removeAllConnections()
  413. {
  414. return this->removeConnection(0, vtkCommand::NoEvent, 0, 0);
  415. }
  416. //-----------------------------------------------------------------------------
  417. bool ctkVTKObjectEventsObserver::containsConnection(vtkObject* vtk_obj, unsigned long vtk_event,
  418. const QObject* qt_obj, const char* qt_slot)const
  419. {
  420. Q_D(const ctkVTKObjectEventsObserver);
  421. return (d->findConnection(vtk_obj, vtk_event, qt_obj, qt_slot) != 0);
  422. }