Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Core.Views/3.3/TypeSelector.cs @ 17226

Last change on this file since 17226 was 17226, checked in by mkommend, 5 years ago

#2521: Merged trunk changes into problem refactoring branch.

  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/2839_HiveProjectManagement/HeuristicLab.Core.Views/3.3/TypeSelector.csmergedeligible
    /stable/HeuristicLab.Core.Views/3.3/TypeSelector.csmergedeligible
    /trunk/HeuristicLab.Core.Views/3.3/TypeSelector.csmergedeligible
    /branches/2520_PersistenceReintegration/HeuristicLab.Core.Views/3.3/TypeSelector.cs16451-16564
    /branches/2892_LR-prediction-intervals/HeuristicLab.Core.Views/3.3/TypeSelector.cs15743-16388
    /branches/2915-AbsoluteSymbol/HeuristicLab.Core.Views/3.3/TypeSelector.cs15943-16355
    /branches/2947_ConfigurableIndexedDataTable/HeuristicLab.Core.Views/3.3/TypeSelector.cs16148-16526
    /branches/2965_CancelablePersistence/HeuristicLab.Core.Views/3.3/TypeSelector.cs16321-16439
    /branches/Async/HeuristicLab.Core.Views/3.3/TypeSelector.cs13329-15286
    /branches/CloningRefactoring/HeuristicLab.Core.Views/3.3/TypeSelector.cs4656-4721
    /branches/DataAnalysis Refactoring/HeuristicLab.Core.Views/3.3/TypeSelector.cs5471-5808
    /branches/DataAnalysis SolutionEnsembles/HeuristicLab.Core.Views/3.3/TypeSelector.cs5815-6180
    /branches/DataAnalysis/HeuristicLab.Core.Views/3.3/TypeSelector.cs4458-4459,​4462,​4464
    /branches/DataPreprocessing/HeuristicLab.Core.Views/3.3/TypeSelector.cs10085-11101
    /branches/GP.Grammar.Editor/HeuristicLab.Core.Views/3.3/TypeSelector.cs6335
    /branches/GP.Symbols (TimeLag, Diff, Integral)/HeuristicLab.Core.Views/3.3/TypeSelector.cs5060
    /branches/HeuristicLab.DatasetRefactor/sources/HeuristicLab.Core.Views/3.3/TypeSelector.cs11570-12508
    /branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Core.Views/3.3/TypeSelector.cs11130-12721
    /branches/NET40/sources/HeuristicLab.Core.Views/3.3/TypeSelector.cs5138-5162
    /branches/ParallelEngine/HeuristicLab.Core.Views/3.3/TypeSelector.cs5175-5192
    /branches/QAPAlgorithms/HeuristicLab.Core.Views/3.3/TypeSelector.cs6350-6627
    /branches/Restructure trunk solution/HeuristicLab.Core.Views/3.3/TypeSelector.cs6828
    /branches/SuccessProgressAnalysis/HeuristicLab.Core.Views/3.3/TypeSelector.cs5370-5682
    /branches/Trunk/HeuristicLab.Core.Views/3.3/TypeSelector.cs6829-6865
    /branches/VNS/HeuristicLab.Core.Views/3.3/TypeSelector.cs5594-5752
    /branches/histogram/HeuristicLab.Core.Views/3.3/TypeSelector.cs5959-6341
    /branches/symbreg-factors-2650/HeuristicLab.Core.Views/3.3/TypeSelector.cs14232-14825
    /trunk/sources/HeuristicLab.Core.Views/3.3/TypeSelector.cs13331-15681
