Free cookie consent management tool by TermsFeed Policy Generator

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

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

Fixed resetting of node appearance when the value of an operator parameter is set to null (#927).

File size: 18.4 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        if (!graphTreeView.ImageList.Images.ContainsKey("Default"))
127          graphTreeView.ImageList.Images.Add("Default", HeuristicLab.Common.Resources.VS2008ImageLibrary.Method);
128
129        node.Text += "-";
130        node.ToolTipText = "";
131        node.ImageIndex = graphTreeView.ImageList.Images.IndexOfKey("Default"); ;
132        node.SelectedImageIndex = node.ImageIndex;
133        node.ForeColor = graphTreeView.ForeColor;
134      } else {
135        if (!graphTreeView.ImageList.Images.ContainsKey(op.GetType().FullName))
136          graphTreeView.ImageList.Images.Add(op.GetType().FullName, op.ItemImage);
137
138        node.Text += op.Name;
139        node.ToolTipText = op.ItemName + ": " + op.ItemDescription;
140        node.ImageIndex = graphTreeView.ImageList.Images.IndexOfKey(op.GetType().FullName);
141        node.SelectedImageIndex = node.ImageIndex;
142        SetOperatorTag(node, op);
143
144        if (!operatorNodeTable.ContainsKey(op)) {
145          operatorNodeTable.Add(op, new List<TreeNode>());
146          op.NameChanged += new EventHandler(op_NameChanged);
147          op.BreakpointChanged += new EventHandler(op_BreakpointChanged);
148          parametersOperatorTable.Add(op.Parameters, op);
149          op.Parameters.ItemsAdded += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
150          op.Parameters.ItemsRemoved += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
151          op.Parameters.ItemsReplaced += new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
152          op.Parameters.CollectionReset += new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
153        }
154        operatorNodeTable[op].Add(node);
155
156        if (op.Breakpoint) node.ForeColor = Color.Red;
157        else node.ForeColor = graphTreeView.ForeColor;
158
159        foreach (IParameter param in op.Parameters) {
160          if (param is IValueParameter<IOperator>)
161            node.Nodes.Add(new TreeNode());
162        }
163        node.Collapse();
164      }
165    }
166    private void ClearTreeNode(TreeNode node) {
167      while (node.Nodes.Count > 0)
168        RemoveTreeNode(node.Nodes[0]);
169
170      IOperator op = GetOperatorTag(node);
171      if (op != null) {
172        operatorNodeTable[op].Remove(node);
173        if (operatorNodeTable[op].Count == 0) {
174          op.NameChanged -= new EventHandler(op_NameChanged);
175          op.BreakpointChanged -= new EventHandler(op_BreakpointChanged);
176          operatorNodeTable.Remove(op);
177          op.Parameters.ItemsAdded -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded);
178          op.Parameters.ItemsRemoved -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved);
179          op.Parameters.ItemsReplaced -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced);
180          op.Parameters.CollectionReset -= new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset);
181          parametersOperatorTable.Remove(op.Parameters);
182        }
183      }
184      SetOperatorTag(node, null);
185    }
186    private void RemoveTreeNode(TreeNode node) {
187      ClearTreeNode(node);
188
189      IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
190      if (opParam != null) {
191        opParamNodeTable[opParam].Remove(node);
192        if (opParamNodeTable[opParam].Count == 0) {
193          opParam.ValueChanged -= new EventHandler(opParam_ValueChanged);
194          opParamNodeTable.Remove(opParam);
195        }
196      }
197      SetOperatorParameterTag(node, null);
198      node.Remove();
199    }
200    private void AddParameterNodes(IOperator op, IEnumerable<IParameter> parameters) {
201      foreach (IParameter param in parameters) {
202        IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
203        if (opParam != null) {
204          foreach (TreeNode node in operatorNodeTable[op])
205            node.Nodes.Add(CreateTreeNode(opParam));
206        }
207      }
208    }
209    private void RemoveParameterNodes(IEnumerable<IParameter> parameters) {
210      foreach (IParameter param in parameters) {
211        IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
212        if (opParam != null) {
213          while (opParamNodeTable.ContainsKey(opParam))
214            RemoveTreeNode(opParamNodeTable[opParam][0]);
215        }
216      }
217    }
218    #endregion
219
220    #region Parameter and Operator Events
221    private void opParam_ValueChanged(object sender, EventArgs e) {
222      if (InvokeRequired)
223        Invoke(new EventHandler(opParam_ValueChanged), sender, e);
224      else {
225        IValueParameter<IOperator> opParam = (IValueParameter<IOperator>)sender;
226        foreach (TreeNode node in opParamNodeTable[opParam].ToArray())
227          ClearTreeNode(node);
228        foreach (TreeNode node in opParamNodeTable[opParam]) {
229          node.Text = opParam.Name + ": ";
230          FillTreeNode(node, opParam.Value);
231        }
232      }
233    }
234    private void op_NameChanged(object sender, EventArgs e) {
235      if (InvokeRequired)
236        Invoke(new EventHandler(op_NameChanged), sender, e);
237      else {
238        IOperator op = (IOperator)sender;
239        foreach (TreeNode node in operatorNodeTable[op]) {
240          IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
241          if (opParam == null)
242            node.Text = op.Name + " (" + op.ItemName + ")";
243          else
244            node.Text = opParam.Name + ": " + op.Name;
245        }
246      }
247    }
248    private void op_BreakpointChanged(object sender, EventArgs e) {
249      if (InvokeRequired)
250        Invoke(new EventHandler(op_BreakpointChanged), sender, e);
251      else {
252        IOperator op = (IOperator)sender;
253        foreach (TreeNode node in operatorNodeTable[op]) {
254          if (op.Breakpoint)
255            node.ForeColor = Color.Red;
256          else
257            node.ForeColor = graphTreeView.ForeColor;
258        }
259      }
260    }
261
262    private void Parameters_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
263      if (InvokeRequired)
264        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsAdded), sender, e);
265      else {
266        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
267        IOperator op = parametersOperatorTable[coll];
268        AddParameterNodes(op, e.Items);
269      }
270    }
271    private void Parameters_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
272      if (InvokeRequired)
273        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsRemoved), sender, e);
274      else
275        RemoveParameterNodes(e.Items);
276    }
277    private void Parameters_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
278      if (InvokeRequired)
279        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_ItemsReplaced), sender, e);
280      else {
281        RemoveParameterNodes(e.Items);
282        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
283        IOperator op = parametersOperatorTable[coll];
284        AddParameterNodes(op, e.Items);
285      }
286    }
287    private void Parameters_CollectionReset(object sender, CollectionItemsChangedEventArgs<IParameter> e) {
288      if (InvokeRequired)
289        Invoke(new CollectionItemsChangedEventHandler<IParameter>(Parameters_CollectionReset), sender, e);
290      else {
291        RemoveParameterNodes(e.Items);
292        IObservableKeyedCollection<string, IParameter> coll = (IObservableKeyedCollection<string, IParameter>)sender;
293        IOperator op = parametersOperatorTable[coll];
294        AddParameterNodes(op, e.Items);
295      }
296    }
297    #endregion
298
299    #region TreeView Events
300    private void graphTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
301      TreeNode node = e.Node;
302      if ((node.Nodes.Count > 0) && (node.Nodes[0].Tag == null)) {
303        node.Nodes.Clear();
304        IOperator op = GetOperatorTag(node);
305        foreach (IParameter param in op.Parameters) {
306          IValueParameter<IOperator> opParam = param as IValueParameter<IOperator>;
307          if (opParam != null) node.Nodes.Add(CreateTreeNode(opParam));
308        }
309      }
310    }
311    private void graphTreeView_MouseDown(object sender, MouseEventArgs e) {
312      TreeNode node = graphTreeView.GetNodeAt(e.X, e.Y);
313      graphTreeView.SelectedNode = node;
314      graphTreeView.Refresh();
315    }
316    private void graphTreeView_KeyDown(object sender, KeyEventArgs e) {
317      if ((e.KeyCode == Keys.Delete) && (graphTreeView.SelectedNode != null)) {
318        IValueParameter<IOperator> opParam = GetOperatorParameterTag(graphTreeView.SelectedNode);
319        if (opParam != null) opParam.Value = null;
320      }
321    }
322    private void graphTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
323      SelectedOperator = graphTreeView.SelectedNode == null ? null : GetOperatorTag(graphTreeView.SelectedNode);
324    }
325    private void graphContextMenuStrip_Opening(object sender, CancelEventArgs e) {
326      viewToolStripMenuItem.Enabled = false;
327      breakpointToolStripMenuItem.Enabled = false;
328      breakpointToolStripMenuItem.Checked = false;
329      if (graphTreeView.SelectedNode != null) {
330        IOperator op = GetOperatorTag(graphTreeView.SelectedNode);
331        if (op != null) {
332          IView view = MainFormManager.CreateDefaultView(op);
333          if (view != null) {
334            viewToolStripMenuItem.Enabled = true;
335            viewToolStripMenuItem.Tag = view;
336          }
337          breakpointToolStripMenuItem.Enabled = true;
338          breakpointToolStripMenuItem.Tag = op;
339          if (op.Breakpoint)
340            breakpointToolStripMenuItem.Checked = true;
341        }
342      }
343    }
344    private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
345      TreeNode node = (TreeNode)e.Item;
346      IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
347      IOperator op = GetOperatorTag(node);
348      DataObject data = new DataObject();
349      data.SetData("Type", op.GetType());
350      data.SetData("Value", op);
351      if (opParam == null) {
352        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
353      } else {
354        DragDropEffects action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
355        if ((action & DragDropEffects.Move) == DragDropEffects.Move)
356          opParam.Value = null;
357      }
358    }
359    private void graphTreeView_DragEnterOver(object sender, DragEventArgs e) {
360      e.Effect = DragDropEffects.None;
361      Type type = e.Data.GetData("Type") as Type;
362      if ((type != null) && (typeof(IOperator).IsAssignableFrom(type))) {
363        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
364        if ((node != null) && !node.IsExpanded) node.Expand();
365        if ((node != null) && (GetOperatorParameterTag(node) != null)) {
366          if ((e.KeyState & 8) == 8) e.Effect = DragDropEffects.Copy;  // CTRL key
367          else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
368          else if ((e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link) e.Effect = DragDropEffects.Link;
369          else if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) e.Effect = DragDropEffects.Copy;
370          else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) e.Effect = DragDropEffects.Move;
371        }
372      }
373    }
374    private void graphTreeView_DragDrop(object sender, DragEventArgs e) {
375      if (e.Effect != DragDropEffects.None) {
376        IOperator op = e.Data.GetData("Value") as IOperator;
377        if ((e.Effect & DragDropEffects.Copy) == DragDropEffects.Copy) op = (IOperator)op.Clone();
378        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
379        IValueParameter<IOperator> opParam = GetOperatorParameterTag(node);
380        opParam.Value = op;
381      }
382    }
383    #endregion
384
385    #region Context Menu Events
386    private void viewToolStripMenuItem_Click(object sender, EventArgs e) {
387      IView view = ((ToolStripMenuItem)sender).Tag as IView;
388      if (view != null) view.Show();
389    }
390    private void breakpointToolStripMenuItem_Click(object sender, EventArgs e) {
391      IOperator op = (IOperator)breakpointToolStripMenuItem.Tag;
392      op.Breakpoint = breakpointToolStripMenuItem.Checked;
393    }
394    #endregion
395
396    #region Helpers
397    private class Tuple<T1, T2> {
398      public T1 Item1 { get; set; }
399      public T2 Item2 { get; set; }
400
401      public Tuple() {
402        Item1 = default(T1);
403        Item2 = default(T2);
404      }
405      public Tuple(T1 item1, T2 item2) {
406        Item1 = item1;
407        Item2 = item2;
408      }
409    }
410
411    private IValueParameter<IOperator> GetOperatorParameterTag(TreeNode node) {
412      if (node.Tag != null)
413        return ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item1;
414      else
415        return null;
416    }
417    private void SetOperatorParameterTag(TreeNode node, IValueParameter<IOperator> opParam) {
418      if (node.Tag == null)
419        node.Tag = new Tuple<IValueParameter<IOperator>, IOperator>(opParam, null);
420      else
421        ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item1 = opParam;
422    }
423    private IOperator GetOperatorTag(TreeNode node) {
424      if (node.Tag != null)
425        return ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item2;
426      else
427        return null;
428    }
429    private void SetOperatorTag(TreeNode node, IOperator op) {
430      if (node.Tag == null)
431        node.Tag = new Tuple<IValueParameter<IOperator>, IOperator>(null, op);
432      else
433        ((Tuple<IValueParameter<IOperator>, IOperator>)node.Tag).Item2 = op;
434    }
435    #endregion
436  }
437}
Note: See TracBrowser for help on using the repository browser.