Free cookie consent management tool by TermsFeed Policy Generator

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

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

Added SetEnabledStateOfControls as protected virtual method in !View. Therefore the overloading of OnReadOnlyChanged and OnLockedChanged got obsolete in most views, because the method got called in the !View respectively ContentView. (ticket #1021)

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