source: trunk/sources/HeuristicLab.Operators.Views.GraphVisualization/3.3/OperatorGraphVisualization/OperatorGraphVisualizationInfo.cs @ 3729

Last change on this file since 3729 was 3729, checked in by swagner, 12 years ago

Fixed exception thrown in OperatorGraph views when removing one of the operator parameters of a MultiOperator (#1004)

File size: 21.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.Generic;
24using System.Linq;
25using System.Text;
26using HeuristicLab.Core;
27using Netron.Diagramming.Core;
28using System.Drawing;
29using HeuristicLab.Collections;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31using HeuristicLab.Common;
32
33namespace HeuristicLab.Operators.Views.GraphVisualization {
34  [StorableClass]
35  public sealed class OperatorGraphVisualizationInfo : GraphVisualizationInfo {
36    [Storable]
37    private BidirectionalLookup<IOperator, IOperatorShapeInfo> operatorShapeInfoMapping;
38    private BidirectionalLookup<IOperator, IKeyedItemCollection<string, IParameter>> operatorParameterCollectionMapping;
39    private Dictionary<IParameter, IOperator> parameterOperatorMapping;
40
41    private OperatorGraphVisualizationInfo()
42      : base() {
43      this.operatorShapeInfoMapping = new BidirectionalLookup<IOperator, IOperatorShapeInfo>();
44      this.operatorParameterCollectionMapping = new BidirectionalLookup<IOperator, IKeyedItemCollection<string, IParameter>>();
45      this.parameterOperatorMapping = new Dictionary<IParameter, IOperator>();
46    }
47
48    [StorableConstructor]
49    private OperatorGraphVisualizationInfo(bool deserializing)
50      : base() {
51      this.operatorParameterCollectionMapping = new BidirectionalLookup<IOperator, IKeyedItemCollection<string, IParameter>>();
52      this.parameterOperatorMapping = new Dictionary<IParameter, IOperator>();
53    }
54
55    public OperatorGraphVisualizationInfo(OperatorGraph operatorGraph)
56      : this() {
57      this.operatorGraph = operatorGraph;
58      this.RegisterOperatorGraphEvents();
59
60      foreach (IOperator op in operatorGraph.Operators)
61        if (!this.operatorShapeInfoMapping.ContainsFirst(op))  //could be added by referencing parameters
62          this.AddOperator(op);
63
64      this.UpdateInitialShape();
65    }
66
67    [StorableHook(HookType.AfterDeserialization)]
68    private void DeserializationHook() {
69      this.operatorGraph.DeserializationFinished += new EventHandler(operatorGraph_DeserializationFinished);
70
71      IOperator op;
72      IOperatorShapeInfo shapeInfo;
73      foreach (KeyValuePair<IOperator, IOperatorShapeInfo> pair in this.operatorShapeInfoMapping.FirstEnumerable) {
74        op = pair.Key;
75        shapeInfo = pair.Value;
76        shapeInfo.Icon = new Bitmap(op.ItemImage);
77        this.RegisterOperatorEvents(op);
78        this.operatorParameterCollectionMapping.Add(op, op.Parameters);
79      }
80
81      foreach (IOperator oper in this.operatorShapeInfoMapping.FirstValues) {
82        foreach (IParameter param in oper.Parameters) {
83          IValueParameter opParam = param as IValueParameter;
84          this.parameterOperatorMapping.Add(param, oper);
85          if (opParam != null && typeof(IOperator).IsAssignableFrom(param.DataType))
86            this.RegisterOperatorParameterEvents(opParam);
87          else
88            this.RegisterParameterEvents(param);
89        }
90      }
91    }
92
93    private void operatorGraph_DeserializationFinished(object sender, EventArgs e) {
94      this.RegisterOperatorGraphEvents();
95      if (this.operatorGraph.InitialOperator != null) {
96        IOperatorShapeInfo newInitialShapeInfo = this.operatorShapeInfoMapping.GetByFirst(this.operatorGraph.InitialOperator);
97        if (newInitialShapeInfo != null) {
98          oldInitialShapeColor = newInitialShapeInfo.Color;
99          newInitialShapeInfo.Color = Color.LightGreen;
100        }
101        oldInitialShape = this.InitialShape;
102        this.OnInitialShapeChanged();
103      }
104      this.operatorGraph.DeserializationFinished -= new EventHandler(operatorGraph_DeserializationFinished);
105    }
106
107    public override IDeepCloneable Clone(Cloner cloner) {
108      OperatorGraphVisualizationInfo clone = (OperatorGraphVisualizationInfo)base.Clone(cloner);
109      clone.operatorGraph = (OperatorGraph)cloner.Clone(this.operatorGraph);
110      clone.RegisterOperatorGraphEvents();
111      clone.oldInitialShape = (IOperatorShapeInfo)cloner.Clone(this.oldInitialShape);
112      clone.oldInitialShapeColor = this.oldInitialShapeColor;
113
114      IOperator op;
115      IOperatorShapeInfo shapeInfo;
116      foreach (KeyValuePair<IOperator, IOperatorShapeInfo> pair in this.operatorShapeInfoMapping.FirstEnumerable) {
117        op = (IOperator)cloner.Clone(pair.Key);
118        shapeInfo = (IOperatorShapeInfo)cloner.Clone(pair.Value);
119        clone.RegisterOperatorEvents(op);
120        clone.operatorParameterCollectionMapping.Add(op, pair.Key.Parameters);
121        clone.operatorShapeInfoMapping.Add(op, shapeInfo);
122      }
123
124      foreach (IOperator oper in clone.operatorShapeInfoMapping.FirstValues) {
125        foreach (IParameter param in oper.Parameters) {
126          clone.parameterOperatorMapping.Add(param, oper);
127          IValueParameter opParam = param as IValueParameter;
128          if (opParam != null && typeof(IOperator).IsAssignableFrom(param.DataType))
129            clone.RegisterOperatorParameterEvents(opParam);
130          else
131            clone.RegisterParameterEvents(param);
132        }
133      }
134      if (this.operatorGraph.InitialOperator != null) {
135        IOperatorShapeInfo newInitialShapeInfo = this.operatorShapeInfoMapping.GetByFirst(this.operatorGraph.InitialOperator);
136        if (newInitialShapeInfo != null) {
137          oldInitialShapeColor = newInitialShapeInfo.Color;
138          newInitialShapeInfo.Color = Color.LightGreen;
139        }
140        oldInitialShape = this.InitialShape;
141        this.OnInitialShapeChanged();
142      }
143      return clone;
144    }
145
146    internal IOperator GetOperatorForShapeInfo(IOperatorShapeInfo shapeInfo) {
147      return this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
148    }
149
150    private void operatorGraph_InitialOperatorChanged(object sender, EventArgs e) {
151      this.UpdateInitialShape();
152    }
153
154    private void UpdateInitialShape() {
155      IOperatorShapeInfo old = this.oldInitialShape as OperatorShapeInfo;
156      if (old != null)
157        old.Color = oldInitialShapeColor;
158
159      OperatorShapeInfo newInitialShapeInfo = this.InitialShape as OperatorShapeInfo;
160      if (newInitialShapeInfo != null) {
161        oldInitialShapeColor = newInitialShapeInfo.Color;
162        newInitialShapeInfo.Color = Color.LightGreen;
163      }
164
165      oldInitialShape = this.InitialShape;
166      this.OnInitialShapeChanged();
167    }
168
169    private IShapeInfo oldInitialShape;
170    private Color oldInitialShapeColor;
171    public override IShapeInfo InitialShape {
172      get {
173        IOperator op = this.operatorGraph.InitialOperator;
174        if (op == null)
175          return null;
176        return this.operatorShapeInfoMapping.GetByFirst(op);
177      }
178      set {
179        if (value == null)
180          this.OperatorGraph.InitialOperator = null;
181        else {
182          IOperatorShapeInfo shapeInfo = (IOperatorShapeInfo)value;
183          this.OperatorGraph.InitialOperator = this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
184        }
185      }
186    }
187
188    [Storable]
189    private OperatorGraph operatorGraph;
190    public OperatorGraph OperatorGraph {
191      get { return this.operatorGraph; }
192    }
193
194    private void RegisterOperatorGraphEvents() {
195      this.operatorGraph.InitialOperatorChanged += new EventHandler(operatorGraph_InitialOperatorChanged);
196      this.operatorGraph.Operators.ItemsAdded += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_ItemsAdded);
197      this.operatorGraph.Operators.ItemsRemoved += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_ItemsRemoved);
198      this.operatorGraph.Operators.CollectionReset += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_CollectionReset);
199    }
200
201    private void DeregisterOperatorGraphEvents() {
202      this.operatorGraph.InitialOperatorChanged -= new EventHandler(operatorGraph_InitialOperatorChanged);
203      this.operatorGraph.Operators.ItemsAdded -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_ItemsAdded);
204      this.operatorGraph.Operators.ItemsRemoved -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_ItemsRemoved);
205      this.operatorGraph.Operators.CollectionReset -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IOperator>(Operators_CollectionReset);
206    }
207
208    #region methods to manipulate operatorgraph by the shape info
209    internal void AddShapeInfo(IOperator op, IOperatorShapeInfo shapeInfo) {
210      this.RegisterOperatorEvents(op);
211      this.operatorParameterCollectionMapping.Add(op, op.Parameters);
212      this.operatorShapeInfoMapping.Add(op, shapeInfo);
213      this.shapeInfos.Add(shapeInfo);
214
215      foreach (IParameter param in op.Parameters)
216        this.AddParameter(op, param);
217
218      this.operatorGraph.Operators.Add(op);
219    }
220
221    public override void RemoveShapeInfo(IShapeInfo shapeInfo) {
222      IOperatorShapeInfo opShapeInfo = (IOperatorShapeInfo)shapeInfo;
223      if (this.operatorShapeInfoMapping.ContainsSecond(opShapeInfo)) {
224        IOperator op = this.operatorShapeInfoMapping.GetBySecond(opShapeInfo);
225        this.operatorGraph.Operators.Remove(op);
226      }
227    }
228
229    public override void RemoveConnectionInfo(IConnectionInfo connectionInfo) {
230      IOperatorShapeInfo shapeInfo = (IOperatorShapeInfo)connectionInfo.From;
231      IOperator op = this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
232      IValueParameter param = (IValueParameter)op.Parameters[connectionInfo.ConnectorFrom];
233      param.Value = null;
234    }
235
236    public override void AddConnectionInfo(IConnectionInfo connectionInfo) {
237      IOperatorShapeInfo shapeInfo = (IOperatorShapeInfo)connectionInfo.From;
238      IOperator op = this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
239      IOperatorShapeInfo shapeInfoTo = (IOperatorShapeInfo)connectionInfo.To;
240      IOperator opTo = this.operatorShapeInfoMapping.GetBySecond(shapeInfoTo);
241      IValueParameter param = (IValueParameter)op.Parameters.Where(p => p.Name == connectionInfo.ConnectorFrom).SingleOrDefault();
242      if (param != null)
243        param.Value = opTo;
244    }
245    #endregion
246
247    #region operator events
248    private void AddOperator(IOperator op) {
249      if (!this.operatorShapeInfoMapping.ContainsFirst(op)) {
250        this.RegisterOperatorEvents(op);
251        IOperatorShapeInfo shapeInfo = OperatorShapeInfoFactory.CreateOperatorShapeInfo(op);
252        this.operatorParameterCollectionMapping.Add(op, op.Parameters);
253        this.operatorShapeInfoMapping.Add(op, shapeInfo);
254        this.shapeInfos.Add(shapeInfo);
255        foreach (IParameter param in op.Parameters)
256          this.AddParameter(op, param);
257      }
258    }
259    private void RemoveOperator(IOperator op) {
260      this.DeregisterOperatorEvents(op);
261      foreach (IParameter param in op.Parameters)
262        this.RemoveParameter(op, param);
263
264      IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
265      this.operatorParameterCollectionMapping.RemoveByFirst(op);
266      this.operatorShapeInfoMapping.RemoveByFirst(op);
267      this.shapeInfos.Remove(shapeInfo);
268    }
269
270    private void OperatorBreakpointChanged(object sender, EventArgs e) {
271      IOperator op = (IOperator)sender;
272      IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
273      if (op.Breakpoint) {
274        operatorShapeInfo.LineColor = Color.Red;
275        operatorShapeInfo.LineWidth = 2;
276      } else {
277        operatorShapeInfo.LineColor = Color.Black;
278        operatorShapeInfo.LineWidth = 1;
279      }
280    }
281
282    private void OperatorItemImageChanged(object sender, EventArgs e) {
283      IOperator op = (IOperator)sender;
284      IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
285      operatorShapeInfo.Icon = new Bitmap(op.ItemImage);
286    }
287
288    private void OperatorNameChanged(object sender, EventArgs e) {
289      IOperator op = (IOperator)sender;
290      IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
291      operatorShapeInfo.Title = op.Name;
292    }
293
294    private void Operators_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IOperator> e) {
295      foreach (IOperator op in e.Items)
296        this.AddOperator(op);
297    }
298    private void Operators_ItemsRemoved(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IOperator> e) {
299      foreach (IOperator op in e.Items)
300        this.RemoveOperator(op);
301    }
302    private void Operators_CollectionReset(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IOperator> e) {
303      foreach (IOperator op in e.OldItems)
304        this.RemoveOperator(op);
305      foreach (IOperator op in e.Items)
306        this.AddOperator(op);
307    }
308
309    private void RegisterOperatorEvents(IOperator op) {
310      op.Parameters.ItemsAdded += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
311      op.Parameters.ItemsRemoved += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
312      op.Parameters.ItemsReplaced += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
313      op.Parameters.CollectionReset += new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
314      op.NameChanged += new EventHandler(OperatorNameChanged);
315      op.ItemImageChanged += new EventHandler(OperatorItemImageChanged);
316      op.BreakpointChanged += new EventHandler(OperatorBreakpointChanged);
317    }
318
319    private void DeregisterOperatorEvents(IOperator op) {
320      op.Parameters.ItemsAdded -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
321      op.Parameters.ItemsRemoved -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
322      op.Parameters.ItemsReplaced -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
323      op.Parameters.CollectionReset -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
324      op.NameChanged -= new EventHandler(OperatorNameChanged);
325      op.ItemImageChanged -= new EventHandler(OperatorItemImageChanged);
326      op.BreakpointChanged -= new EventHandler(OperatorBreakpointChanged);
327    }
328    #endregion
329
330    #region parameter events
331    private void AddParameter(IOperator op, IParameter param) {
332      this.parameterOperatorMapping.Add(param, op);
333      IValueParameter opParam = param as IValueParameter;
334      if (opParam != null && typeof(IOperator).IsAssignableFrom(param.DataType)) {
335        this.RegisterOperatorParameterEvents(opParam);
336        IOperatorShapeInfo shapeInfoFrom = this.operatorShapeInfoMapping.GetByFirst(op);
337        shapeInfoFrom.AddConnector(param.Name);
338
339        if (opParam.Value != null) {
340          if (!this.operatorShapeInfoMapping.ContainsFirst((IOperator)opParam.Value))
341            this.AddOperator((IOperator)opParam.Value);
342          IOperatorShapeInfo shapeInfoTo = this.operatorShapeInfoMapping.GetByFirst((IOperator)opParam.Value);
343          this.connectionInfos.Add(new ConnectionInfo(shapeInfoFrom, param.Name, shapeInfoTo, OperatorShapeInfoFactory.PredecessorConnector));
344        }
345      } else
346        this.RegisterParameterEvents(param);
347    }
348
349    private void RemoveParameter(IOperator op, IParameter param) {
350      IValueParameter opParam = param as IValueParameter;
351      if (opParam != null && typeof(IOperator).IsAssignableFrom(param.DataType)) {
352        this.DeregisterOperatorParameterEvents(opParam);
353        IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
354        this.connectionInfos.RemoveWhere(c => c.From == shapeInfo && c.ConnectorFrom == param.Name);
355        this.connectionInfos.RemoveWhere(c => c.To == shapeInfo && c.ConnectorTo == param.Name);
356        shapeInfo.RemoveConnector(param.Name);
357      } else
358        this.DeregisterParameterEvents(param);
359
360      this.parameterOperatorMapping.Remove(param);
361    }
362
363    private void opParam_ValueChanged(object sender, EventArgs e) {
364      IValueParameter opParam = (IValueParameter)sender;
365      if (this.parameterOperatorMapping.ContainsKey(opParam)) {
366        IOperator op = this.parameterOperatorMapping[opParam];
367        IOperatorShapeInfo shapeInfoFrom = this.operatorShapeInfoMapping.GetByFirst(op);
368        KeyValuePair<IOperatorShapeInfo, string> connectionFrom = new KeyValuePair<IOperatorShapeInfo, string>(shapeInfoFrom, opParam.Name);
369
370        this.connectionInfos.RemoveWhere(c => c.From == shapeInfoFrom && c.ConnectorFrom == opParam.Name);
371        if (opParam.Value != null) {
372          if (!this.operatorShapeInfoMapping.ContainsFirst((IOperator)opParam.Value))
373            this.AddOperator((IOperator)opParam.Value);
374          IOperatorShapeInfo shapeInfoTo = this.operatorShapeInfoMapping.GetByFirst((IOperator)opParam.Value);
375          base.AddConnectionInfo(new ConnectionInfo(shapeInfoFrom, opParam.Name, shapeInfoTo, OperatorShapeInfoFactory.PredecessorConnector));
376        }
377      }
378    }
379
380    private void Parameters_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
381      IKeyedItemCollection<string, IParameter> parameterCollection = sender as IKeyedItemCollection<string, IParameter>;
382      IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
383      foreach (IParameter param in e.Items)
384        AddParameter(op, param);
385      this.UpdateParameterLabels(op);
386    }
387    private void Parameters_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
388      IKeyedItemCollection<string, IParameter> parameterCollection = sender as IKeyedItemCollection<string, IParameter>;
389      IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
390      foreach (IParameter param in e.Items)
391        RemoveParameter(op, param);
392      this.UpdateParameterLabels(op);
393    }
394    private void Parameters_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
395      IKeyedItemCollection<string, IParameter> parameterCollection = sender as IKeyedItemCollection<string, IParameter>;
396      IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
397      foreach (IParameter param in e.OldItems)
398        RemoveParameter(op, param);
399      foreach (IParameter param in e.Items)
400        AddParameter(op, param);
401      this.UpdateParameterLabels(op);
402    }
403    private void Parameters_CollectionReset(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
404      IKeyedItemCollection<string, IParameter> parameterCollection = sender as IKeyedItemCollection<string, IParameter>;
405      IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
406      foreach (IParameter param in e.OldItems)
407        RemoveParameter(op, param);
408      foreach (IParameter param in e.Items)
409        AddParameter(op, param);
410      this.UpdateParameterLabels(op);
411    }
412
413    private void RegisterOperatorParameterEvents(IValueParameter opParam) {
414      opParam.ValueChanged += new EventHandler(opParam_ValueChanged);
415    }
416    private void DeregisterOperatorParameterEvents(IValueParameter opParam) {
417      opParam.ValueChanged -= new EventHandler(opParam_ValueChanged);
418    }
419    private void RegisterParameterEvents(IParameter param) {
420      param.ToStringChanged += new EventHandler(param_ToStringChanged);
421      param.NameChanged += new EventHandler(param_NameChanged);
422    }
423    private void DeregisterParameterEvents(IParameter param) {
424      param.ToStringChanged -= new EventHandler(param_ToStringChanged);
425      param.NameChanged -= new EventHandler(param_NameChanged);
426    }
427
428    private void param_NameChanged(object sender, EventArgs e) {
429      IParameter param = (IParameter)sender;
430      IOperator op = this.parameterOperatorMapping[param];
431      this.UpdateParameterLabels(op);
432    }
433    private void param_ToStringChanged(object sender, EventArgs e) {
434      IParameter param = (IParameter)sender;
435      IOperator op = this.parameterOperatorMapping[param];
436      this.UpdateParameterLabels(op);
437    }
438
439    private void UpdateParameterLabels(IOperator op) {
440      IEnumerable<IParameter> parameters = op.Parameters.Where(p => !(p is IValueParameter && typeof(IOperator).IsAssignableFrom(p.DataType)));
441      IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
442      if (parameters.Count() > 0)
443        operatorShapeInfo.UpdateLabels(parameters.Select(p => p.ToString()));
444      else
445        operatorShapeInfo.UpdateLabels(new List<string>());
446    }
447    #endregion
448  }
449}
Note: See TracBrowser for help on using the repository browser.