Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3764 was 3764, checked in by mkommend, 14 years ago

adapted view captions (ticket #893)

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