Free cookie consent management tool by TermsFeed Policy Generator

source: branches/ProblemRefactoring/HeuristicLab.Core.Views/3.3/TypeSelector.cs @ 13435

Last change on this file since 13435 was 13422, checked in by mkommend, 9 years ago

#2521: Adapted type discovery and type selector to allow the creation of generic programmable problems.

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