ctkPluginAbstractTracked.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkPluginAbstractTracked_p.h"
  16. #include <QDebug>
  17. template<class Item, class Related>
  18. const bool ctkPluginAbstractTracked<Item,Related>::DEBUG = true;
  19. template<class Item, class Related>
  20. ctkPluginAbstractTracked<Item,Related>::ctkPluginAbstractTracked()
  21. {
  22. closed = false;
  23. }
  24. template<class Item, class Related>
  25. ctkPluginAbstractTracked<Item,Related>::~ctkPluginAbstractTracked()
  26. {
  27. }
  28. template<class Item, class Related>
  29. bool ctkPluginAbstractTracked<Item,Related>::wait(unsigned long timeout)
  30. {
  31. return waitCond.wait(this, timeout);
  32. }
  33. template<class Item, class Related>
  34. void ctkPluginAbstractTracked<Item,Related>::wakeAll()
  35. {
  36. waitCond.wakeAll();
  37. }
  38. template<class Item, class Related>
  39. void ctkPluginAbstractTracked<Item,Related>::setInitial(const QList<Item>& list)
  40. {
  41. foreach (Item item, list)
  42. {
  43. if (DEBUG)
  44. {
  45. qDebug() << "ctkPluginAbstractTracked::setInitial:" << item;
  46. }
  47. initial.push_back(item);
  48. }
  49. }
  50. template<class Item, class Related>
  51. void ctkPluginAbstractTracked<Item,Related>::setInitial(const QList<Item*>& list)
  52. {
  53. foreach (Item* item, list)
  54. {
  55. if (item == 0)
  56. {
  57. continue;
  58. }
  59. if (DEBUG)
  60. {
  61. qDebug() << "ctkPluginAbstractTracked::setInitial:" << item;
  62. }
  63. initial.push_back(item);
  64. }
  65. }
  66. template<class Item, class Related>
  67. void ctkPluginAbstractTracked<Item,Related>::trackInitial()
  68. {
  69. while (true)
  70. {
  71. Item item(0);
  72. {
  73. QMutexLocker lock(this);
  74. if (closed || (initial.size() == 0))
  75. {
  76. /*
  77. * if there are no more initial items
  78. */
  79. return; /* we are done */
  80. }
  81. /*
  82. * move the first item from the initial list to the adding list
  83. * within this synchronized block.
  84. */
  85. item = initial.takeFirst();
  86. if (tracked.value(item) != 0)
  87. {
  88. /* if we are already tracking this item */
  89. if (DEBUG)
  90. {
  91. qDebug() << "ctkPluginAbstractTracked::trackInitial[already tracked]: " << item;
  92. }
  93. continue; /* skip this item */
  94. }
  95. if (adding.contains(item))
  96. {
  97. /*
  98. * if this item is already in the process of being added.
  99. */
  100. if (DEBUG)
  101. {
  102. qDebug() << "ctkPluginAbstractTracked::trackInitial[already adding]: " << item;
  103. }
  104. continue; /* skip this item */
  105. }
  106. adding.push_back(item);
  107. }
  108. if (DEBUG)
  109. {
  110. qDebug() << "ctkPluginAbstractTracked::trackInitial: " << item;
  111. }
  112. trackAdding(item, Related());
  113. /*
  114. * Begin tracking it. We call trackAdding
  115. * since we have already put the item in the
  116. * adding list.
  117. */
  118. }
  119. }
  120. template<class Item, class Related>
  121. void ctkPluginAbstractTracked<Item,Related>::close()
  122. {
  123. closed = true;
  124. }
  125. template<class Item, class Related>
  126. void ctkPluginAbstractTracked<Item,Related>::track(Item item, Related related)
  127. {
  128. QObject* object = 0;
  129. {
  130. QMutexLocker lock(this);
  131. if (closed)
  132. {
  133. return;
  134. }
  135. object = tracked.value(item);
  136. if (object == 0)
  137. { /* we are not tracking the item */
  138. if (adding.contains(item))
  139. {
  140. /* if this item is already in the process of being added. */
  141. if (DEBUG)
  142. {
  143. qDebug() << "ctkPluginAbstractTracked::track[already adding]: " << item;
  144. }
  145. return;
  146. }
  147. adding.push_back(item); /* mark this item is being added */
  148. }
  149. else
  150. { /* we are currently tracking this item */
  151. if (DEBUG)
  152. {
  153. qDebug() << "ctkPluginAbstractTracked::track[modified]: " << item;
  154. }
  155. modified(); /* increment modification count */
  156. }
  157. }
  158. if (object == 0)
  159. { /* we are not tracking the item */
  160. trackAdding(item, related);
  161. }
  162. else
  163. {
  164. /* Call customizer outside of synchronized region */
  165. customizerModified(item, related, object);
  166. /*
  167. * If the customizer throws an unchecked exception, it is safe to
  168. * let it propagate
  169. */
  170. }
  171. }
  172. template<class Item, class Related>
  173. void ctkPluginAbstractTracked<Item,Related>::untrack(Item item, Related related)
  174. {
  175. QObject* object = 0;
  176. {
  177. QMutexLocker lock(this);
  178. if (initial.removeOne(item))
  179. { /* if this item is already in the list
  180. * of initial references to process
  181. */
  182. if (DEBUG)
  183. {
  184. qDebug() << "ctkPluginAbstractTracked::untrack[removed from initial]: " << item;
  185. }
  186. return; /* we have removed it from the list and it will not be
  187. * processed
  188. */
  189. }
  190. if (adding.removeOne(item))
  191. { /* if the item is in the process of
  192. * being added
  193. */
  194. if (DEBUG)
  195. {
  196. qDebug() << "ctkPluginAbstractTracked::untrack[being added]: " << item;
  197. }
  198. return; /*
  199. * in case the item is untracked while in the process of
  200. * adding
  201. */
  202. }
  203. object = tracked.take(item); /*
  204. * must remove from tracker before
  205. * calling customizer callback
  206. */
  207. if (object == 0)
  208. { /* are we actually tracking the item */
  209. return;
  210. }
  211. modified(); /* increment modification count */
  212. }
  213. if (DEBUG)
  214. {
  215. qDebug() << "ctkPluginAbstractTracked::untrack[removed]: " << item;
  216. }
  217. /* Call customizer outside of synchronized region */
  218. customizerRemoved(item, related, object);
  219. /*
  220. * If the customizer throws an unchecked exception, it is safe to let it
  221. * propagate
  222. */
  223. }
  224. template<class Item, class Related>
  225. int ctkPluginAbstractTracked<Item,Related>::size() const
  226. {
  227. return tracked.size();
  228. }
  229. template<class Item, class Related>
  230. QObject* ctkPluginAbstractTracked<Item,Related>::getCustomizedObject(Item item) const
  231. {
  232. return tracked.value(item);
  233. }
  234. template<class Item, class Related>
  235. QList<Item> ctkPluginAbstractTracked<Item,Related>::getTracked() const
  236. {
  237. return tracked.keys();
  238. }
  239. template<class Item, class Related>
  240. void ctkPluginAbstractTracked<Item,Related>::modified()
  241. {
  242. trackingCount.ref();
  243. }
  244. template<class Item, class Related>
  245. int ctkPluginAbstractTracked<Item,Related>::getTrackingCount() const
  246. {
  247. return trackingCount;
  248. }
  249. template<class Item, class Related>
  250. bool ctkPluginAbstractTracked<Item,Related>::customizerAddingFinal(Item item, QObject* custom)
  251. {
  252. QMutexLocker lock(this);
  253. if (adding.removeOne(item) && !closed)
  254. {
  255. /*
  256. * if the item was not untracked during the customizer
  257. * callback
  258. */
  259. if (custom != 0)
  260. {
  261. tracked.insert(item, custom);
  262. modified(); /* increment modification count */
  263. waitCond.wakeAll(); /* notify any waiters */
  264. }
  265. return false;
  266. }
  267. else
  268. {
  269. return true;
  270. }
  271. }
  272. template<class Item, class Related>
  273. void ctkPluginAbstractTracked<Item,Related>::trackAdding(Item item, Related related)
  274. {
  275. if (DEBUG)
  276. {
  277. qDebug() << "ctkPluginAbstractTracked::trackAdding:" << item;
  278. }
  279. QObject* object = 0;
  280. bool becameUntracked = false;
  281. /* Call customizer outside of synchronized region */
  282. try
  283. {
  284. object = customizerAdding(item, related);
  285. becameUntracked = this->customizerAddingFinal(item, object);
  286. }
  287. catch (...)
  288. {
  289. /*
  290. * If the customizer throws an exception, it will
  291. * propagate after the cleanup code.
  292. */
  293. this->customizerAddingFinal(item, object);
  294. throw;
  295. }
  296. /*
  297. * The item became untracked during the customizer callback.
  298. */
  299. if (becameUntracked && (object != 0))
  300. {
  301. if (DEBUG)
  302. {
  303. qDebug() << "ctkPluginAbstractTracked::trackAdding[removed]: " << item;
  304. }
  305. /* Call customizer outside of synchronized region */
  306. customizerRemoved(item, related, object);
  307. /*
  308. * If the customizer throws an unchecked exception, it is safe to
  309. * let it propagate
  310. */
  311. }
  312. }