File size: 20.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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.Drawing;
25using System.Linq;
26using System.Reflection;
27using System.Text;
28using System.Windows.Forms;
29using HeuristicLab.Common;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Core.Views {
33  public partial class TypeSelector : UserControl {
34    protected List<TreeNode> treeNodes;
35    protected string currentSearchString;
36    protected TypeSelectorDialog typeSelectorDialog;
37
38    protected IEnumerable<Type> baseTypes;
39    public IEnumerable<Type> BaseTypes {
40      get { return baseTypes; }
41    }
42    protected bool showNotInstantiableTypes;
43    public bool ShowNotInstantiableTypes {
44      get { return showNotInstantiableTypes; }
45    }
46    protected bool showGenericTypes;
47    public bool ShowGenericTypes {
48      get { return showGenericTypes; }
49    }
50    public string Caption {
51      get { return typesGroupBox.Text; }
52      set {
53        if (InvokeRequired)
54          Invoke(new Action<string>(delegate(string s) { Caption = s; }), value);
55        else
56          typesGroupBox.Text = value;
57      }
58    }
59    public TreeView TypesTreeView {
60      get { return typesTreeView; }
61    }
62    protected Type selectedType;
63    public Type SelectedType {
64      get { return selectedType; }
65      private set {
66        if (value != selectedType) {
67          selectedType = value;
68          OnSelectedTypeChanged();
69        }
70      }
71    }
72
73    public TypeSelector() {
74      InitializeComponent();
75      treeNodes = new List<TreeNode>();
76      currentSearchString = string.Empty;
77      selectedType = null;
78    }
79
80    protected override void Dispose(bool disposing) {
81      if (disposing) {
82        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
83        if (components != null) components.Dispose();
84      }
85      base.Dispose(disposing);
86    }
87
88    public virtual void Configure(Type baseType, bool showNotInstantiableTypes, bool showGenericTypes) {
89      Configure(baseType, showNotInstantiableTypes, showGenericTypes, (t) => true);
90    }
91
92    public virtual void Configure(Type baseType, bool showNotInstantiableTypes, bool showGenericTypes, Func<Type, bool> typeCondition) {
93      Configure(new List<Type>() { baseType }, showNotInstantiableTypes, showGenericTypes, true, typeCondition);
94    }
95
96    public virtual void Configure(IEnumerable<Type> baseTypes, bool showNotInstantiableTypes, bool showGenericTypes, bool assignableToAllTypes) {
97      Configure(baseTypes, showNotInstantiableTypes, showGenericTypes, assignableToAllTypes, (t) => { return true; });
98    }
99
100    public virtual void Configure(IEnumerable<Type> baseTypes, bool showNotInstantiableTypes, bool showGenericTypes, bool assignableToAllTypes, Func<Type, bool> typeCondition) {
101      if (baseTypes == null) throw new ArgumentNullException();
102      if (InvokeRequired)
103        Invoke(new Action<IEnumerable<Type>, bool, bool, bool, Func<Type, bool>>(Configure), baseTypes, showNotInstantiableTypes, showGenericTypes, assignableToAllTypes, typeCondition);
104      else {
105        this.baseTypes = baseTypes;
106        this.showNotInstantiableTypes = showNotInstantiableTypes;
107        this.showGenericTypes = showGenericTypes;
108        bool selectedTypeFound = false;
109
110        typeParametersSplitContainer.Panel2Collapsed = !showGenericTypes;
111
112        TreeNode selectedNode = typesTreeView.SelectedNode;
113        typesTreeView.Nodes.Clear();
114        treeNodes.Clear();
115
116        imageList.Images.Clear();
117        imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class);      // default icon
118        imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Namespace);  // plugins
119        imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Interface);  // interfaces
120        imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Template);   // generic types
121        // additional dictionary for image indexes as imageList.ContainsKey and imageList.IndexOfKey are very slow!
122        var imageNames = new Dictionary<string, int>();
123
124        var plugins = from p in ApplicationManager.Manager.Plugins
125                      orderby p.Name, p.Version ascending
126                      select p;
127        foreach (IPluginDescription plugin in plugins) {
128          TreeNode pluginNode = new TreeNode();
129          pluginNode.Text = string.Format("{0} {1}.{2}", plugin.Name, plugin.Version.Major, plugin.Version.Minor);
130          pluginNode.ImageIndex = 1;
131          pluginNode.SelectedImageIndex = pluginNode.ImageIndex;
132          pluginNode.Tag = plugin;
133
134          var types = from t in ApplicationManager.Manager.GetTypes(BaseTypes, plugin, !ShowNotInstantiableTypes, ShowGenericTypes, assignableToAllTypes)
135                      where typeCondition(t)
136                      orderby t.Name ascending
137                      select t;
138          foreach (Type type in types) {
139            bool valid = (ShowNotInstantiableTypes || type.GetConstructor(Type.EmptyTypes) != null); //check for public default ctor
140            if (valid) {
141              TreeNode typeNode = new TreeNode();
142              string name = ItemAttribute.GetName(type);
143              typeNode.Text = name != null ? name : type.GetPrettyName();
144              typeNode.ImageIndex = 0;
145              if (type.IsInterface) typeNode.ImageIndex = 2;
146              else if (type.ContainsGenericParameters) typeNode.ImageIndex = 3;
147              else if (imageNames.ContainsKey(type.FullName)) typeNode.ImageIndex = imageNames[type.FullName];
148              else {
149                var image = ItemAttribute.GetImage(type);
150                if (image != null) {
151                  imageList.Images.Add(image);
152                  typeNode.ImageIndex = imageList.Images.Count - 1;
153                  imageNames.Add(type.FullName, imageList.Images.Count - 1);
154                }
155              }
156              typeNode.SelectedImageIndex = typeNode.ImageIndex;
157              typeNode.Tag = type;
158              pluginNode.Nodes.Add(typeNode);
159              if (type.Equals(selectedType)) selectedTypeFound = true;
160            }
161          }
162          if (pluginNode.Nodes.Count > 0)
163            treeNodes.Add(pluginNode);
164        }
165        if (!selectedTypeFound) SelectedType = null;
166        foreach (TreeNode node in treeNodes)
167          typesTreeView.Nodes.Add((TreeNode)node.Clone());
168        RestoreSelectedNode(selectedNode);
169        Filter(searchTextBox.Text);
170
171        UpdateTypeParameters();
172      }
173    }
174
175    public virtual void Filter(string searchString) {
176      if (InvokeRequired)
177        Invoke(new Action<string>(Filter), searchString);
178      else {
179        searchString = searchString.ToLower();
180        TreeNode selectedNode = typesTreeView.SelectedNode;
181
182        if (!searchString.Contains(currentSearchString)) {
183          typesTreeView.BeginUpdate();
184          // expand search -> restore all tree nodes
185          typesTreeView.Nodes.Clear();
186          foreach (TreeNode node in treeNodes)
187            typesTreeView.Nodes.Add((TreeNode)node.Clone());
188          typesTreeView.EndUpdate();
189        }
190
191        // remove nodes
192        typesTreeView.BeginUpdate();
193        var searchTokens = searchString.Split(' ');
194        int i = 0;
195        while (i < typesTreeView.Nodes.Count) {
196          var node = typesTreeView.Nodes[i];
197          bool remove = FilterNode(node, searchTokens);
198          if (remove)
199            typesTreeView.Nodes.RemoveAt(i);
200          else i++;
201        }
202        typesTreeView.EndUpdate();
203        currentSearchString = searchString;
204
205        // select first item
206        typesTreeView.BeginUpdate();
207        var firstNode = typesTreeView.Nodes.Count > 0 ? typesTreeView.Nodes[0] : null;
208        while (firstNode != null && !(firstNode.Tag is Type))
209          firstNode = firstNode.NextVisibleNode;
210        if (firstNode != null)
211          typesTreeView.SelectedNode = firstNode;
212
213        if (typesTreeView.Nodes.Count == 0) {
214          SelectedType = null;
215          typesTreeView.Enabled = false;
216        } else {
217          SetTreeNodeVisibility();
218          typesTreeView.Enabled = true;
219        }
220        typesTreeView.EndUpdate();
221
222        RestoreSelectedNode(selectedNode);
223        UpdateDescription();
224      }
225    }
226
227    private bool FilterNode(TreeNode node, string[] searchTokens) {
228      if (node.Tag is IPluginDescription) { // Plugin node
229        int i = 0;
230        while (i < node.Nodes.Count) {
231          bool remove = FilterNode(node.Nodes[i], searchTokens);
232          if (remove)
233            node.Nodes.RemoveAt(i);
234          else i++;
235        }
236        return node.Nodes.Count == 0;
237      }
238      if (node.Tag is Type) { // Type node
239        var text = node.Text;
240        if (searchTokens.Any(searchToken => !text.ToLower().Contains(searchToken))) {
241          var typeTag = (Type)node.Tag;
242          if (typeTag == SelectedType) {
243            SelectedType = null;
244            typesTreeView.SelectedNode = null;
245          }
246          return true;
247        }
248        return false;
249      }
250      throw new InvalidOperationException("Encountered neither a plugin nor a type node during tree traversal.");
251    }
252
253    public virtual object CreateInstanceOfSelectedType(params object[] args) {
254      if (SelectedType == null)
255        throw new InvalidOperationException("No type selected.");
256      else
257        return Activator.CreateInstance(SelectedType, args);
258    }
259
260    private Type[] genericTypeArguments = null;
261    protected virtual void UpdateTypeParameters() {
262      typeParametersListView.Items.Clear();
263      if ((SelectedType == null) || !SelectedType.ContainsGenericParameters) {
264        typeParametersGroupBox.Enabled = false;
265        typeParametersSplitContainer.Panel2Collapsed = true;
266        genericTypeArguments = null;
267      } else {
268        typeParametersGroupBox.Enabled = true;
269        typeParametersSplitContainer.Panel2Collapsed = false;
270        setTypeParameterButton.Enabled = false;
271
272
273        genericTypeArguments = SelectedType.GetGenericArguments();
274
275        foreach (Type param in genericTypeArguments) {
276          if (param.IsGenericParameter) {
277            ListViewItem item = new ListViewItem();
278            item.Text = param.Name;
279
280            item.ToolTipText = "Constraints:";
281            Type[] constraints = param.GetGenericParameterConstraints();
282            if (constraints.Length == 0) {
283              item.ToolTipText += " none";
284            } else {
285              foreach (Type constraint in constraints)
286                item.ToolTipText += " " + constraint.GetPrettyName();
287            }
288
289            item.Tag = param;
290            typeParametersListView.Items.Add(item);
291          }
292        }
293        typeParametersListView.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
294      }
295    }
296
297    protected virtual void SetTypeParameter() {
298      if (typeSelectorDialog == null) {
299        typeSelectorDialog = new TypeSelectorDialog();
300        typeSelectorDialog.Caption = "Select Type of Generic Type Parameter";
301      }
302      Type param = typeParametersListView.SelectedItems[0].Tag as Type;
303      Type[] constraints = param.GetGenericParameterConstraints();
304      bool showNotInstantiableTypes = !param.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint);
305      typeSelectorDialog.TypeSelector.Configure(constraints, showNotInstantiableTypes, true, true);
306
307      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
308        Type selected = typeSelectorDialog.TypeSelector.SelectedType;
309        genericTypeArguments[param.GenericParameterPosition] = selected;
310        if (genericTypeArguments.All(p => !p.IsGenericParameter))
311          SelectedType = SelectedType.GetGenericTypeDefinition().MakeGenericType(genericTypeArguments);
312
313        typeParametersListView.SelectedItems[0].Text = param.Name + ": " + selected.GetPrettyName();
314        typeParametersListView.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
315      }
316    }
317
318    protected virtual void UpdateDescription() {
319      descriptionTextBox.Text = string.Empty;
320
321      if (typesTreeView.SelectedNode != null) {
322        IPluginDescription plugin = typesTreeView.SelectedNode.Tag as IPluginDescription;
323        if (plugin != null) {
324          StringBuilder sb = new StringBuilder();
325          sb.Append("Plugin: ").Append(plugin.Name).Append(Environment.NewLine);
326          sb.Append("Version: ").Append(plugin.Version.ToString()).Append(Environment.NewLine);
327          descriptionTextBox.Text = sb.ToString();
328        }
329        Type type = typesTreeView.SelectedNode.Tag as Type;
330        if (type != null) {
331          string description = ItemAttribute.GetDescription(type);
332          if (description != null)
333            descriptionTextBox.Text = description;
334        }
335      } else if (typesTreeView.Nodes.Count == 0) {
336        descriptionTextBox.Text = "No types found";
337      }
338    }
339
340    #region Events
341    public event EventHandler SelectedTypeChanged;
342    protected virtual void OnSelectedTypeChanged() {
343      if (SelectedTypeChanged != null)
344        SelectedTypeChanged(this, EventArgs.Empty);
345    }
346    #endregion
347
348    #region Control Events
349    protected virtual void searchTextBox_TextChanged(object sender, System.EventArgs e) {
350      Filter(searchTextBox.Text);
351    }
352
353    protected virtual void typesTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
354      if (typesTreeView.SelectedNode == null) SelectedType = null;
355      else SelectedType = typesTreeView.SelectedNode.Tag as Type;
356      UpdateTypeParameters();
357      UpdateDescription();
358    }
359    protected virtual void typesTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
360      TreeNode node = (TreeNode)e.Item;
361      Type type = node.Tag as Type;
362      if ((type != null) && (!type.IsInterface) && (!type.IsAbstract) && (!type.HasElementType) && (!type.ContainsGenericParameters)) {
363        object o = Activator.CreateInstance(type);
364        DataObject data = new DataObject();
365        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, o);
366        DoDragDrop(data, DragDropEffects.Copy);
367      }
368    }
369    protected virtual void typesTreeView_VisibleChanged(object sender, EventArgs e) {
370      if (Visible) SetTreeNodeVisibility();
371    }
372
373    protected virtual void typeParametersListView_SelectedIndexChanged(object sender, EventArgs e) {
374      setTypeParameterButton.Enabled = typeParametersListView.SelectedItems.Count == 1;
375    }
376    protected virtual void typeParametersListView_DoubleClick(object sender, EventArgs e) {
377      if (typeParametersListView.SelectedItems.Count == 1)
378        SetTypeParameter();
379    }
380
381    protected virtual void setTypeParameterButton_Click(object sender, EventArgs e) {
382      SetTypeParameter();
383    }
384    private void searchTextBox_KeyDown(object sender, KeyEventArgs e) {
385      if (typesTreeView.Nodes.Count == 0)
386        return;
387
388      if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) {
389        var selectedNode = typesTreeView.SelectedNode;
390
391        if (selectedNode == null) { // nothing selected => select first
392          if (e.KeyCode == Keys.Down) typesTreeView.SelectedNode = typesTreeView.Nodes.Count > 0 ? typesTreeView.Nodes[0] : null;
393        } else {
394          if (e.KeyCode == Keys.Down && selectedNode.NextVisibleNode != null)
395            typesTreeView.SelectedNode = selectedNode.NextVisibleNode;
396          if (e.KeyCode == Keys.Up && selectedNode.PrevVisibleNode != null)
397            typesTreeView.SelectedNode = selectedNode.PrevVisibleNode;
398        }
399        e.Handled = true;
400      }
401    }
402    private void clearSearchButton_Click(object sender, EventArgs e) {
403      searchTextBox.Text = string.Empty;
404      searchTextBox.Focus();
405    }
406
407    private TreeNode toolStripMenuNode = null;
408    private void typesTreeView_MouseDown(object sender, MouseEventArgs e) {
409      if (e.Button == MouseButtons.Right) {
410        Point coordinates = typesTreeView.PointToClient(Cursor.Position);
411        toolStripMenuNode = typesTreeView.GetNodeAt(coordinates);
412
413        if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left &&
414            coordinates.X <= toolStripMenuNode.Bounds.Right) {
415          typesTreeView.SelectedNode = toolStripMenuNode;
416
417          expandToolStripMenuItem.Enabled =
418            expandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
419          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
420        } else {
421          expandToolStripMenuItem.Enabled = expandToolStripMenuItem.Visible = false;
422          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = false;
423        }
424        expandAllToolStripMenuItem.Enabled =
425          expandAllToolStripMenuItem.Visible =
426            !typesTreeView.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x));
427        collapseAllToolStripMenuItem.Enabled =
428          collapseAllToolStripMenuItem.Visible = typesTreeView.Nodes.OfType<TreeNode>().Any(x => x.IsExpanded);
429        if (contextMenuStrip.Items.Cast<ToolStripMenuItem>().Any(item => item.Enabled))
430          contextMenuStrip.Show(Cursor.Position);
431      }
432    }
433    private bool TreeNodeIsFullyExpanded(TreeNode node) {
434      return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x)));
435    }
436    private void expandToolStripMenuItem_Click(object sender, EventArgs e) {
437      typesTreeView.BeginUpdate();
438      if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
439      typesTreeView.EndUpdate();
440    }
441    private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) {
442      typesTreeView.BeginUpdate();
443      typesTreeView.ExpandAll();
444      typesTreeView.EndUpdate();
445    }
446    private void collapseToolStripMenuItem_Click(object sender, EventArgs e) {
447      typesTreeView.BeginUpdate();
448      if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
449      typesTreeView.EndUpdate();
450    }
451    private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
452      typesTreeView.BeginUpdate();
453      typesTreeView.CollapseAll();
454      typesTreeView.EndUpdate();
455    }
456    #endregion
457
458    #region Helpers
459    private void RestoreSelectedNode(TreeNode selectedNode) {
460      if (selectedNode != null) {
461        foreach (TreeNode node in typesTreeView.Nodes) {
462          if (node.Text.Equals(selectedNode.Text)) typesTreeView.SelectedNode = node;
463          foreach (TreeNode child in node.Nodes) {
464            if ((child.Text.Equals(selectedNode.Text)) && (child.Tag == selectedNode.Tag))
465              typesTreeView.SelectedNode = child;
466          }
467        }
468        if (typesTreeView.SelectedNode == null) SelectedType = null;
469      }
470    }
471    private void SetTreeNodeVisibility() {
472      TreeNode selectedNode = typesTreeView.SelectedNode;
473      if (string.IsNullOrEmpty(currentSearchString) && (typesTreeView.Nodes.Count > 1)) {
474        typesTreeView.CollapseAll();
475        if (selectedNode != null) typesTreeView.SelectedNode = selectedNode;
476      } else {
477        typesTreeView.ExpandAll();
478      }
479      if (selectedNode != null) selectedNode.EnsureVisible();
480    }
481    #endregion
482  }
483}
Note: See TracBrowser for help on using the repository browser.