Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 2936 was 2917, checked in by swagner, 15 years ago

Operator architecture refactoring (#95)

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