Free cookie consent management tool by TermsFeed Policy Generator

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

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

Implemented review comments of mkommend (#1112)

File size: 18.6 KB
RevLine 
[2655]1#region License Information
2/* HeuristicLab
[5445]3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[2655]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;
[3407]26using System.Linq;
[2655]27using System.Windows.Forms;
[2818]28using HeuristicLab.Collections;
[2655]29using HeuristicLab.MainForm;
30
31namespace HeuristicLab.Core.Views {
[2917]32  [View("Operator View (Successors)")]
[2655]33  [Content(typeof(IOperator), false)]
[2676]34  public sealed partial class OperatorTreeView : ItemView {
[3407]35    private Dictionary<IValueParameter, List<TreeNode>> opParamNodeTable;
[2655]36    private Dictionary<IOperator, List<TreeNode>> operatorNodeTable;
[3393]37    private Dictionary<IKeyedItemCollection<string, IParameter>, IOperator> parametersOperatorTable;
[2655]38
[2713]39    public new IOperator Content {
40      get { return (IOperator)base.Content; }
41      set { base.Content = value; }
[2655]42    }
43
[2949]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
[2655]55    public OperatorTreeView() {
56      InitializeComponent();
57      graphTreeView.Sorted = true;
[3407]58      opParamNodeTable = new Dictionary<IValueParameter, List<TreeNode>>();
[2655]59      operatorNodeTable = new Dictionary<IOperator, List<TreeNode>>();
[3393]60      parametersOperatorTable = new Dictionary<IKeyedItemCollection<string, IParameter>, IOperator>();
[2655]61    }
62
[5237]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
[2713]74    protected override void OnContentChanged() {
75      base.OnContentChanged();
[2655]76      if (graphTreeView.Nodes.Count > 0)
77        RemoveTreeNode(graphTreeView.Nodes[0]);
[2713]78      if (Content != null) {
[2655]79        TreeNode root = new TreeNode();
[2713]80        FillTreeNode(root, Content);
[2655]81        graphTreeView.Nodes.Add(root);
82      }
83    }
84
[3904]85    protected override void SetEnabledStateOfControls() {
86      base.SetEnabledStateOfControls();
[3362]87      graphTreeView.Enabled = Content != null;
88    }
89
[2949]90    public event EventHandler SelectedOperatorChanged;
91    private void OnSelectedOperatorChanged() {
92      if (SelectedOperatorChanged != null)
93        SelectedOperatorChanged(this, EventArgs.Empty);
94    }
95
[2655]96    #region TreeNode Management
[3407]97    private TreeNode CreateTreeNode(IValueParameter opParam) {
[2655]98      TreeNode node = new TreeNode();
[2756]99      node.Text = opParam.Name + ": ";
100      SetOperatorParameterTag(node, opParam);
[2655]101
[2756]102      if (!opParamNodeTable.ContainsKey(opParam)) {
103        opParamNodeTable.Add(opParam, new List<TreeNode>());
104        opParam.ValueChanged += new EventHandler(opParam_ValueChanged);
[2655]105      }
[2756]106      opParamNodeTable[opParam].Add(node);
[2655]107
[3407]108      FillTreeNode(node, (IOperator)opParam.Value);
[2655]109      return node;
110    }
111    private void FillTreeNode(TreeNode node, IOperator op) {
[3135]112      if (op == null) {
113        node.Text += "-";
114        node.ToolTipText = "";
[5287]115        graphTreeView.ImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Nothing);
[3341]116        node.ImageIndex = graphTreeView.ImageList.Images.Count - 1;
[3135]117        node.SelectedImageIndex = node.ImageIndex;
118        node.ForeColor = graphTreeView.ForeColor;
119      } else {
120        node.Text += op.Name;
121        node.ToolTipText = op.ItemName + ": " + op.ItemDescription;
[3341]122        graphTreeView.ImageList.Images.Add(op.ItemImage);
123        node.ImageIndex = graphTreeView.ImageList.Images.Count - 1;
[3135]124        node.SelectedImageIndex = node.ImageIndex;
125        SetOperatorTag(node, op);
[2655]126
[3135]127        if (!operatorNodeTable.ContainsKey(op)) {
128          operatorNodeTable.Add(op, new List<TreeNode>());
[3341]129          op.ItemImageChanged += new EventHandler(op_ItemImageChanged);
[3135]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);
[2655]139
[3135]140        if (op.Breakpoint) node.ForeColor = Color.Red;
141        else node.ForeColor = graphTreeView.ForeColor;
142
[3407]143        foreach (IValueParameter param in op.Parameters.OfType<IValueParameter>()) {
144          if (typeof(IOperator).IsAssignableFrom(param.DataType))
[3135]145            node.Nodes.Add(new TreeNode());
146        }
147        node.Collapse();
[2655]148      }
149    }
150    private void ClearTreeNode(TreeNode node) {
151      while (node.Nodes.Count > 0)
152        RemoveTreeNode(node.Nodes[0]);
153
[3341]154      if (node.ImageIndex != -1) {
155        int i = node.ImageIndex;
156        CorrectImageIndexes(graphTreeView.Nodes, i);
157        graphTreeView.ImageList.Images.RemoveAt(i);
158      }
159
[2655]160      IOperator op = GetOperatorTag(node);
161      if (op != null) {
162        operatorNodeTable[op].Remove(node);
163        if (operatorNodeTable[op].Count == 0) {
[3341]164          op.ItemImageChanged -= new EventHandler(op_ItemImageChanged);
[2655]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
[3407]180      IValueParameter opParam = GetOperatorParameterTag(node);
[2655]181      if (opParam != null) {
[2756]182        opParamNodeTable[opParam].Remove(node);
183        if (opParamNodeTable[opParam].Count == 0) {
184          opParam.ValueChanged -= new EventHandler(opParam_ValueChanged);
185          opParamNodeTable.Remove(opParam);
[2655]186        }
187      }
188      SetOperatorParameterTag(node, null);
189      node.Remove();
190    }
191    private void AddParameterNodes(IOperator op, IEnumerable<IParameter> parameters) {
[3407]192      foreach (IValueParameter param in parameters.OfType<IValueParameter>()) {
193        if (typeof(IOperator).IsAssignableFrom(param.DataType)) {
[2655]194          foreach (TreeNode node in operatorNodeTable[op])
[3407]195            node.Nodes.Add(CreateTreeNode(param));
[2655]196        }
197      }
198    }
199    private void RemoveParameterNodes(IEnumerable<IParameter> parameters) {
[3407]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]);
[2655]204        }
205      }
206    }
207    #endregion
208
209    #region Parameter and Operator Events
[2756]210    private void opParam_ValueChanged(object sender, EventArgs e) {
[2655]211      if (InvokeRequired)
[2756]212        Invoke(new EventHandler(opParam_ValueChanged), sender, e);
[2655]213      else {
[3407]214        IValueParameter opParam = (IValueParameter)sender;
[3729]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          }
[2655]222        }
223      }
224    }
[3341]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    }
[2655]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]) {
[3407]246          IValueParameter opParam = GetOperatorParameterTag(node);
[2655]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 {
[3393]272        IKeyedItemCollection<string, IParameter> coll = (IKeyedItemCollection<string, IParameter>)sender;
[2655]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);
[3393]288        IKeyedItemCollection<string, IParameter> coll = (IKeyedItemCollection<string, IParameter>)sender;
[2655]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);
[3393]298        IKeyedItemCollection<string, IParameter> coll = (IKeyedItemCollection<string, IParameter>)sender;
[2655]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);
[3407]311        foreach (IValueParameter param in op.Parameters.OfType<IValueParameter>()) {
312          if (typeof(IOperator).IsAssignableFrom(param.DataType)) node.Nodes.Add(CreateTreeNode(param));
[2655]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) {
[3362]322      if (!ReadOnly && (e.KeyCode == Keys.Delete) && (graphTreeView.SelectedNode != null)) {
[3407]323        IValueParameter opParam = GetOperatorParameterTag(graphTreeView.SelectedNode);
[2655]324        if (opParam != null) opParam.Value = null;
325      }
326    }
[2949]327    private void graphTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
328      SelectedOperator = graphTreeView.SelectedNode == null ? null : GetOperatorTag(graphTreeView.SelectedNode);
329    }
[2655]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) {
[3557]337          Type viewType = MainFormManager.GetDefaultViewType(op.GetType());
338          if (viewType != null) {
[2655]339            viewToolStripMenuItem.Enabled = true;
[3557]340            viewToolStripMenuItem.Tag = op;
[2655]341          }
[5224]342          breakpointToolStripMenuItem.Enabled = !Locked;
[2655]343          breakpointToolStripMenuItem.Tag = op;
344          if (op.Breakpoint)
345            breakpointToolStripMenuItem.Checked = true;
346        }
347      }
348    }
349    private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
[3432]350      if (!Locked) {
351        TreeNode node = (TreeNode)e.Item;
352        IValueParameter opParam = GetOperatorParameterTag(node);
353        IOperator op = GetOperatorTag(node);
354        DataObject data = new DataObject();
[5837]355        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, op);
[3432]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        }
[2655]363      }
364    }
365    private void graphTreeView_DragEnterOver(object sender, DragEventArgs e) {
366      e.Effect = DragDropEffects.None;
[5837]367      if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IOperator)) {
[2655]368        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
[2694]369        if ((node != null) && !node.IsExpanded) node.Expand();
[2655]370        if ((node != null) && (GetOperatorParameterTag(node) != null)) {
371          if ((e.KeyState & 8) == 8) e.Effect = DragDropEffects.Copy;  // CTRL key
[2694]372          else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
[5744]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;
[2655]376        }
377      }
378    }
379    private void graphTreeView_DragDrop(object sender, DragEventArgs e) {
380      if (e.Effect != DragDropEffects.None) {
[5837]381        IOperator op = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IOperator;
[5744]382        if (e.Effect.HasFlag(DragDropEffects.Copy)) op = (IOperator)op.Clone();
[2655]383        TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y)));
[3407]384        IValueParameter opParam = GetOperatorParameterTag(node);
[2655]385        opParam.Value = op;
386      }
387    }
388    #endregion
389
390    #region Context Menu Events
391    private void viewToolStripMenuItem_Click(object sender, EventArgs e) {
[3557]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      }
[2655]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
[3407]420    private IValueParameter GetOperatorParameterTag(TreeNode node) {
[2655]421      if (node.Tag != null)
[3407]422        return ((Tuple<IValueParameter, IOperator>)node.Tag).Item1;
[2655]423      else
424        return null;
425    }
[3407]426    private void SetOperatorParameterTag(TreeNode node, IValueParameter opParam) {
[2655]427      if (node.Tag == null)
[3407]428        node.Tag = new Tuple<IValueParameter, IOperator>(opParam, null);
[2655]429      else
[3407]430        ((Tuple<IValueParameter, IOperator>)node.Tag).Item1 = opParam;
[2655]431    }
432    private IOperator GetOperatorTag(TreeNode node) {
433      if (node.Tag != null)
[3407]434        return ((Tuple<IValueParameter, IOperator>)node.Tag).Item2;
[2655]435      else
436        return null;
437    }
438    private void SetOperatorTag(TreeNode node, IOperator op) {
439      if (node.Tag == null)
[3407]440        node.Tag = new Tuple<IValueParameter, IOperator>(null, op);
[2655]441      else
[3407]442        ((Tuple<IValueParameter, IOperator>)node.Tag).Item2 = op;
[2655]443    }
[3341]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    }
[2655]454    #endregion
455  }
456}
Note: See TracBrowser for help on using the repository browser.