Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CloningRefactorBranch/HeuristicLab.Core/Scope.cs @ 885

Last change on this file since 885 was 885, checked in by gkronber, 16 years ago

Refactored cloning in HL.Core, HL.Data and HL.Constraints

#285 (Cloning could be improved by creating objects at the bottom of the cloning chain with 'new' instead of the top with Activator.CreateInstance())

File size: 17.5 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.Generic;
24using System.Text;
25using System.Xml;
26
27namespace HeuristicLab.Core {
28  /// <summary>
29  /// Hierarchical container of variables (and of subscopes).
30  /// </summary>
31  public class Scope : ItemBase, IScope {
32    private IScope parent;
33
34    private string myName;
35    /// <summary>
36    /// Gets the name of the current scope.
37    /// </summary>
38    public string Name {
39      get { return myName; }
40    }
41
42    private IDictionary<string, IVariable> myVariables;
43    /// <inheritdoc/>
44    public ICollection<IVariable> Variables {
45      get { return myVariables.Values; }
46    }
47    private IDictionary<string, string> myAliases;
48    /// <inheritdoc/>
49    public IEnumerable<KeyValuePair<string, string>> Aliases {
50      get { return myAliases; }
51    }
52    private List<IScope> mySubScopes;
53    /// <summary>
54    /// Gets all subscopes of the current instance.
55    /// <note type="caution"> The subscopes are returned as read-only.</note>
56    /// </summary>
57    public IList<IScope> SubScopes {
58      get { return mySubScopes.AsReadOnly(); }
59    }
60
61    /// <summary>
62    /// Initializes a new instance of <see cref="Scope"/> having "Anonymous" as default name.
63    /// </summary>
64    public Scope() {
65      myName = "Anonymous";
66      myVariables = new Dictionary<string, IVariable>();
67      myAliases = new Dictionary<string, string>();
68      mySubScopes = new List<IScope>();
69    }
70    /// <summary>
71    /// Initializes a new instance of <see cref="Scope"/> with the given <paramref name="name"/>.
72    /// </summary>
73    /// <param name="name">The name of the scope.</param>
74    public Scope(string name)
75      : this() {
76      if (name != null) myName = name;
77    }
78
79    /// <summary>
80    /// Copy constructor to clone (deep) a Scope instance.
81    /// </summary>
82    /// <param name="original"></param>
83    public Scope(Scope original) : this(original, new Dictionary<Guid, object>()) { }
84
85    /// <summary>
86    /// Copy constructor to clone (deep) a Scope instance reusing
87    /// already cloned object references.
88    /// </summary>
89    /// <param name="original">The original instance to be cloned.</param>
90    /// <param name="clonedObjects">Already cloned object references (for referential integrity).</param>
91    protected Scope(Scope original, IDictionary<Guid, object> clonedObjects)
92      : base(original, clonedObjects) {
93      this.myName = original.Name;
94      foreach (IVariable variable in original.myVariables.Values)
95        AddVariable((IVariable)Auxiliary.Clone(variable, clonedObjects));
96      foreach (KeyValuePair<string, string> alias in original.myAliases)
97        AddAlias(alias.Key, alias.Value);
98      for (int i = 0; i < original.SubScopes.Count; i++)
99        AddSubScope((IScope)Auxiliary.Clone(original.SubScopes[i], clonedObjects));
100    }
101
102    /// <inheritdoc/>
103    public void SetParent(IScope scope) {
104      parent = scope;
105    }
106
107    /// <summary>
108    /// Creates a new instance of <see cref="ScopeView"/> to represent the current instance visually.
109    /// </summary>
110    /// <returns>The created view as <see cref="ScopeView"/>.</returns>
111    public override IView CreateView() {
112      return new ScopeView(this);
113    }
114
115    /// <inheritdoc/>
116    public IVariable GetVariable(string name) {
117      IVariable variable;
118      if (myVariables.TryGetValue(name, out variable))
119        return variable;
120      else
121        return null;
122    }
123    /// <inheritdoc/>
124    public void AddVariable(IVariable variable) {
125      myVariables.Add(variable.Name, variable);
126      variable.NameChanging += new EventHandler<NameChangingEventArgs>(Variable_NameChanging);
127      variable.NameChanged += new EventHandler(Variable_NameChanged);
128      OnVariableAdded(variable);
129    }
130
131    /// <inheritdoc/>
132    public void RemoveVariable(string name) {
133      IVariable variable;
134      if (myVariables.TryGetValue(name, out variable)) {
135        variable.NameChanging -= new EventHandler<NameChangingEventArgs>(Variable_NameChanging);
136        variable.NameChanged -= new EventHandler(Variable_NameChanged);
137        myVariables.Remove(name);
138        OnVariableRemoved(variable);
139      }
140    }
141    private void Variable_NameChanging(object sender, NameChangingEventArgs e) {
142      e.Cancel = myVariables.ContainsKey(e.Name);
143    }
144    private void Variable_NameChanged(object sender, EventArgs e) {
145      IVariable variable = (IVariable)sender;
146      string oldName = null;
147      foreach (KeyValuePair<string, IVariable> element in myVariables) {
148        if (element.Value == variable)
149          oldName = element.Key;
150      }
151      myVariables.Remove(oldName);
152      myVariables.Add(variable.Name, variable);
153    }
154    /// <inheritdoc cref="IScope.GetVariableValue&lt;T&gt;(string, bool)"/>
155    public T GetVariableValue<T>(string name, bool recursiveLookup) where T : class, IItem {
156      return GetVariableValue<T>(name, recursiveLookup, true);
157    }
158    /// <inheritdoc cref="IScope.GetVariableValue&lt;T&gt;(string, bool, bool)"/>
159    public T GetVariableValue<T>(string name, bool recursiveLookup, bool throwOnError) where T : class, IItem {
160      return (T)GetVariableValue(name, recursiveLookup, throwOnError);
161    }
162    /// <inheritdoc cref="IScope.GetVariableValue(string, bool)"/>
163    public IItem GetVariableValue(string name, bool recursiveLookup) {
164      return GetVariableValue(name, recursiveLookup, true);
165    }
166    /// <inheritdoc cref="IScope.GetVariableValue(string, bool, bool)"/>
167    public IItem GetVariableValue(string name, bool recursiveLookup, bool throwOnError) {
168      IVariable variable;
169      name = TranslateName(name);
170      if (myVariables.TryGetValue(name, out variable)) {
171        return variable.Value;
172      } else {
173        if (recursiveLookup && (parent != null))
174          return parent.GetVariableValue(name, recursiveLookup, throwOnError);
175        else {
176          if (throwOnError)
177            throw new ArgumentException("Variable " + name + " not found");
178          else
179            return null;
180        }
181      }
182    }
183    /// <inheritdoc/>
184    public string TranslateName(string name) {
185      while (myAliases.ContainsKey(name))
186        name = myAliases[name];
187      if (parent != null)
188        name = parent.TranslateName(name);
189      return name;
190    }
191    /// <inheritdoc/>
192    public void AddAlias(string alias, string name) {
193      RemoveAlias(alias);
194      if (alias != name) {
195        myAliases.Add(alias, name);
196        OnAliasAdded(alias);
197      }
198    }
199    /// <inheritdoc/>
200    public void RemoveAlias(string alias) {
201      if (myAliases.ContainsKey(alias)) {
202        myAliases.Remove(alias);
203        OnAliasRemoved(alias);
204      }
205    }
206
207    /// <inheritdoc/>
208    public void AddSubScope(IScope scope) {
209      scope.SetParent(this);
210      mySubScopes.Add(scope);
211      OnSubScopeAdded(scope, mySubScopes.Count - 1);
212    }
213    /// <inheritdoc/>
214    public void RemoveSubScope(IScope scope) {
215      int index = mySubScopes.IndexOf(scope);
216      if (mySubScopes.Remove(scope)) {
217        scope.SetParent(null);
218        OnSubScopeRemoved(scope, index);
219      }
220    }
221    /// <inheritdoc/>
222    public void ReorderSubScopes(int[] sequence) {
223      IScope[] scopes = mySubScopes.ToArray();
224      mySubScopes.Clear();
225      for (int i = 0; i < scopes.Length; i++)
226        mySubScopes.Add(scopes[sequence[i]]);
227      OnSubScopesReordered();
228    }
229    /// <inheritdoc/>
230    public IScope GetScope(Guid guid) {
231      if (Guid == guid) return this;
232      else {
233        for (int i = 0; i < mySubScopes.Count; i++) {
234          IScope s = mySubScopes[i].GetScope(guid);
235          if (s != null) return s;
236        }
237      }
238      return null;
239    }
240    /// <inheritdoc/>
241    public IScope GetScope(string name) {
242      if (Name == name) return this;
243      else {
244        for (int i = 0; i < mySubScopes.Count; i++) {
245          IScope s = mySubScopes[i].GetScope(name);
246          if (s != null) return s;
247        }
248      }
249      return null;
250    }
251
252    /// <inheritdoc/>
253    public void Clear() {
254      string[] variableNames = new string[Variables.Count];
255      int i = 0;
256      foreach (IVariable variable in Variables) {
257        variableNames[i] = variable.Name;
258        i++;
259      }
260      for (int j = 0; j < variableNames.Length; j++)
261        RemoveVariable(variableNames[j]);
262
263      KeyValuePair<string, string>[] aliases = new KeyValuePair<string, string>[myAliases.Count];
264      myAliases.CopyTo(aliases, 0);
265      for (int j = 0; j < aliases.Length; j++)
266        RemoveAlias(aliases[j].Key);
267
268      while (SubScopes.Count > 0)
269        RemoveSubScope(SubScopes[0]);
270    }
271
272    /// <inheritdoc/>
273    public override object Clone(IDictionary<Guid, object> clonedObjects) {
274      return new Scope(this, clonedObjects);
275    }
276
277    /// <inheritdoc />
278    public event EventHandler<VariableEventArgs> VariableAdded;
279    /// <summary>
280    /// Fires a new <c>VariableAdded</c> event.
281    /// </summary>
282    /// <param name="variable">The variable that has been added.</param>
283    protected virtual void OnVariableAdded(IVariable variable) {
284      if (VariableAdded != null)
285        VariableAdded(this, new VariableEventArgs(variable));
286    }
287    /// <inheritdoc />
288    public event EventHandler<VariableEventArgs> VariableRemoved;
289    /// <summary>
290    /// Fires a new <c>VariableRemoved</c>.
291    /// </summary>
292    /// <param name="variable">The variable that has been deleted.</param>
293    protected virtual void OnVariableRemoved(IVariable variable) {
294      if (VariableRemoved != null)
295        VariableRemoved(this, new VariableEventArgs(variable));
296    }
297    /// <inheritdoc />
298    public event EventHandler<AliasEventArgs> AliasAdded;
299    /// <summary>
300    /// Fires a new <c>AliasAdded</c> event.
301    /// </summary>
302    /// <param name="alias">The alias that has been added.</param>
303    protected virtual void OnAliasAdded(string alias) {
304      if (AliasAdded != null)
305        AliasAdded(this, new AliasEventArgs(alias));
306    }
307    /// <inheritdoc/>
308    public event EventHandler<AliasEventArgs> AliasRemoved;
309    /// <summary>
310    /// Fires a new <c>AliasRemoved</c> event.
311    /// </summary>
312    /// <param name="alias">The alias that has been deleted.</param>
313    protected virtual void OnAliasRemoved(string alias) {
314      if (AliasRemoved != null)
315        AliasRemoved(this, new AliasEventArgs(alias));
316    }
317    /// <inheritdoc/>
318    public event EventHandler<ScopeIndexEventArgs> SubScopeAdded;
319    /// <summary>
320    /// Fires a new <c>SubScopeAdded</c> event.
321    /// </summary>
322    /// <param name="scope">The sub scope that has been added.</param>
323    /// <param name="index">The index where the scope has been added.</param>
324    protected virtual void OnSubScopeAdded(IScope scope, int index) {
325      if (SubScopeAdded != null)
326        SubScopeAdded(this, new ScopeIndexEventArgs(scope, index));
327    }
328    /// <inheritdoc/>
329    public event EventHandler<ScopeIndexEventArgs> SubScopeRemoved;
330    /// <summary>
331    /// Fires a new <c>SubScopeRemoved</c> event.
332    /// </summary>
333    /// <param name="scope">The sub scope that has been deleted.</param>
334    /// <param name="index">The position of the sub scope.</param>
335    protected virtual void OnSubScopeRemoved(IScope scope, int index) {
336      if (SubScopeRemoved != null)
337        SubScopeRemoved(this, new ScopeIndexEventArgs(scope, index));
338    }
339    /// <inheritdoc />
340    public event EventHandler SubScopesReordered;
341    /// <summary>
342    /// Fires a new <c>SubScopesReordered</c> event
343    /// </summary>
344    protected virtual void OnSubScopesReordered() {
345      if (SubScopesReordered != null)
346        SubScopesReordered(this, new EventArgs());
347    }
348
349    #region Persistence Methods
350    /// <summary>
351    /// Saves the current instance as <see cref="XmlNode"/> in the given <paramref name="document"/>.
352    /// </summary>
353    /// <remarks>
354    /// Calls <see cref="StorableBase.GetXmlNode"/> of base class <see cref="ItemBase"/>.<br/>
355    /// A quick overview how the single elements of the current instance are saved:
356    /// <list type="bullet">
357    /// <item>
358    /// <term>Name: </term>
359    /// <description>Saved as an <see cref="XmlAttribute"/> having the tag name <c>Name</c>.</description>
360    /// </item>
361    /// <item>
362    /// <term>Variables: </term>
363    /// <description>A child node is created with the tag name <c>Variables</c>. Beyond this child node,
364    /// all variables are saved as child nodes.</description>
365    /// </item>
366    /// <item>
367    /// <term>Aliases: </term>
368    /// <description>A child node is created with the tag name <c>Aliases</c>. Beyond this child node,
369    /// all aliases are saved as child nodes with the tag name <c>Alias</c>. Each alias has an
370    /// <see cref="XmlAttribute"/> with the tag name "Alias", holding the alias, and an attribute
371    /// with the tag name <c>Name</c>, holding the name of the alias.</description>
372    /// </item>
373    /// <item>
374    /// <term>Sub scopes: </term>
375    /// <description>A child node is created with the tag name <c>SubScopes</c>. Beyond this child node,
376    /// all sub scopes are saved as child nodes.</description>
377    /// </item>
378    /// </list>
379    /// </remarks>
380    /// <param name="name">The (tag)name of the <see cref="XmlNode"/>.</param>
381    /// <param name="document">The <see cref="XmlDocument"/> where to save the data.</param>
382    /// <param name="persistedObjects">The dictionary of all already persisted objects. (Needed to avoid cycles.)</param>
383    /// <returns>The saved <see cref="XmlNode"/>.</returns>
384    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
385      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
386      XmlAttribute nameAttribute = document.CreateAttribute("Name");
387      nameAttribute.Value = Name.ToString();
388      node.Attributes.Append(nameAttribute);
389
390      XmlNode variables = document.CreateNode(XmlNodeType.Element, "Variables", null);
391      foreach (IVariable variable in Variables)
392        variables.AppendChild(PersistenceManager.Persist(variable, document, persistedObjects));
393      node.AppendChild(variables);
394
395      XmlNode aliases = document.CreateNode(XmlNodeType.Element, "Aliases", null);
396      foreach (KeyValuePair<string, string> alias in myAliases) {
397        XmlNode aliasNode = document.CreateNode(XmlNodeType.Element, "Alias", null);
398        XmlAttribute keyAttribute = document.CreateAttribute("Alias");
399        keyAttribute.Value = alias.Key;
400        aliasNode.Attributes.Append(keyAttribute);
401        XmlAttribute valueAttribute = document.CreateAttribute("Name");
402        valueAttribute.Value = alias.Value;
403        aliasNode.Attributes.Append(valueAttribute);
404        aliases.AppendChild(aliasNode);
405      }
406      node.AppendChild(aliases);
407
408      XmlNode subScopes = document.CreateNode(XmlNodeType.Element, "SubScopes", null);
409      for (int i = 0; i < SubScopes.Count; i++)
410        subScopes.AppendChild(PersistenceManager.Persist(SubScopes[i], document, persistedObjects));
411      node.AppendChild(subScopes);
412
413      return node;
414    }
415    /// <summary>
416    /// Loads the persisted scope from the specified <paramref name="node"/>.
417    /// </summary>
418    /// <remarks>See <see cref="GetXmlNode"/> to get further information on how the current instance must
419    /// be saved. <br/>
420    /// Calls <see cref="StorableBase.Populate"/> of base class <see cref="ItemBase"/>.</remarks>
421    /// <param name="node">The <see cref="XmlNode"/> where the boolean value is saved.</param>
422    /// <param name="restoredObjects">The dictionary of all already restored objects.
423    /// (Needed to avoid cycles.)</param>
424    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
425      base.Populate(node, restoredObjects);
426      myName = node.Attributes["Name"].Value;
427
428      XmlNode variables = node.SelectSingleNode("Variables");
429      foreach (XmlNode variableNode in variables.ChildNodes) {
430        IVariable variable = (IVariable)PersistenceManager.Restore(variableNode, restoredObjects);
431        AddVariable(variable);
432      }
433
434      XmlNode aliases = node.SelectSingleNode("Aliases");
435      if (aliases != null) {
436        foreach (XmlNode aliasNode in aliases.ChildNodes)
437          AddAlias(aliasNode.Attributes["Alias"].Value, aliasNode.Attributes["Name"].Value);
438      }
439
440      XmlNode subScopes = node.SelectSingleNode("SubScopes");
441      for (int i = 0; i < subScopes.ChildNodes.Count; i++) {
442        IScope scope = (IScope)PersistenceManager.Restore(subScopes.ChildNodes[i], restoredObjects);
443        AddSubScope(scope);
444      }
445    }
446    #endregion
447  }
448}
Note: See TracBrowser for help on using the repository browser.