ctkPluginAbstractTracked.tpp 9.8 KB

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