Free cookie consent management tool by TermsFeed Policy Generator

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

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

Implemented review comments of mkommend (#1112)

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