Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
04/13/15 16:58:58 (10 years ago)
Author:
mkommend
Message:

#2025: Merged changes from the NewItemDialog branch into the trunk.

Location:
trunk/sources/HeuristicLab.Optimizer
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Optimizer

    • Property svn:mergeinfo set to (toggle deleted branches)
      /branches/HLScript/HeuristicLab.Optimizermergedeligible
      /branches/NewItemDialog/HeuristicLab.Optimizermergedeligible
      /stable/HeuristicLab.Optimizermergedeligible
      /branches/1721-RandomForestPersistence/HeuristicLab.Optimizer10321-10322
      /branches/Algorithms.GradientDescent/HeuristicLab.Optimizer5516-5520
      /branches/Benchmarking/sources/HeuristicLab.Optimizer6917-7005
      /branches/CloningRefactoring/HeuristicLab.Optimizer4656-4721
      /branches/CodeEditor/HeuristicLab.Optimizer11700-11806
      /branches/DataAnalysis Refactoring/HeuristicLab.Optimizer5471-5808
      /branches/DataAnalysis SolutionEnsembles/HeuristicLab.Optimizer5815-6180
      /branches/DataAnalysis/HeuristicLab.Optimizer4458-4459,​4462,​4464
      /branches/DataPreprocessing/HeuristicLab.Optimizer10085-11101
      /branches/GP.Grammar.Editor/HeuristicLab.Optimizer6284-6795
      /branches/GP.Symbols (TimeLag, Diff, Integral)/HeuristicLab.Optimizer5060
      /branches/HeuristicLab.Problems.DataAnalysis.Trading/HeuristicLab.Optimizer6123-9799
      /branches/LogResidualEvaluator/HeuristicLab.Optimizer10202-10483
      /branches/NET40/sources/HeuristicLab.Optimizer5138-5162
      /branches/NSGA-II Changes/HeuristicLab.Optimizer12033-12122
      /branches/ParallelEngine/HeuristicLab.Optimizer5175-5192
      /branches/ProblemInstancesRegressionAndClassification/HeuristicLab.Optimizer7568-7810
      /branches/QAPAlgorithms/HeuristicLab.Optimizer6350-6627
      /branches/Restructure trunk solution/HeuristicLab.Optimizer6828
      /branches/RuntimeOptimizer/HeuristicLab.Optimizer8943-9078
      /branches/ScatterSearch (trunk integration)/HeuristicLab.Optimizer7787-8333
      /branches/SlaveShutdown/HeuristicLab.Optimizer8944-8956
      /branches/SpectralKernelForGaussianProcesses/HeuristicLab.Optimizer10204-10479
      /branches/SuccessProgressAnalysis/HeuristicLab.Optimizer5370-5682
      /branches/Trunk/HeuristicLab.Optimizer6829-6865
      /branches/UnloadJobs/HeuristicLab.Optimizer9168-9215
      /branches/VNS/HeuristicLab.Optimizer5594-5752
      /branches/histogram/HeuristicLab.Optimizer5959-6341
  • trunk/sources/HeuristicLab.Optimizer/3.3/NewItemDialog.cs

    r12012 r12305  
    2121
    2222using System;
     23using System.Collections;
     24using System.Collections.Generic;
    2325using System.Drawing;
    2426using System.Linq;
     
    2931namespace HeuristicLab.Optimizer {
    3032  internal partial class NewItemDialog : Form {
    31     private bool initialized;
     33    private bool isInitialized;
     34
     35    private readonly List<TreeNode> treeNodes;
     36    private string currentSearchString;
     37
     38    private Type selectedType;
     39    public Type SelectedType {
     40      get { return selectedType; }
     41      private set {
     42        if (value != selectedType) {
     43          selectedType = value;
     44          OnSelectedTypeChanged();
     45        }
     46      }
     47    }
    3248
    3349    private IItem item;
     
    3753
    3854    public NewItemDialog() {
    39       initialized = false;
     55      InitializeComponent();
     56      treeNodes = new List<TreeNode>();
     57      currentSearchString = string.Empty;
    4058      item = null;
    41       InitializeComponent();
     59      SelectedTypeChanged += this_SelectedTypeChanged;
    4260    }
    4361
    4462    private void NewItemDialog_Load(object sender, EventArgs e) {
    45       if (!initialized) {
    46         var categories = from t in ApplicationManager.Manager.GetTypes(typeof(IItem))
    47                          where CreatableAttribute.IsCreatable(t)
    48                          orderby CreatableAttribute.GetCategory(t), ItemAttribute.GetName(t), ItemAttribute.GetVersion(t) ascending
    49                          group t by CreatableAttribute.GetCategory(t) into c
    50                          select c;
    51 
    52         itemsListView.SmallImageList = new ImageList();
    53         itemsListView.SmallImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class);  // default icon
    54         foreach (var category in categories) {
    55           ListViewGroup group = new ListViewGroup(category.Key);
    56           itemsListView.Groups.Add(group);
    57           foreach (var creatable in category) {
    58             string name = ItemAttribute.GetName(creatable);
    59             string version = ItemAttribute.GetVersion(creatable).ToString();
    60             string description = ItemAttribute.GetDescription(creatable);
    61             ListViewItem item = new ListViewItem(new string[] { name, version, description }, group);
    62             item.ImageIndex = 0;
    63             Image image = ItemAttribute.GetImage(creatable);
    64             if (image != null) {
    65               itemsListView.SmallImageList.Images.Add(image);
    66               item.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
    67             }
    68             item.Tag = creatable;
    69             itemsListView.Items.Add(item);
     63      if (isInitialized) return;
     64
     65      var categories =
     66        from type in ApplicationManager.Manager.GetTypes(typeof(IItem))
     67        let category = CreatableAttribute.GetCategory(type)
     68        let name = ItemAttribute.GetName(type)
     69        let priority = CreatableAttribute.GetPriority(type)
     70        let version = ItemAttribute.GetVersion(type)
     71        where CreatableAttribute.IsCreatable(type)
     72        orderby category, priority, name, version ascending
     73        group type by category into categoryGroup
     74        select categoryGroup;
     75
     76      var rootNode = CreateCategoryTree(categories);
     77      CreateItemNodes(rootNode, categories);
     78
     79      foreach (TreeNode topNode in rootNode.Nodes)
     80        treeNodes.Add(topNode);
     81      foreach (var node in treeNodes)
     82        typesTreeView.Nodes.Add((TreeNode)node.Clone());
     83
     84      typesTreeView.TreeViewNodeSorter = new ItemTreeNodeComparer();
     85      typesTreeView.Sort();
     86
     87      isInitialized = true;
     88    }
     89
     90    private TreeNode CreateCategoryTree(IEnumerable<IGrouping<string, Type>> categories) {
     91      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class);      // default icon
     92      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Namespace);  // plugins
     93
     94      var rootNode = new TreeNode();
     95
     96      foreach (var category in categories) {
     97        var fullName = category.Key;
     98        var tokens = fullName.Split('#');
     99        var name = tokens.Last();
     100        var parents = tokens.Take(tokens.Length - 1);
     101
     102        var categoryNode = new TreeNode(name, imageIndex: 1, selectedImageIndex: 1) {
     103          Name = fullName,
     104          Tag = fullName
     105        };
     106
     107        var parentNode = FindOrCreateParentNode(rootNode, parents);
     108        if (parentNode != null)
     109          parentNode.Nodes.Add(categoryNode);
     110        else
     111          rootNode.Nodes.Add(categoryNode);
     112      }
     113
     114      return rootNode;
     115    }
     116    private TreeNode FindOrCreateParentNode(TreeNode node, IEnumerable<string> parentCategories) {
     117      TreeNode parentNode = null;
     118      string fullName = null;
     119      foreach (string parentCategory in parentCategories) {
     120        fullName = fullName == null ? parentCategory : fullName + "#" + parentCategory;
     121        parentNode = node.Nodes.Find(fullName, searchAllChildren: false).SingleOrDefault();
     122        if (parentNode == null) {
     123          parentNode = new TreeNode(parentCategory, imageIndex: 1, selectedImageIndex: 1) {
     124            Name = fullName,
     125            Tag = fullName
     126          };
     127          node.Nodes.Add(parentNode);
     128        }
     129        node = parentNode;
     130      }
     131      return parentNode;
     132    }
     133    private void CreateItemNodes(TreeNode node, IEnumerable<IGrouping<string, Type>> categories) {
     134      foreach (var category in categories) {
     135        var categoryNode = node.Nodes.Find(category.Key, searchAllChildren: true).Single();
     136        foreach (var creatable in category) {
     137          var itemNode = CreateItemNode(creatable);
     138          itemNode.Name = itemNode.Name + ":" + category.Key;
     139          categoryNode.Nodes.Add(itemNode);
     140        }
     141      }
     142    }
     143    private TreeNode CreateItemNode(Type creatable) {
     144      string name = ItemAttribute.GetName(creatable);
     145
     146      var itemNode = new TreeNode(name) {
     147        ImageIndex = 0,
     148        Tag = creatable,
     149        Name = name
     150      };
     151
     152      var image = ItemAttribute.GetImage(creatable);
     153      if (image != null) {
     154        imageList.Images.Add(image);
     155        itemNode.ImageIndex = imageList.Images.Count - 1;
     156      }
     157      itemNode.SelectedImageIndex = itemNode.ImageIndex;
     158
     159      return itemNode;
     160    }
     161
     162    private void NewItemDialog_Shown(object sender, EventArgs e) {
     163      searchTextBox.Text = string.Empty;
     164      searchTextBox.Focus();
     165      SelectedType = null;
     166      typesTreeView.SelectedNode = null;
     167      typesTreeView.CollapseAll();
     168      UpdateDescription();
     169    }
     170
     171    public virtual void Filter(string searchString) {
     172      if (InvokeRequired) {
     173        Invoke(new Action<string>(Filter), searchString);
     174      } else {
     175        searchString = searchString.ToLower();
     176
     177        if (!searchString.Contains(currentSearchString)) {
     178          typesTreeView.BeginUpdate();
     179          // expand search -> restore all tree nodes
     180          var selectedNode = typesTreeView.SelectedNode;
     181          typesTreeView.Nodes.Clear();
     182          foreach (TreeNode node in treeNodes)
     183            typesTreeView.Nodes.Add((TreeNode)node.Clone());
     184          RestoreSelectedNode(selectedNode);
     185          typesTreeView.EndUpdate();
     186        }
     187
     188        // remove nodes
     189        typesTreeView.BeginUpdate();
     190        var searchTokens = searchString.Split(' ');
     191
     192        int i = 0;
     193        while (i < typesTreeView.Nodes.Count) {
     194          var categoryNode = typesTreeView.Nodes[i];
     195          bool remove = FilterNode(categoryNode, searchTokens);
     196          if (remove)
     197            typesTreeView.Nodes.RemoveAt(i);
     198          else i++;
     199        }
     200        typesTreeView.EndUpdate();
     201        currentSearchString = searchString;
     202
     203        // select first item
     204        var firstNode = FirstVisibleNode;
     205        while (firstNode != null && !(firstNode.Tag is Type))
     206          firstNode = firstNode.NextVisibleNode;
     207        if (firstNode != null)
     208          typesTreeView.SelectedNode = firstNode;
     209
     210        if (typesTreeView.Nodes.Count == 0) {
     211          SelectedType = null;
     212          typesTreeView.Enabled = false;
     213        } else {
     214          SetTreeNodeVisibility();
     215          typesTreeView.Enabled = true;
     216        }
     217        UpdateDescription();
     218      }
     219    }
     220
     221    private bool FilterNode(TreeNode node, string[] searchTokens) {
     222      if (node.Tag is string) { // Category node
     223        int i = 0;
     224        while (i < node.Nodes.Count) {
     225          bool remove = FilterNode(node.Nodes[i], searchTokens);
     226          if (remove)
     227            node.Nodes.RemoveAt(i);
     228          else i++;
     229        }
     230        return node.Nodes.Count == 0;
     231      } if (node.Tag is Type) { // Type node
     232        var text = node.Text;
     233        if (searchTokens.Any(searchToken => !text.ToLower().Contains(searchToken))) {
     234          var typeTag = (Type)node.Tag;
     235          if (typeTag == SelectedType) {
     236            SelectedType = null;
     237            typesTreeView.SelectedNode = null;
    70238          }
    71         }
    72         for (int i = 0; i < itemsListView.Columns.Count; i++)
    73           itemsListView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
    74         initialized = true;
    75       }
    76     }
    77 
    78     private void NewItemDialog_Shown(object sender, EventArgs e) {
    79       item = null;
    80     }
    81 
    82     private void itemTypesListView_SelectedIndexChanged(object sender, EventArgs e) {
    83       okButton.Enabled = itemsListView.SelectedItems.Count == 1;
    84     }
     239          return true;
     240        }
     241        return false;
     242      }
     243      throw new InvalidOperationException("Encountered neither a category nor a creatable node during tree traversal.");
     244    }
     245
     246    protected virtual void UpdateDescription() {
     247      itemDescriptionTextBox.Text = string.Empty;
     248      pluginDescriptionTextBox.Text = string.Empty;
     249      pluginTextBox.Text = string.Empty;
     250      versionTextBox.Text = string.Empty;
     251
     252      if (typesTreeView.SelectedNode != null) {
     253        string category = typesTreeView.SelectedNode.Tag as string;
     254        if (category != null) {
     255          itemDescriptionTextBox.Text = category;
     256        }
     257        Type type = typesTreeView.SelectedNode.Tag as Type;
     258        if (type != null) {
     259          string description = ItemAttribute.GetDescription(type);
     260          var version = ItemAttribute.GetVersion(type);
     261          var plugin = ApplicationManager.Manager.GetDeclaringPlugin(type);
     262          if (description != null)
     263            itemDescriptionTextBox.Text = description;
     264          if (plugin != null) {
     265            pluginTextBox.Text = plugin.Name;
     266            pluginDescriptionTextBox.Text = plugin.Description;
     267          }
     268          if (version != null)
     269            versionTextBox.Text = version.ToString();
     270        }
     271      } else if (typesTreeView.Nodes.Count == 0) {
     272        itemDescriptionTextBox.Text = "No types found";
     273      }
     274    }
     275
     276    #region Events
     277    public event EventHandler SelectedTypeChanged;
     278    protected virtual void OnSelectedTypeChanged() {
     279      if (SelectedTypeChanged != null)
     280        SelectedTypeChanged(this, EventArgs.Empty);
     281    }
     282    #endregion
     283
     284    #region Control Events
     285    protected virtual void searchTextBox_TextChanged(object sender, EventArgs e) {
     286      Filter(searchTextBox.Text);
     287    }
     288
     289    protected virtual void itemsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
     290      if (typesTreeView.SelectedNode == null) SelectedType = null;
     291      else SelectedType = typesTreeView.SelectedNode.Tag as Type;
     292      UpdateDescription();
     293    }
     294
     295    protected virtual void itemsTreeView_VisibleChanged(object sender, EventArgs e) {
     296      if (Visible) SetTreeNodeVisibility();
     297    }
     298    #endregion
     299
     300    #region Helpers
     301    private void RestoreSelectedNode(TreeNode selectedNode) {
     302      if (selectedNode != null) {
     303        var node = typesTreeView.Nodes.Find(selectedNode.Name, searchAllChildren: true).SingleOrDefault();
     304        typesTreeView.SelectedNode = node;
     305        if (typesTreeView.SelectedNode == null) SelectedType = null;
     306      }
     307    }
     308    private void SetTreeNodeVisibility() {
     309      TreeNode selectedNode = typesTreeView.SelectedNode;
     310      if (string.IsNullOrEmpty(currentSearchString) && (typesTreeView.Nodes.Count > 1)) {
     311        typesTreeView.CollapseAll();
     312        if (selectedNode != null) typesTreeView.SelectedNode = selectedNode;
     313      } else {
     314        typesTreeView.ExpandAll();
     315      }
     316      if (selectedNode != null) selectedNode.EnsureVisible();
     317    }
     318    #endregion
    85319
    86320    private void okButton_Click(object sender, EventArgs e) {
    87       if (itemsListView.SelectedItems.Count == 1) {
    88         item = (IItem)Activator.CreateInstance((Type)itemsListView.SelectedItems[0].Tag);
     321      if (SelectedType != null) {
     322        item = (IItem)Activator.CreateInstance(SelectedType);
    89323        DialogResult = DialogResult.OK;
    90324        Close();
    91325      }
    92326    }
    93     private void itemTypesListView_DoubleClick(object sender, EventArgs e) {
    94       if (itemsListView.SelectedItems.Count == 1) {
    95         item = (IItem)Activator.CreateInstance((Type)itemsListView.SelectedItems[0].Tag);
     327    private void itemTreeView_DoubleClick(object sender, EventArgs e) {
     328      if (SelectedType != null) {
     329        item = (IItem)Activator.CreateInstance(SelectedType);
    96330        DialogResult = DialogResult.OK;
    97331        Close();
    98332      }
    99333    }
     334    private void this_SelectedTypeChanged(object sender, EventArgs e) {
     335      okButton.Enabled = SelectedType != null;
     336    }
     337
     338    private void expandAllButton_Click(object sender, EventArgs e) {
     339      typesTreeView.ExpandAll();
     340    }
     341    private void collapseAllButton_Click(object sender, EventArgs e) {
     342      typesTreeView.CollapseAll();
     343    }
     344
     345    private TreeNode toolStripMenuNode = null;
     346    private void typesTreeView_MouseDown(object sender, MouseEventArgs e) {
     347      if (e.Button == MouseButtons.Right) {
     348        Point coordinates = typesTreeView.PointToClient(Cursor.Position);
     349        toolStripMenuNode = typesTreeView.GetNodeAt(coordinates);
     350
     351        if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left &&
     352            coordinates.X <= toolStripMenuNode.Bounds.Right) {
     353          typesTreeView.SelectedNode = toolStripMenuNode;
     354
     355          expandToolStripMenuItem.Enabled =
     356            expandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
     357          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
     358        } else {
     359          expandToolStripMenuItem.Enabled = expandToolStripMenuItem.Visible = false;
     360          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = false;
     361        }
     362        expandAllToolStripMenuItem.Enabled =
     363          expandAllToolStripMenuItem.Visible =
     364            !typesTreeView.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x));
     365        collapseAllToolStripMenuItem.Enabled =
     366          collapseAllToolStripMenuItem.Visible = typesTreeView.Nodes.OfType<TreeNode>().Any(x => x.IsExpanded);
     367        if (contextMenuStrip.Items.Cast<ToolStripMenuItem>().Any(item => item.Enabled))
     368          contextMenuStrip.Show(Cursor.Position);
     369      }
     370    }
     371    private bool TreeNodeIsFullyExpanded(TreeNode node) {
     372      return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x)));
     373    }
     374
     375    private void expandToolStripMenuItem_Click(object sender, EventArgs e) {
     376      if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
     377    }
     378    private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) {
     379      typesTreeView.ExpandAll();
     380    }
     381    private void collapseToolStripMenuItem_Click(object sender, EventArgs e) {
     382      if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
     383    }
     384    private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
     385      typesTreeView.CollapseAll();
     386    }
     387
     388    private void clearSearchButton_Click(object sender, EventArgs e) {
     389      searchTextBox.Text = string.Empty;
     390      searchTextBox.Focus();
     391    }
     392
     393    private void searchTextBox_KeyDown(object sender, KeyEventArgs e) {
     394      if (typesTreeView.Nodes.Count == 0)
     395        return;
     396
     397      if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) {
     398        var selectedNode = typesTreeView.SelectedNode;
     399
     400        if (selectedNode == null) { // nothing selected => select first or last
     401          if (e.KeyCode == Keys.Down) typesTreeView.SelectedNode = FirstVisibleNode;
     402          if (e.KeyCode == Keys.Up) typesTreeView.SelectedNode = LastVisibleNode;
     403        } else {
     404          if (e.KeyCode == Keys.Down)
     405            typesTreeView.SelectedNode = selectedNode.NextVisibleNode ?? FirstVisibleNode; // select next or cycle to first
     406          if (e.KeyCode == Keys.Up)
     407            typesTreeView.SelectedNode = selectedNode.PrevVisibleNode ?? LastVisibleNode; // select prev or cycle to last
     408        }
     409        e.Handled = true;
     410      }
     411    }
     412
     413    private TreeNode FirstVisibleNode {
     414      get {
     415        return typesTreeView.Nodes.Count > 0 ? typesTreeView.Nodes[0] : null;
     416      }
     417    }
     418    private TreeNode LastVisibleNode {
     419      get {
     420        var node = FirstVisibleNode;
     421        while (node != null && node.NextVisibleNode != null) node = node.NextVisibleNode;
     422        return node;
     423      }
     424    }
     425
     426    private class ItemTreeNodeComparer : IComparer {
     427      public int Compare(object x, object y) {
     428        var lhs = (TreeNode)x;
     429        var rhs = (TreeNode)y;
     430
     431        if (lhs.Tag is string && rhs.Tag is string) {
     432          return lhs.Name.CompareTo(rhs.Name);
     433        } else if (lhs.Tag is string) {
     434          return -1;
     435        } else
     436          return 1;
     437      }
     438    }
    100439  }
    101440}
Note: See TracChangeset for help on using the changeset viewer.