ctkPluginAbstractTracked.tpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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 S, class T, class R>
  18. const bool ctkPluginAbstractTracked<S,T,R>::DEBUG = true;
  19. template<class S, class T, class R>
  20. ctkPluginAbstractTracked<S,T,R>::ctkPluginAbstractTracked()
  21. {
  22. closed = false;
  23. }
  24. template<class S, class T, class R>
  25. ctkPluginAbstractTracked<S,T,R>::~ctkPluginAbstractTracked()
  26. {
  27. }
  28. template<class S, class T, class R>
  29. bool ctkPluginAbstractTracked<S,T,R>::wait(unsigned long timeout)
  30. {
  31. return waitCond.wait(this, timeout);
  32. }
  33. template<class S, class T, class R>
  34. void ctkPluginAbstractTracked<S,T,R>::wakeAll()
  35. {
  36. waitCond.wakeAll();
  37. }
  38. template<class S, class T, class R>
  39. void ctkPluginAbstractTracked<S,T,R>::setInitial(const QList<S>& list)
  40. {
  41. foreach (S item, list)
  42. {
  43. if (DEBUG)
  44. {
  45. qDebug() << "ctkPluginAbstractTracked::setInitial:" << item;
  46. }
  47. initial.push_back(item);
  48. }
  49. }
  50. template<class S, class T, class R>
  51. void ctkPluginAbstractTracked<S,T,R>::trackInitial()
  52. {
  53. while (true)
  54. {
  55. S item(0);
  56. {
  57. QMutexLocker lock(this);
  58. if (closed || (initial.size() == 0))
  59. {
  60. /*
  61. * if there are no more initial items
  62. */
  63. return; /* we are done */
  64. }
  65. /*
  66. * move the first item from the initial list to the adding list
  67. * within this synchronized block.
  68. */
  69. item = initial.takeFirst();
  70. if (tracked.value(item))
  71. {
  72. /* if we are already tracking this item */
  73. if (DEBUG)
  74. {
  75. qDebug() << "ctkPluginAbstractTracked::trackInitial[already tracked]: " << item;
  76. }
  77. continue; /* skip this item */
  78. }
  79. if (adding.contains(item))
  80. {
  81. /*
  82. * if this item is already in the process of being added.
  83. */
  84. if (DEBUG)
  85. {
  86. qDebug() << "ctkPluginAbstractTracked::trackInitial[already adding]: " << item;
  87. }
  88. continue; /* skip this item */
  89. }
  90. adding.push_back(item);
  91. }
  92. if (DEBUG)
  93. {
  94. qDebug() << "ctkPluginAbstractTracked::trackInitial: " << item;
  95. }
  96. trackAdding(item, R());
  97. /*
  98. * Begin tracking it. We call trackAdding
  99. * since we have already put the item in the
  100. * adding list.
  101. */
  102. }
  103. }
  104. template<class S, class T, class R>
  105. void ctkPluginAbstractTracked<S,T,R>::close()
  106. {
  107. closed = true;
  108. }
  109. template<class S, class T, class R>
  110. void ctkPluginAbstractTracked<S,T,R>::track(S item, R related)
  111. {
  112. T object(0);
  113. {
  114. QMutexLocker lock(this);
  115. if (closed)
  116. {
  117. return;
  118. }
  119. object = tracked.value(item);
  120. if (!object)
  121. { /* we are not tracking the item */
  122. if (adding.contains(item))
  123. {
  124. /* if this item is already in the process of being added. */
  125. if (DEBUG)
  126. {
  127. qDebug() << "ctkPluginAbstractTracked::track[already adding]: " << item;
  128. }
  129. return;
  130. }
  131. adding.push_back(item); /* mark this item is being added */
  132. }
  133. else
  134. { /* we are currently tracking this item */
  135. if (DEBUG)
  136. {
  137. qDebug() << "ctkPluginAbstractTracked::track[modified]: " << item;
  138. }
  139. modified(); /* increment modification count */
  140. }
  141. }
  142. if (!object)
  143. { /* we are not tracking the item */
  144. trackAdding(item, related);
  145. }
  146. else
  147. {
  148. /* Call customizer outside of synchronized region */
  149. customizerModified(item, related, object);
  150. /*
  151. * If the customizer throws an unchecked exception, it is safe to
  152. * let it propagate
  153. */
  154. }
  155. }
  156. template<class S, class T, class R>
  157. void ctkPluginAbstractTracked<S,T,R>::untrack(S item, R related)
  158. {
  159. T object(0);
  160. {
  161. QMutexLocker lock(this);
  162. if (initial.removeOne(item))
  163. { /* if this item is already in the list
  164. * of initial references to process
  165. */
  166. if (DEBUG)
  167. {
  168. qDebug() << "ctkPluginAbstractTracked::untrack[removed from initial]: " << item;
  169. }
  170. return; /* we have removed it from the list and it will not be
  171. * processed
  172. */
  173. }
  174. if (adding.removeOne(item))
  175. { /* if the item is in the process of
  176. * being added
  177. */
  178. if (DEBUG)
  179. {
  180. qDebug() << "ctkPluginAbstractTracked::untrack[being added]: " << item;
  181. }
  182. return; /*
  183. * in case the item is untracked while in the process of
  184. * adding
  185. */
  186. }
  187. object = tracked.take(item); /*
  188. * must remove from tracker before
  189. * calling customizer callback
  190. */
  191. if (!object)
  192. { /* are we actually tracking the item */
  193. return;
  194. }
  195. modified(); /* increment modification count */
  196. }
  197. if (DEBUG)
  198. {
  199. qDebug() << "ctkPluginAbstractTracked::untrack[removed]: " << item;
  200. }
  201. /* Call customizer outside of synchronized region */
  202. customizerRemoved(item, related, object);
  203. /*
  204. * If the customizer throws an unchecked exception, it is safe to let it
  205. * propagate
  206. */
  207. }
  208. template<class S, class T, class R>
  209. int ctkPluginAbstractTracked<S,T,R>::size() const
  210. {
  211. return tracked.size();
  212. }
  213. template<class S, class T, class R>
  214. T ctkPluginAbstractTracked<S,T,R>::getCustomizedObject(S item) const
  215. {
  216. return tracked.value(item);
  217. }
  218. template<class S, class T, class R>
  219. QList<S> ctkPluginAbstractTracked<S,T,R>::getTracked() const
  220. {
  221. return tracked.keys();
  222. }
  223. template<class S, class T, class R>
  224. void ctkPluginAbstractTracked<S,T,R>::modified()
  225. {
  226. trackingCount.ref();
  227. }
  228. template<class S, class T, class R>
  229. int ctkPluginAbstractTracked<S,T,R>::getTrackingCount() const
  230. {
  231. return trackingCount;
  232. }
  233. template<class S, class T, class R>
  234. bool ctkPluginAbstractTracked<S,T,R>::customizerAddingFinal(S item, const T& custom)
  235. {
  236. QMutexLocker lock(this);
  237. if (adding.removeOne(item) && !closed)
  238. {
  239. /*
  240. * if the item was not untracked during the customizer
  241. * callback
  242. */
  243. if (custom)
  244. {
  245. tracked.insert(item, custom);
  246. modified(); /* increment modification count */
  247. waitCond.wakeAll(); /* notify any waiters */
  248. }
  249. return false;
  250. }
  251. else
  252. {
  253. return true;
  254. }
  255. }
  256. template<class S, class T, class R>
  257. void ctkPluginAbstractTracked<S,T,R>::trackAdding(S item, R related)
  258. {
  259. if (DEBUG)
  260. {
  261. qDebug() << "ctkPluginAbstractTracked::trackAdding:" << item;
  262. }
  263. T object(0);
  264. bool becameUntracked = false;
  265. /* Call customizer outside of synchronized region */
  266. try
  267. {
  268. object = customizerAdding(item, related);
  269. becameUntracked = this->customizerAddingFinal(item, object);
  270. }
  271. catch (...)
  272. {
  273. /*
  274. * If the customizer throws an exception, it will
  275. * propagate after the cleanup code.
  276. */
  277. this->customizerAddingFinal(item, object);
  278. throw;
  279. }
  280. /*
  281. * The item became untracked during the customizer callback.
  282. */
  283. if (becameUntracked && object)
  284. {
  285. if (DEBUG)
  286. {
  287. qDebug() << "ctkPluginAbstractTracked::trackAdding[removed]: " << item;
  288. }
  289. /* Call customizer outside of synchronized region */
  290. customizerRemoved(item, related, object);
  291. /*
  292. * If the customizer throws an unchecked exception, it is safe to
  293. * let it propagate
  294. */
  295. }
  296. }