/common/src/core/Core/Collections/EditableIDList.cs

https://github.com/woeishi/vvvv-sdk · C# · 436 lines · 346 code · 80 blank · 10 comment · 46 complexity · 5e6567136635a67536ed32936aa3b39f MD5 · raw file

  1. using System;
  2. using System.Linq;
  3. using System.Text;
  4. using VVVV.Core;
  5. using VVVV.Core.Model;
  6. using System.Collections.Generic;
  7. namespace VVVV.Core.Collections
  8. {
  9. // items named
  10. // therefore lookup works through [string name]
  11. // since it is an editablecollection it provides easy acces to
  12. // IViewableCollection and IEditableCollection
  13. [Serializable]
  14. public class EditableIDList<T> : EditableList<T>,
  15. IViewableIDList<T>, IEditableIDList<T>,
  16. IViewableIDList, IEditableIDList where T: IIDItem
  17. {
  18. protected KeyedIDCollection<T> FItems;
  19. private bool FOwnsItems;
  20. public bool OwnsItems
  21. {
  22. get
  23. {
  24. return FOwnsItems;
  25. }
  26. set
  27. {
  28. if (Count == 0)
  29. FOwnsItems = value;
  30. else
  31. throw new Exception("OwnsItems property should be set on startup");
  32. }
  33. }
  34. public bool AllowRenameOnAdd { get; set; }
  35. public ModelMapper Mapper
  36. {
  37. get;
  38. private set;
  39. }
  40. public EditableIDList(KeyedIDCollection<T> collection, string name)
  41. : base(collection)
  42. {
  43. Name = name;
  44. FItems = collection;
  45. OwnsItems = true;
  46. }
  47. public EditableIDList(KeyedIDCollection<T> collection, string name, bool allowRenameOnAdd)
  48. : this(collection, name)
  49. {
  50. AllowRenameOnAdd = allowRenameOnAdd;
  51. }
  52. public EditableIDList(string name)
  53. : this(new KeyedIDCollection<T>(), name)
  54. {
  55. }
  56. public EditableIDList(string name, bool allowRenameOnAdd)
  57. : this(new KeyedIDCollection<T>(), name, allowRenameOnAdd)
  58. {
  59. }
  60. protected EditableIDList(IList<T> list, KeyedIDCollection<T> collection, string name, bool allowRenameOnAdd)
  61. : base(list)
  62. {
  63. Name = name;
  64. FItems = collection;
  65. OwnsItems = true;
  66. AllowRenameOnAdd = allowRenameOnAdd;
  67. }
  68. public override void Dispose()
  69. {
  70. if (FOwner != null)
  71. {
  72. FOwner.RootingChanged -= FOwner_RootingChanged;
  73. }
  74. ItemRenamed = null;
  75. Renamed = null;
  76. base.Dispose();
  77. }
  78. public bool Contains(string name)
  79. {
  80. return FItems.Contains(name);
  81. }
  82. public ViewableIDList<T> AsViewableIDList()
  83. {
  84. return new ViewableIDList<T>(this);
  85. }
  86. protected override void AddToInternalCollection(T item)
  87. {
  88. if (Contains(item))
  89. if (AllowRenameOnAdd && (item is IRenameable) && (!item.Equals(this[item.Name])))
  90. (item as IRenameable).Name = GetNewQualifyingName(item.Name);
  91. else
  92. throw new Exception("Item can't be added since there is already an item with that name in the list. Either it is not renameable, or rename on add is not allowed by the list, or that item exists already in the list.");
  93. base.AddToInternalCollection(item);
  94. if (FItems != FList)
  95. FItems.Add(item);
  96. if (OwnsItems)
  97. item.Owner = this;
  98. item.Renamed += item_Renamed;
  99. }
  100. private string GetNewQualifyingName(string name)
  101. {
  102. var x = 2;
  103. while (Contains(name + x.ToString()))
  104. x++;
  105. return name + x.ToString();
  106. }
  107. protected override bool RemoveFromInternalCollection(T item)
  108. {
  109. TearDownItem(item);
  110. return base.RemoveFromInternalCollection(item);
  111. }
  112. private void TearDownItem(T item)
  113. {
  114. if (OwnsItems)
  115. item.Owner = null;
  116. if (FItems != FList)
  117. FItems.Remove(item);
  118. item.Renamed -= item_Renamed;
  119. }
  120. protected override void ClearInternalCollection()
  121. {
  122. foreach (var item in FCollection)
  123. {
  124. TearDownItem(item);
  125. }
  126. base.ClearInternalCollection();
  127. }
  128. private void item_Renamed(INamed sender, string newName)
  129. {
  130. FItems.ChangeKey((T)sender, newName);
  131. OnItemRenamed(sender, newName);
  132. }
  133. public override void MarkChanged()
  134. {
  135. base.MarkChanged();
  136. if (Owner != null)
  137. {
  138. Owner.MarkChanged();
  139. }
  140. }
  141. public override void AcknowledgeChanges()
  142. {
  143. base.AcknowledgeChanges();
  144. foreach (IIDItem item in this)
  145. {
  146. item.AcknowledgeChanges();
  147. }
  148. }
  149. #region IEditableIDList<T> Members
  150. #endregion
  151. #region IEditableIDList Members
  152. IIDItem IEditableIDList.this[int index]
  153. {
  154. get
  155. {
  156. return this[index];
  157. }
  158. set
  159. {
  160. this[index] = (T) value;
  161. }
  162. }
  163. #endregion
  164. #region IViewableIDList<T> Members
  165. #endregion
  166. #region IViewableIDList Members
  167. IIDItem IViewableIDList.this[int index]
  168. {
  169. get
  170. {
  171. return this[index];
  172. }
  173. }
  174. #endregion
  175. #region IIDContainer<T> Members
  176. public event RenamedHandler ItemRenamed;
  177. public T this[string name]
  178. {
  179. get
  180. {
  181. if (FItems.Contains(name))
  182. return FItems[name];
  183. return default(T);
  184. }
  185. }
  186. protected virtual void OnItemRenamed(INamed item, string newName)
  187. {
  188. if (ItemRenamed != null) {
  189. ItemRenamed(item, newName);
  190. }
  191. }
  192. #endregion
  193. #region IIDContainer Members
  194. IIDItem IIDContainer.this[string name]
  195. {
  196. get
  197. {
  198. return this[name];
  199. }
  200. }
  201. #endregion
  202. #region IIDItem Members
  203. IIDContainer FOwner;
  204. public IIDContainer Owner
  205. {
  206. get
  207. {
  208. return FOwner;
  209. }
  210. set
  211. {
  212. if (FOwner != null)
  213. {
  214. if (value != null)
  215. {
  216. throw new Exception(string.Format("ID item {0} ('{1}') has owner already.", this, Name));
  217. }
  218. // Unsubscribe from old owner
  219. FOwner.RootingChanged -= FOwner_RootingChanged;
  220. CheckIfRootingChanged(new RootingChangedEventArgs(RootingAction.ToBeUnrooted));
  221. }
  222. FOwner = value;
  223. if (FOwner != null)
  224. {
  225. // Subscribe to new owner
  226. FOwner.RootingChanged += FOwner_RootingChanged;
  227. CheckIfRootingChanged(new RootingChangedEventArgs(RootingAction.Rooted));
  228. }
  229. }
  230. }
  231. public bool IsRooted
  232. {
  233. get;
  234. private set;
  235. }
  236. public event RootingChangedEventHandler RootingChanged;
  237. public virtual void Dispatch(IVisitor visitor)
  238. {
  239. visitor.Visit(this);
  240. }
  241. private void CheckIfRootingChanged(RootingChangedEventArgs args)
  242. {
  243. switch (args.Rooting)
  244. {
  245. case RootingAction.Rooted:
  246. if (FOwner.IsRooted && !IsRooted)
  247. {
  248. IsRooted = true;
  249. OnRootingChanged(args);
  250. }
  251. break;
  252. case RootingAction.ToBeUnrooted:
  253. if (FOwner.IsRooted && IsRooted)
  254. {
  255. OnRootingChanged(args);
  256. IsRooted = false;
  257. }
  258. break;
  259. }
  260. }
  261. private void OnRootingChanged(RootingChangedEventArgs args)
  262. {
  263. if (args.Rooting == RootingAction.Rooted)
  264. {
  265. Mapper = FOwner.Mapper.CreateChildMapper(this);
  266. OnRootingChanged(RootingAction.Rooted);
  267. }
  268. if (RootingChanged != null)
  269. {
  270. RootingChanged(this, args);
  271. }
  272. if (args.Rooting == RootingAction.ToBeUnrooted)
  273. {
  274. OnRootingChanged(RootingAction.ToBeUnrooted);
  275. Mapper.Dispose();
  276. }
  277. }
  278. protected virtual void OnRootingChanged(RootingAction rooting)
  279. {
  280. }
  281. void FOwner_RootingChanged(object sender, RootingChangedEventArgs args)
  282. {
  283. // Propagate the event down further in the object graph
  284. CheckIfRootingChanged(args);
  285. }
  286. #endregion
  287. #region INamed Members
  288. public string Name
  289. {
  290. get;
  291. private set;
  292. }
  293. // as long as Name is private we don't fire this (name is only set on construction)
  294. public event RenamedHandler Renamed;
  295. protected virtual void OnRenamed(string newName)
  296. {
  297. if (Renamed != null) {
  298. Renamed(this, newName);
  299. }
  300. }
  301. #endregion
  302. #region Overwritten ViewableCollection<T> Members
  303. new public bool Contains(T item)
  304. {
  305. return Contains(item.Name);
  306. }
  307. #endregion
  308. #region Overwritten EditableCollection<T> Members
  309. public override bool CanAdd(T item)
  310. {
  311. if (Contains(item))
  312. if (this[item.Name].Equals(item))
  313. // don't allow to add same object twice (it only can have one name)
  314. return false;
  315. else
  316. // allow to add item when name is already used and AllowRenameOnAdd == true
  317. return (AllowRenameOnAdd && (item is IRenameable));
  318. else
  319. return base.CanAdd(item);
  320. }
  321. #endregion
  322. #region Overwritten EditableList<T> Members
  323. public override T this[int index]
  324. {
  325. get
  326. {
  327. return base[index];
  328. }
  329. set
  330. {
  331. base[index] = value;
  332. if (OwnsItems)
  333. value.Owner = this;
  334. value.Renamed += item_Renamed;
  335. }
  336. }
  337. public override void Sort(Comparison<T> comparison)
  338. {
  339. if (FList is KeyedIDCollection<T>)
  340. {
  341. (FList as KeyedIDCollection<T>).Sort(comparison);
  342. OnOrderChanged();
  343. }
  344. else if (FList is System.Collections.Generic.List<T>)
  345. {
  346. (FList as System.Collections.Generic.List<T>).Sort(comparison);
  347. OnOrderChanged();
  348. }
  349. }
  350. #endregion
  351. public override string ToString()
  352. {
  353. return string.Format("{0}: {1}", Name, this.GetType().Name);
  354. }
  355. }
  356. }