Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Data/3.2/ConstrainedItemList.cs @ 2913

Last change on this file since 2913 was 2474, checked in by swagner, 15 years ago

Implemented generic EventArgs (#796)

File size: 15.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.Text;
26using System.Xml;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29
30namespace HeuristicLab.Data {
31  /// <summary>
32  /// A class representing a list of elements
33  /// (which are implementing the interface <see cref="IItem"/>) having some constraints.
34  /// </summary>
35  public class ConstrainedItemList : ConstrainedItemBase, IEnumerable, IEnumerable<IItem> {
36    private List<IItem> list;
37    private bool suspendConstraintCheck;
38
39    /// <summary>
40    /// Checks whether the test for the constraints is suspended.
41    /// </summary>
42    public bool ConstraintCheckSuspended {
43      get { return suspendConstraintCheck; }
44    }
45
46    /// <summary>
47    /// Initializes a new instance of <see cref="ConstrainedItemList"/> with the constraint check enabled.
48    /// </summary>
49    public ConstrainedItemList()
50      : base() {
51      list = new List<IItem>();
52      suspendConstraintCheck = false;
53    }
54
55    /// <summary>
56    /// Creates a new instance of <see cref="ConstrainedItemListView"/>.
57    /// </summary>
58    /// <returns>The created instance as <see cref="ConstrainedItemListView"/>.</returns>
59    public override IView CreateView() {
60      return new ConstrainedItemListView(this);
61    }
62
63    #region Clone & Persistence
64    /// <summary>
65    /// Clones the current instance.
66    /// </summary>
67    /// <remarks>The elements of the current instance are cloned with the
68    /// <see cref="HeuristicLab.Core.Auxiliary.Clone"/> method of the class <see cref="Auxiliary"/>.</remarks>
69    /// <param name="clonedObjects">A dictionary of all already cloned objects.</param>
70    /// <returns>The cloned instance as <see cref="ConstrainedItemList"/>.</returns>
71    public override object Clone(IDictionary<Guid, object> clonedObjects) {
72      ConstrainedItemList clone = new ConstrainedItemList();
73      clonedObjects.Add(Guid, clone);
74      foreach (IConstraint constraint in Constraints)
75        clone.AddConstraint((IConstraint)Auxiliary.Clone(constraint, clonedObjects));
76      clone.suspendConstraintCheck = suspendConstraintCheck;
77      foreach (IItem item in list) {
78        clone.list.Add((IItem)Auxiliary.Clone(item, clonedObjects));
79      }
80      return clone;
81    }
82
83    /// <summary>
84    /// Saves the current instance as <see cref="XmlNode"/> in the specified <paramref name="document"/>.
85    /// </summary>
86    /// <remarks>The basic instance is saved through the call of
87    /// <see cref="HeuristicLab.Core.ConstrainedItemBase.GetXmlNode"/> of base class
88    /// <see cref="ConstrainedItemBase"/>. <br/>
89    /// The list itself is saved as child node having the tag name <c>ListItems</c>
90    /// and each element is saved as a child node of the <c>ListItems</c> node.
91    /// The <c>suspendConstraintCheck</c> attribute is saved as an attribute of the list node
92    /// having the tag name <c>SuspendConstraintCheck</c>.</remarks>
93    /// <param name="name">The (tag)name of the <see cref="XmlNode"/>.</param>
94    /// <param name="document">The <see cref="XmlDocument"/> where the data is saved.</param>
95    /// <param name="persistedObjects">A dictionary of all already persisted objects. (Needed to avoid cycles.)</param>
96    /// <returns>The saved <see cref="XmlNode"/>.</returns>
97    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid,IStorable> persistedObjects) {
98      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
99      XmlNode listNode = document.CreateNode(XmlNodeType.Element, "ListItems", null);
100      for (int i = 0; i < list.Count; i++)
101        listNode.AppendChild(PersistenceManager.Persist(list[i], document, persistedObjects));
102      XmlAttribute sccAttrib = document.CreateAttribute("SuspendConstraintCheck");
103      sccAttrib.Value = suspendConstraintCheck.ToString();
104      listNode.Attributes.Append(sccAttrib);
105      node.AppendChild(listNode);
106      return node;
107    }
108
109    /// <summary>
110    /// Loads the persisted int value from the specified <paramref name="node"/>.
111    /// </summary>
112    /// <remarks>The elements of the list must be saved as child nodes of
113    /// the node with the tag name <c>ListItems</c>, which itself is a child node of the current instance.<br/>
114    /// The <c>suspendConstraintCheck</c> must be saved as attribute of the list node
115    /// with the tag name <c>SuspendConstraintCheck</c> (see <see cref="GetXmlNode"/>).</remarks>
116    /// <param name="node">The <see cref="XmlNode"/> where the int is saved.</param>
117    /// <param name="restoredObjects">A dictionary of all already restored objects. (Needed to avoid cycles.)</param>
118    public override void Populate(XmlNode node, IDictionary<Guid,IStorable> restoredObjects) {
119      base.Populate(node, restoredObjects);
120      XmlNode listNode = node.SelectSingleNode("ListItems");
121      list = new List<IItem>();
122      for (int i = 0; i < listNode.ChildNodes.Count; i++)
123        list.Add((IItem)PersistenceManager.Restore(listNode.ChildNodes[i], restoredObjects));
124      suspendConstraintCheck = bool.Parse(listNode.Attributes["SuspendConstraintCheck"].Value);
125    }
126    #endregion
127
128    /// <summary>
129    /// The string representation of the current list instance.
130    /// </summary>
131    /// <returns>The current list as string, each element separated by a semicolon.
132    /// "Empty List" if the list has no elements.</returns>
133    public override string ToString() {
134      if (list.Count > 0) {
135        StringBuilder builder = new StringBuilder();
136        builder.Append(list[0].ToString());
137        for (int i = 1; i < list.Count; i++) {
138          builder.Append(";");
139          builder.Append(list[i].ToString());
140        }
141        return builder.ToString();
142      } else {
143        return "Empty List";
144      }
145    }
146
147    /// <inheritdoc cref="List&lt;T&gt;.IndexOf(T)"/>
148    public int IndexOf(IItem item) {
149      return list.IndexOf(item);
150    }
151
152    /// <summary>
153    /// Sets <c>suspendConstraintCheck</c> to <c>true</c>.
154    /// </summary>
155    public void BeginCombinedOperation() {
156      suspendConstraintCheck = true;
157    }
158
159    /// <summary>
160    /// Checks whether the current instance fulfills all constraints.
161    /// </summary>
162    /// <param name="violatedConstraints">Output parameter,
163    /// contains all constraints that could not be fulfilled.</param>
164    /// <returns><c>true</c> if all constraints could be fulfilled, <c>false</c> otherwise.</returns>
165    public bool EndCombinedOperation(out ICollection<IConstraint> violatedConstraints) {
166      if (IsValid(out violatedConstraints))
167        suspendConstraintCheck = false;
168      else
169        suspendConstraintCheck = true;
170
171      return !suspendConstraintCheck;
172    }
173
174    /// <summary>
175    /// Adds a new <paramref name="item"/> at a specified <paramref name="index"/> to the current instance if all constraints are fulfilled.
176    /// </summary>
177    /// <remarks>Calls <see cref="OnItemAdded"/> if the insertion was successful.</remarks>
178    /// <param name="index">The position where to insert the new element.</param>
179    /// <param name="item">The new element to insert.</param>
180    /// <param name="violatedConstraints">Output parameter, all constraints that could not be fulfilled.</param>
181    /// <returns><c>true</c> if the insertion was successful, <c>false</c> otherwise.</returns>
182    public bool TryInsert(int index, IItem item, out ICollection<IConstraint> violatedConstraints) {
183      list.Insert(index, item);
184      violatedConstraints = new List<IConstraint>();
185      if (suspendConstraintCheck || IsValid(out violatedConstraints)) {
186        OnItemAdded(item, index);
187        return true;
188      } else {
189        list.RemoveAt(index);
190        return false;
191      }
192    }
193
194    /// <summary>
195    /// Removes an element at the specified <paramref name="index"/>
196    /// from the current instance if all constraints are fulfilled.
197    /// </summary>
198    /// <remarks>Calls <see cref="OnItemRemoved"/> if the deletion was successful.</remarks>
199    /// <param name="index">The position where to remove the element.</param>
200    /// <param name="violatedConstraints">Output parameter, all constraints that could not be fulfilled.</param>
201    /// <returns><c>true</c> if the element could be removed successfully, <c>false</c> otherwise.</returns>
202    public bool TryRemoveAt(int index, out ICollection<IConstraint> violatedConstraints) {
203      IItem item = list[index];
204      list.RemoveAt(index);
205      violatedConstraints = new List<IConstraint>();
206      if (suspendConstraintCheck || IsValid(out violatedConstraints)) {
207        OnItemRemoved(item, index);
208        return true;
209      } else {
210        list.Insert(index, item);
211        return false;
212      }
213    }
214
215    /// <summary>
216    /// Gets the element of the current instance at the specified <paramref name="index"/>.
217    /// </summary>
218    /// <param name="index">The position of the searched element.</param>
219    /// <returns>The searched element as <see cref="IItem"/>.</returns>
220    public IItem this[int index] {
221      get { return list[index]; }
222    }
223
224    /// <summary>
225    /// Changes the element at a specified position if all constraints are fulfilled.
226    /// </summary>
227    /// <param name="index">The position where to change the element.</param>
228    /// <param name="item">The element that replaces the current one.</param>
229    /// <param name="violatedConstraints">Output parameter, all constraints that could not be fulfilled.</param>
230    /// <returns><c>true</c> if the substitution was successful, <c>false</c> otherwise.</returns>
231    public bool TrySetAt(int index, IItem item, out ICollection<IConstraint> violatedConstraints) {
232      IItem backup = this[index];
233      list[index] = item;
234      violatedConstraints = new List<IConstraint>();
235      if (suspendConstraintCheck || IsValid(out violatedConstraints)) {
236        return true;
237      } else {
238        list[index] = backup;
239        return false;
240      }
241    }
242
243    /// <summary>
244    /// Adds a new <paramref name="item"/> to the current list if all constraints are fulfilled.
245    /// </summary>
246    /// <remarks>Calls <see cref="OnItemAdded"/> if the add was successful.</remarks>
247    /// <param name="item">The element to add.</param>
248    /// <param name="violatedConstraints">Output parameter, all constraints that could not be fulfilled.</param>
249    /// <returns><c>true</c> if the element could be successfully added, <c>false</c> otherwise.</returns>
250    public bool TryAdd(IItem item, out ICollection<IConstraint> violatedConstraints) {
251      list.Add(item);
252      violatedConstraints = new List<IConstraint>();
253      if (suspendConstraintCheck || IsValid(out violatedConstraints)) {
254        OnItemAdded(item, list.Count - 1);
255        return true;
256      } else {
257        list.RemoveAt(list.Count - 1);
258        return false;
259      }
260    }
261    /// <summary>
262    /// Empties the current list.
263    /// </summary>
264    /// <remarks>Calls <see cref="OnCleared"/>.</remarks>
265    public void Clear() {
266      list.Clear();
267      OnCleared();
268    }
269    /// <inheritdoc cref="List&lt;T&gt;.Contains"/>
270    public bool Contains(IItem item) {
271      return list.Contains(item);
272    }
273    /// <inheritdoc cref="List&lt;T&gt;.CopyTo(T[],int)"/>
274    public void CopyTo(IItem[] array, int arrayIndex) {
275      list.CopyTo(array, arrayIndex);
276    }
277    /// <inheritdoc cref="List&lt;T&gt;.Count"/>
278    public int Count {
279      get { return list.Count; }
280    }
281    /// <summary>
282    /// Checks whether the current instance is read-only.
283    /// </summary>
284    /// <remarks>Always returns <c>false</c>.</remarks>
285    public bool IsReadOnly {
286      get { return false; }
287    }
288    /// <summary>
289    /// Removes a specified <paramref name="item"/> from the
290    /// current instance if all constraints are fulfilled.
291    /// </summary>
292    /// <param name="item">The element to remove.</param>
293    /// <param name="violatedConstraints">Output parameter, all constraints that could not be fulfilled.</param>
294    /// <returns><c>true</c> if the deletion was successful, <c>false</c> otherwise.</returns>
295    public bool TryRemove(IItem item, out ICollection<IConstraint> violatedConstraints) {
296      int index = list.IndexOf(item);
297      if (index >= 0) {
298        return TryRemoveAt(index, out violatedConstraints);
299      } else {
300        violatedConstraints = new List<IConstraint>();
301        return false;
302      }
303    }
304
305    /// <inheritdoc cref="List&lt;T&gt;.GetEnumerator"/>
306    public IEnumerator<IItem> GetEnumerator() {
307      return list.GetEnumerator();
308    }
309
310    /// <inheritdoc cref="List&lt;T&gt;.GetEnumerator"/>
311    IEnumerator IEnumerable.GetEnumerator() {
312      return list.GetEnumerator();
313    }
314
315    /// <summary>
316    /// Occurs when a new item is added.
317    /// </summary>
318    public event EventHandler<EventArgs<IItem, int>> ItemAdded;
319    /// <summary>
320    /// Fires a new <c>ItemAdded</c> event.
321    /// </summary>         
322    /// <remarks>Calls <see cref="HeuristicLab.Core.ItemBase.OnChanged"/>.</remarks>
323    /// <param name="item">The element that was added.</param>
324    /// <param name="index">The position where the element was added.</param>
325    protected virtual void OnItemAdded(IItem item, int index) {
326      if (ItemAdded != null)
327        ItemAdded(this, new EventArgs<IItem, int>(item, index));
328      OnChanged();
329    }
330    /// <summary>
331    /// Occurs when an element is removed from the current instance.
332    /// </summary>
333    public event EventHandler<EventArgs<IItem, int>> ItemRemoved;
334    /// <summary>
335    /// Fires a new <c>ItemRemoved</c> event.
336    /// </summary>
337    /// <remarks>Calls <see cref="HeuristicLab.Core.ItemBase.OnChanged"/>.</remarks>
338    /// <param name="item">The element that has been removed.</param>
339    /// <param name="index">The position from where it has been removed.</param>
340    protected virtual void OnItemRemoved(IItem item, int index) {
341      if (ItemRemoved != null)
342        ItemRemoved(this, new EventArgs<IItem, int>(item, index));
343      OnChanged();
344    }
345    /// <summary>
346    /// Occurs when the current list is emptied.
347    /// </summary>
348    public event EventHandler Cleared;
349    /// <summary>
350    /// Fires a new <c>Cleared</c> event.
351    /// </summary>
352    /// <remarks>Calls <see cref="HeuristicLab.Core.ItemBase.OnChanged"/>.</remarks>
353    protected virtual void OnCleared() {
354      if (Cleared != null)
355        Cleared(this, new EventArgs());
356      OnChanged();
357    }
358  }
359}
Note: See TracBrowser for help on using the repository browser.