source: trunk/sources/HeuristicLab.Operators.Views.GraphVisualization/3.3/Model/GraphVisualizationInfo.cs @ 3017

Last change on this file since 3017 was 3017, checked in by epitzer, 12 years ago

Merge StorableClassType.Empty into StorableClassType.MarkedOnly and make it the default if not specified (#548)

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