Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Core.Views/3.3/TypeSelector.cs @ 12742

Last change on this file since 12742 was 12742, checked in by abeham, 9 years ago

#2208: merged 12722 to stable

  • Property svn:mergeinfo set to (toggle deleted branches)
    /trunk/sources/HeuristicLab.Core.Views/3.3/TypeSelector.csmergedeligible
    /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
File size: 19.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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      } if (node.Tag is Type) { // Type node
238        var text = node.Text;
239        if (searchTokens.Any(searchToken => !text.ToLower().Contains(searchToken))) {
240          var typeTag = (Type)node.Tag;
241          if (typeTag == SelectedType) {
242            SelectedType = null;
243            typesTreeView.SelectedNode = null;
244          }
245          return true;
246        }
247        return false;
248      }
249      throw new InvalidOperationException("Encountered neither a plugin nor a type node during tree traversal.");
250    }
251
252    public virtual object CreateInstanceOfSelectedType(params object[] args) {
253      if (SelectedType == null)
254        throw new InvalidOperationException("No type selected.");
255      else
256        return Activator.CreateInstance(SelectedType, args);
257    }
258
259    protected virtual void UpdateTypeParameters() {
260      typeParametersListView.Items.Clear();
261      if ((SelectedType == null) || !SelectedType.ContainsGenericParameters) {
262        typeParametersGroupBox.Enabled = false;
263        typeParametersSplitContainer.Panel2Collapsed = true;
264      } else {
265        typeParametersGroupBox.Enabled = true;
266        typeParametersSplitContainer.Panel2Collapsed = false;
267        setTypeParameterButton.Enabled = false;
268
269        foreach (Type param in SelectedType.GetGenericArguments()) {
270          if (param.IsGenericParameter) {
271            ListViewItem item = new ListViewItem();
272            item.Text = param.Name;
273
274            item.ToolTipText = "Constraints:";
275            Type[] constraints = param.GetGenericParameterConstraints();
276            if (constraints.Length == 0) {
277              item.ToolTipText += " none";
278            } else {
279              foreach (Type constraint in constraints)
280                item.ToolTipText += " " + constraint.GetPrettyName();
281            }
282
283            item.Tag = param;
284            typeParametersListView.Items.Add(item);
285          }
286        }
287        typeParametersListView.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
288      }
289    }
290
291    protected virtual void SetTypeParameter() {
292      if (typeSelectorDialog == null) {
293        typeSelectorDialog = new TypeSelectorDialog();
294        typeSelectorDialog.Caption = "Select Type of Generic Type Parameter";
295      }
296      Type param = typeParametersListView.SelectedItems[0].Tag as Type;
297      Type[] constraints = param.GetGenericParameterConstraints();
298      bool showNotInstantiableTypes = !param.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint);
299      typeSelectorDialog.TypeSelector.Configure(constraints, showNotInstantiableTypes, true, true);
300
301      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
302        Type selected = typeSelectorDialog.TypeSelector.SelectedType;
303        Type[] parameters = SelectedType.GetGenericArguments();
304        parameters[param.GenericParameterPosition] = selected;
305        SelectedType = SelectedType.GetGenericTypeDefinition().MakeGenericType(parameters);
306
307        typeParametersListView.SelectedItems[0].Text = param.Name + ": " + selected.GetPrettyName();
308        typeParametersListView.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
309      }
310    }
311
312    protected virtual void UpdateDescription() {
313      descriptionTextBox.Text = string.Empty;
314
315      if (typesTreeView.SelectedNode != null) {
316        IPluginDescription plugin = typesTreeView.SelectedNode.Tag as IPluginDescription;
317        if (plugin != null) {
318          StringBuilder sb = new StringBuilder();
319          sb.Append("Plugin: ").Append(plugin.Name).Append(Environment.NewLine);
320          sb.Append("Version: ").Append(plugin.Version.ToString()).Append(Environment.NewLine);
321          descriptionTextBox.Text = sb.ToString();
322        }
323        Type type = typesTreeView.SelectedNode.Tag as Type;
324        if (type != null) {
325          string description = ItemAttribute.GetDescription(type);
326          if (description != null)
327            descriptionTextBox.Text = description;
328        }
329      } else if (typesTreeView.Nodes.Count == 0) {
330        descriptionTextBox.Text = "No types found";
331      }
332    }
333
334    #region Events
335    public event EventHandler SelectedTypeChanged;
336    protected virtual void OnSelectedTypeChanged() {
337      if (SelectedTypeChanged != null)
338        SelectedTypeChanged(this, EventArgs.Empty);
339    }
340    #endregion
341
342    #region Control Events
343    protected virtual void searchTextBox_TextChanged(object sender, System.EventArgs e) {
344      Filter(searchTextBox.Text);
345    }
346
347    protected virtual void typesTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
348      if (typesTreeView.SelectedNode == null) SelectedType = null;
349      else SelectedType = typesTreeView.SelectedNode.Tag as Type;
350      UpdateTypeParameters();
351      UpdateDescription();
352    }
353    protected virtual void typesTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
354      TreeNode node = (TreeNode)e.Item;
355      Type type = node.Tag as Type;
356      if ((type != null) && (!type.IsInterface) && (!type.IsAbstract) && (!type.HasElementType) && (!type.ContainsGenericParameters)) {
357        object o = Activator.CreateInstance(type);
358        DataObject data = new DataObject();
359        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, o);
360        DoDragDrop(data, DragDropEffects.Copy);
361      }
362    }
363    protected virtual void typesTreeView_VisibleChanged(object sender, EventArgs e) {
364      if (Visible) SetTreeNodeVisibility();
365    }
366
367    protected virtual void typeParametersListView_SelectedIndexChanged(object sender, EventArgs e) {
368      setTypeParameterButton.Enabled = typeParametersListView.SelectedItems.Count == 1;
369    }
370    protected virtual void typeParametersListView_DoubleClick(object sender, EventArgs e) {
371      if (typeParametersListView.SelectedItems.Count == 1)
372        SetTypeParameter();
373    }
374
375    protected virtual void setTypeParameterButton_Click(object sender, EventArgs e) {
376      SetTypeParameter();
377    }
378    private void searchTextBox_KeyDown(object sender, KeyEventArgs e) {
379      if (typesTreeView.Nodes.Count == 0)
380        return;
381
382      if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) {
383        var selectedNode = typesTreeView.SelectedNode;
384
385        if (selectedNode == null) { // nothing selected => select first
386          if (e.KeyCode == Keys.Down) typesTreeView.SelectedNode = typesTreeView.Nodes.Count > 0 ? typesTreeView.Nodes[0] : null;
387        } else {
388          if (e.KeyCode == Keys.Down && selectedNode.NextVisibleNode != null)
389            typesTreeView.SelectedNode = selectedNode.NextVisibleNode;
390          if (e.KeyCode == Keys.Up && selectedNode.PrevVisibleNode != null)
391            typesTreeView.SelectedNode = selectedNode.PrevVisibleNode;
392        }
393        e.Handled = true;
394      }
395    }
396    private void clearSearchButton_Click(object sender, EventArgs e) {
397      searchTextBox.Text = string.Empty;
398      searchTextBox.Focus();
399    }
400
401    private TreeNode toolStripMenuNode = null;
402    private void typesTreeView_MouseDown(object sender, MouseEventArgs e) {
403      if (e.Button == MouseButtons.Right) {
404        Point coordinates = typesTreeView.PointToClient(Cursor.Position);
405        toolStripMenuNode = typesTreeView.GetNodeAt(coordinates);
406
407        if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left &&
408            coordinates.X <= toolStripMenuNode.Bounds.Right) {
409          typesTreeView.SelectedNode = toolStripMenuNode;
410
411          expandToolStripMenuItem.Enabled =
412            expandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
413          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
414        } else {
415          expandToolStripMenuItem.Enabled = expandToolStripMenuItem.Visible = false;
416          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = false;
417        }
418        expandAllToolStripMenuItem.Enabled =
419          expandAllToolStripMenuItem.Visible =
420            !typesTreeView.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x));
421        collapseAllToolStripMenuItem.Enabled =
422          collapseAllToolStripMenuItem.Visible = typesTreeView.Nodes.OfType<TreeNode>().Any(x => x.IsExpanded);
423        if (contextMenuStrip.Items.Cast<ToolStripMenuItem>().Any(item => item.Enabled))
424          contextMenuStrip.Show(Cursor.Position);
425      }
426    }
427    private bool TreeNodeIsFullyExpanded(TreeNode node) {
428      return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x)));
429    }
430    private void expandToolStripMenuItem_Click(object sender, EventArgs e) {
431      typesTreeView.BeginUpdate();
432      if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
433      typesTreeView.EndUpdate();
434    }
435    private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) {
436      typesTreeView.BeginUpdate();
437      typesTreeView.ExpandAll();
438      typesTreeView.EndUpdate();
439    }
440    private void collapseToolStripMenuItem_Click(object sender, EventArgs e) {
441      typesTreeView.BeginUpdate();
442      if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
443      typesTreeView.EndUpdate();
444    }
445    private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
446      typesTreeView.BeginUpdate();
447      typesTreeView.CollapseAll();
448      typesTreeView.EndUpdate();
449    }
450    #endregion
451
452    #region Helpers
453    private void RestoreSelectedNode(TreeNode selectedNode) {
454      if (selectedNode != null) {
455        foreach (TreeNode node in typesTreeView.Nodes) {
456          if (node.Text.Equals(selectedNode.Text)) typesTreeView.SelectedNode = node;
457          foreach (TreeNode child in node.Nodes) {
458            if ((child.Text.Equals(selectedNode.Text)) && (child.Tag == selectedNode.Tag))
459              typesTreeView.SelectedNode = child;
460          }
461        }
462        if (typesTreeView.SelectedNode == null) SelectedType = null;
463      }
464    }
465    private void SetTreeNodeVisibility() {
466      TreeNode selectedNode = typesTreeView.SelectedNode;
467      if (string.IsNullOrEmpty(currentSearchString) && (typesTreeView.Nodes.Count > 1)) {
468        typesTreeView.CollapseAll();
469        if (selectedNode != null) typesTreeView.SelectedNode = selectedNode;
470      } else {
471        typesTreeView.ExpandAll();
472      }
473      if (selectedNode != null) selectedNode.EnsureVisible();
474    }
475    #endregion
476  }
477}
Note: See TracBrowser for help on using the repository browser.