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

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

Restricted types of child operators in MultiOperator (#979)

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