Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Core.Views/3.3/OperatorTreeView.cs @ 3341

Last change on this file since 3341 was 3341, checked in by swagner, 14 years ago

Implemented reviewers' comments (#893).

File size: 19.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.ComponentModel;
25using System.Drawing;
26using System.Windows.Forms;
27using HeuristicLab.Collections;
28using HeuristicLab.MainForm;
29
30namespace HeuristicLab.Core.Views {
31  /// <summary>
32  /// The visual representation of an <see cref="OperatorGraph"/>.
33  /// </summary>
34  [View("Operator View (Successors)")]
35  [Content(typeof(IOperator), false)]
36  public sealed partial class OperatorTreeView : ItemView {
37    private Dictionary<IValueParameter<IOperator>, List<TreeNode>> opParamNodeTable;
38    private Dictionary<IOperator, List<TreeNode>> operatorNodeTable;
39    private Dictionary<IObservableKeyedCollection<string, IParameter>, IOperator> parametersOperatorTable;
40
41    /// <summary>
42    /// Gets or sets the operator graph to represent visually.
43    /// </summary>
44    /// <remarks>Uses property <see cref="ViewBase.Item"/> of base class <see cref="ViewBase"/>.
45    /// No own data storage present.</remarks>
46    public new IOperator Content {
47      get { return (IOperator)base.Content; }
48      set { base.Content = value; }
49    }
50
51    private IOperator selectedOperator;
52    public IOperator SelectedOperator {
53      get { return selectedOperator; }
54      private set {
55        if (value != selectedOperator) {
56          selectedOperator = value;
57          OnSelectedOperatorChanged();
58        }
59      }
60    }
61
62    /// <summary>
63    /// Initializes a new instance of <see cref="OperatorGraphView"/> with caption "Operator Graph".
64    /// </summary>
65    public OperatorTreeView() {
66      InitializeComponent();
67      graphTreeView.Sorted = true;
68      opParamNodeTable = new Dictionary<IValueParameter<IOperator>, List<TreeNode>>();
69      operatorNodeTable = new Dictionary<IOperator, List<TreeNode>>();
70      parametersOperatorTable = new Dictionary<IObservableKeyedCollection<string, IParameter>, IOperator>();
71      Caption = "Operator";
72    }
73    /// <summary>
74    /// Initializes a new instance of <see cref="OperatorGraphView"/>
75    /// with the given <paramref name="operatorGraph"/>.
76    /// </summary>
77    /// <remarks>Calls <see cref="OperatorGraphView()"/>.</remarks>
78    /// <param name="operatorGraph">The operator graph to represent visually.</param>
79    public OperatorTreeView(IOperator content)
80      : this() {
81      Content = content;
82    }
83
84    /// <summary>
85    /// Updates all controls with the latest data of the model.
86    /// </summary>
87    /// <remarks>Calls <see cref="ViewBase.UpdateControls"/> of base class <see cref="ViewBase"/>.</remarks>
88    protected override void OnContentChanged() {
89      base.OnContentChanged();
90      if (graphTreeView.Nodes.Count > 0)
91        RemoveTreeNode(graphTreeView.Nodes[0]);
92      graphTreeView.Enabled = false;
93      Caption = "Operator";
94      if (Content != null) {
95        Caption = Content.Name + " (" + Content.GetType().Name + ")";
96        TreeNode root = new TreeNode();
97        FillTreeNode(root, Content);
98        graphTreeView.Nodes.Add(root);
99        graphTreeView.Enabled = true;
100      }
101    }
102
103    public event EventHandler SelectedOperatorChanged;
104    private void OnSelectedOperatorChanged() {
105      if (SelectedOperatorChanged != null)
106        SelectedOperatorChanged(this, EventArgs.Empty);
107    }
108
109    #region TreeNode Management
110    private TreeNode CreateTreeNode(IValueParameter<IOperator> opParam) {
111      TreeNode node = new TreeNode();
112      node.Text = opParam.Name + ": ";
113      SetOperatorParameterTag(node, opParam);
114
115      if (!opParamNodeTable.ContainsKey(opParam)) {
116        opParamNodeTable.Add(opParam, new List<TreeNode>());
117        opParam.ValueChanged += new EventHandler(opParam_ValueChanged);
118      }
119      opParamNodeTable[opParam].Add(node);
120
121      FillTreeNode(node, opParam.Value);
122      return node;
123    }
124    private void FillTreeNode(TreeNode node, IOperator op) {
125      if (op == null) {
126        node.Text += "-";
127        node.ToolTipText = "";
128        graphTreeView.ImageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.Nothing);
129        node.ImageIndex = graphTreeView.ImageList.Images.Count - 1;
130        node.SelectedImageIndex = node.ImageIndex;
131        node.ForeColor = graphTreeView.ForeColor;
132      } else {
133        node.Text += op.Name;
134        node.ToolTipText = op.ItemName + ": " + op.ItemDescription;
135        graphTreeView.ImageList.Images.Add(op.ItemImage);
136        node.ImageIndex = graphTreeView.ImageList.Images.Count - 1;
137        node.SelectedImageIndex = node.ImageIndex;
138        SetOperatorTag(node, op);
139
140        if (!operatorNodeTable.ContainsKey(op)) {
141          operatorNodeTable.Add(op, new List<TreeNode>());
142          op.ItemImageChanged += new EventHandler(op_ItemImageChanged);
143          op.NameChanged += new EventHandler(op_NameChanged);
144          op.BreakpointChanged += new EventHandler(op_BreakpointChanged);
145          parametersOperatorTable.Add(op.Parameters, op);
146          op.Parameters.ItemsAdded += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
147          op.Parameters.ItemsRemoved += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
148          op.Parameters.ItemsReplaced += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
149          op.Parameters.CollectionReset += new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
150        }
151        operatorNodeTable[op].Add(node);
152
153        if (op.Breakpoint) node.ForeColor = Color.Red;
154        else node.ForeColor = graphTreeView.ForeColor;
155
156        foreach (IParameter param in op.Parameters) {
157          if (param is IValueParameter<IOperator>)
158            node.Nodes.Add(new TreeNode());
159        }
160        node.Collapse();
161      }
162    }
163    private void ClearTreeNode(TreeNode node) {
164      while (node.Nodes.Count > 0)
165        RemoveTreeNode(node.Nodes[0]);
166
167      if (node.ImageIndex != -1) {
168        int i = node.ImageIndex;
169        CorrectImageIndexes(graphTreeView.Nodes, i);
170        graphTreeView.ImageList.Images.RemoveAt(i);
171      }
172
173      IOperator op = GetOperatorTag(node);
174      if (op != null) {
175        operatorNodeTable[op].Remove(node);
176        if (operatorNodeTable[op].Count == 0) {
177          op.ItemImageChanged -= new EventHandler(op_ItemImageChanged);
178          op.NameChanged -= new EventHandler(op_NameChanged);
179          op.BreakpointChanged -= new EventHandler(op_BreakpointChanged);
180          operatorNodeTable.Remove(op);
181          op.Parameters.ItemsAdded -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
182          op.Parameters.ItemsRemoved -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
183          op.Parameters.ItemsReplaced -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
184          op.Parameters.CollectionReset -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
185          parametersOperatorTable.Remove(op.Parameters);
186        }
187      }
188      SetOperatorTag(node, null);
189    }
190    private void RemoveTreeNode(TreeNode node) {
191      ClearTreeNode(node);
192
193      IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
194      if (opParam != null) {
195        opParamNodeTable[opParam].Remove(node);
196        if (opParamNodeTable[opParam].Count == 0) {
197          opParam.ValueChanged -= new EventHandler(opParam_ValueChanged);
198          opParamNodeTable.Remove(opParam);
199        }
200      }
201      SetOperatorParameterTag(node, null);
202      node.Remove();
203    }
204    private void AddParameterNodes(IOperator op, IEnumerable<IParameter> parameters) {
205      foreach (IParameter param in parameters) {
206        IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
207        if (opParam != null) {
208          foreach (TreeNode node in operatorNodeTable[op])
209            node.Nodes.Add(CreateTreeNode(opParam));
210        }
211      }
212    }
213    private void RemoveParameterNodes(IEnumerable<IParameter> parameters) {
214      foreach (IParameter param in parameters) {
215        IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
216        if (opParam != null) {
217          while (opParamNodeTable.ContainsKey(opParam))
218            RemoveTreeNode(opParamNodeTable[opParam][0]);
219        }
220      }
221    }
222    #endregion
223
224    #region Parameter and Operator Events
225    private void opParam_ValueChanged(object sender, EventArgs e) {
226      if (InvokeRequired)
227        Invoke(new EventHandler(opParam_ValueChanged), sender, e);
228      else {
229        IValueParameter<IOperator> opParam = (IValueParameter<IOperator>)sender;
230        foreach (TreeNode node in opParamNodeTable[opParam].ToArray())
231          ClearTreeNode(node);
232        foreach (TreeNode node in opParamNodeTable[opParam]) {
233          node.Text = opParam.Name + ": ";
234          FillTreeNode(node, opParam.Value);
235        }
236      }
237    }
238    void op_ItemImageChanged(object sender, EventArgs e) {
239      if (InvokeRequired)
240        Invoke(new EventHandler(op_ItemImageChanged), sender, e);
241      else {
242        IOperator op = (IOperator)sender;
243        foreach (TreeNode node in operatorNodeTable[op]) {
244          int i = node.ImageIndex;
245          graphTreeView.ImageList.Images[i] = op.ItemImage;
246          node.ImageIndex = -1;
247          node.SelectedImageIndex = -1;
248          node.ImageIndex = i;
249          node.SelectedImageIndex = i;
250        }
251      }
252    }
253    private void op_NameChanged(object sender, EventArgs e) {
254      if (InvokeRequired)
255        Invoke(new EventHandler(op_NameChanged), sender, e);
256      else {
257        IOperator op = (IOperator)sender;
258        foreach (TreeNode node in operatorNodeTable[op]) {
259          IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
260          if (opParam == null)
261            node.Text = op.Name + " (" + op.ItemName + ")";
262          else
263            node.Text = opParam.Name + ": " + op.Name;
264        }
265      }
266    }
267    private void op_BreakpointChanged(object sender, EventArgs e) {
268      if (InvokeRequired)
269        Invoke(new EventHandler(op_BreakpointChanged), sender, e);
270      else {
271        IOperator op = (IOperator)sender;
272        foreach (TreeNode node in operatorNodeTable[op]) {
273          if (op.Breakpoint)
274            node.ForeColor = Color.Red;
275          else
276            node.ForeColor = graphTreeView.ForeColor;
277        }
278      }
279    }
280
281    private void Parameters_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
282      if (InvokeRequired)
283        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded), sender, e);
284      else {
285        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
286        IOperator op = parametersOperatorTable[coll];
287        AddParameterNodes(op, e.Items);
288      }
289    }
290    private void Parameters_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
291      if (InvokeRequired)
292        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved), sender, e);
293      else
294        RemoveParameterNodes(e.Items);
295    }
296    private void Parameters_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
297      if (InvokeRequired)
298        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced), sender, e);
299      else {
300        RemoveParameterNodes(e.Items);
301        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
302        IOperator op = parametersOperatorTable[coll];
303        AddParameterNodes(op, e.Items);
304      }
305    }
306    private void Parameters_CollectionReset(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
307      if (InvokeRequired)
308        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset), sender, e);
309      else {
310        RemoveParameterNodes(e.Items);
311        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
312        IOperator op = parametersOperatorTable[coll];
313        AddParameterNodes(op, e.Items);
314      }
315    }
316    #endregion
317
318    #region TreeView Events
319    private void graphTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
320      TreeNode node = e.Node;
321      if ((node.Nodes.Count > 0) && (node.Nodes[0].Tag == null)) {
322        node.Nodes.Clear();
323        IOperator op = GetOperatorTag(node);
324        foreach (IParameter param in op.Parameters) {
325          IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
326          if (opParam != null) node.Nodes.Add(CreateTreeNode(opParam));
327        }
328      }
329    }
330    private void graphTreeView_MouseDown(object sender, MouseEventArgs e) {
331      TreeNode node = graphTreeView.GetNodeAt(e.X, e.Y);
332      graphTreeView.SelectedNode = node;
333      graphTreeView.Refresh();
334    }
335    private void graphTreeView_KeyDown(object sender, KeyEventArgs e) {
336      if ((e.KeyCode == Keys.Delete) && (graphTreeView.SelectedNode != null)) {
337        IValueParameter<IOperator> opParam = GetOperatorParameterTag(graphTreeView.SelectedNode);
338        if (opParam != null) opParam.Value = null;
339      }
340    }
341    private void graphTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
342      SelectedOperator = graphTreeView.SelectedNode == null ? null : GetOperatorTag(graphTreeView.SelectedNode);
343    }
344    private void graphContextMenuStrip_Opening(object sender, CancelEventArgs e) {
345      viewToolStripMenuItem.Enabled = false;
346      breakpointToolStripMenuItem.Enabled = false;
347      breakpointToolStripMenuItem.Checked = false;
348      if (graphTreeView.SelectedNode != null) {
349        IOperator op = GetOperatorTag(graphTreeView.SelectedNode);
350        if (op != null) {
351          IView view = MainFormManager.CreateDefaultView(op);
352          if (view != null) {
353            viewToolStripMenuItem.Enabled = true;
354            viewToolStripMenuItem.Tag = view;
355          }
356          breakpointToolStripMenuItem.Enabled = true;
357          breakpointToolStripMenuItem.Tag = op;
358          if (op.Breakpoint)
359            breakpointToolStripMenuItem.Checked = true;
360        }
361      }
362    }
363    private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
364      TreeNode node = (TreeNode)e.Item;
365      IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
366      IOperator op = GetOperatorTag(node);
367      DataObject data = new DataObject();
368      data.SetData("Type", op.GetType());
369      data.SetData("Value", op);
370      if (opParam == null) {
371        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
372      } else {
373        DragDropEffects action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
374        if ((action & DragDropEffects.Move) == DragDropEffects.Move)
375          opParam.Value = null;
376      }
377    }
378    private void graphTreeView_DragEnterOver(object sender, DragEventArgs e) {
379      e.Effect = DragDropEffects.None;
380      Type type = e.Data.GetData("Type") as Type;
381      if ((type != null) && (typeof(IOperator).IsAssignableFrom(type))) {
382        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
383        if ((node != null) && !node.IsExpanded) node.Expand();
384        if ((node != null) && (GetOperatorParameterTag(node) != null)) {
385          if ((e.KeyState & 8) == 8) e.Effect = DragDropEffects.Copy;  // CTRL key
386          else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
387          else if ((e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link) e.Effect = DragDropEffects.Link;
388          else if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) e.Effect = DragDropEffects.Copy;
389          else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) e.Effect = DragDropEffects.Move;
390        }
391      }
392    }
393    private void graphTreeView_DragDrop(object sender, DragEventArgs e) {
394      if (e.Effect != DragDropEffects.None) {
395        IOperator op = e.Data.GetData("Value") as IOperator;
396        if ((e.Effect & DragDropEffects.Copy) == DragDropEffects.Copy) op = (IOperator)op.Clone();
397        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
398        IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
399        opParam.Value = op;
400      }
401    }
402    #endregion
403
404    #region Context Menu Events
405    private void viewToolStripMenuItem_Click(object sender, EventArgs e) {
406      IView view = ((ToolStripMenuItem)sender).Tag as IView;
407      if (view != null) view.Show();
408    }
409    private void breakpointToolStripMenuItem_Click(object sender, EventArgs e) {
410      IOperator op = (IOperator)breakpointToolStripMenuItem.Tag;
411      op.Breakpoint = breakpointToolStripMenuItem.Checked;
412    }
413    #endregion
414
415    #region Helpers
416    private class Tuple<T1, T2> {
417      public T1 Item1 { get; set; }
418      public T2 Item2 { get; set; }
419
420      public Tuple() {
421        Item1 = default(T1);
422        Item2 = default(T2);
423      }
424      public Tuple(T1 item1, T2 item2) {
425        Item1 = item1;
426        Item2 = item2;
427      }
428    }
429
430    private IValueParameter<IOperator> GetOperatorParameterTag(TreeNode node) {
431      if (node.Tag != null)
432        return ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item1;
433      else
434        return null;
435    }
436    private void SetOperatorParameterTag(TreeNode node, IValueParameter<IOperator> opParam) {
437      if (node.Tag == null)
438        node.Tag = new Tuple<IValueParameter<IOperator>, IOperator>(opParam, null);
439      else
440        ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item1 = opParam;
441    }
442    private IOperator GetOperatorTag(TreeNode node) {
443      if (node.Tag != null)
444        return ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item2;
445      else
446        return null;
447    }
448    private void SetOperatorTag(TreeNode node, IOperator op) {
449      if (node.Tag == null)
450        node.Tag = new Tuple<IValueParameter<IOperator>, IOperator>(null, op);
451      else
452        ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item2 = op;
453    }
454
455    private void CorrectImageIndexes(TreeNodeCollection nodes, int removedIndex) {
456      foreach (TreeNode node in nodes) {
457        if (node.ImageIndex > removedIndex) {
458          node.ImageIndex--;
459          node.SelectedImageIndex--;
460        }
461        CorrectImageIndexes(node.Nodes, removedIndex);
462      }
463    }
464    #endregion
465  }
466}
Note: See TracBrowser for help on using the repository browser.