Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Data/ConstrainedItemList.cs @ 1343

Last change on this file since 1343 was 1203, checked in by abeham, 15 years ago

fixed bug described in #483 in ConstrainedItemList

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