Free cookie consent management tool by TermsFeed Policy Generator

source: branches/NewItemDialog/HeuristicLab.Optimizer/3.3/NewItemDialog.cs @ 12206

Last change on this file since 12206 was 12206, checked in by pfleck, 9 years ago

#2025 Added context menu for expanding and collapsing nodes.

File size: 11.6 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.Windows.Forms;
27using HeuristicLab.Core;
28using HeuristicLab.PluginInfrastructure;
29
30namespace HeuristicLab.Optimizer {
31  internal partial class NewItemDialog : Form {
32    private bool isInitialized;
33
34    private List<TreeNode> treeNodes;
35    private string currentSearchString;
36
37    private Type selectedType;
38    public Type SelectedType {
39      get { return selectedType; }
40      private set {
41        if (value != selectedType) {
42          selectedType = value;
43          OnSelectedTypeChanged();
44        }
45      }
46    }
47
48    private IItem item;
49    public IItem Item {
50      get { return item; }
51    }
52
53    public NewItemDialog() {
54      InitializeComponent();
55      treeNodes = new List<TreeNode>();
56      currentSearchString = string.Empty;
57      item = null;
58      SelectedTypeChanged += this_SelectedTypeChanged;
59    }
60
61    private void NewItemDialog_Load(object sender, EventArgs e) {
62      if (isInitialized) return;
63
64      var categories =
65        from t in ApplicationManager.Manager.GetTypes(typeof(IItem))
66        where CreatableAttribute.IsCreatable(t)
67        orderby CreatableAttribute.GetCategory(t), ItemAttribute.GetName(t), ItemAttribute.GetVersion(t) ascending
68        group t by CreatableAttribute.GetCategory(t) into c
69        select c;
70
71      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class);      // default icon
72      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Namespace);  // plugins
73
74      foreach (var category in categories) {
75        var categoryNode = new TreeNode(category.Key) {
76          ImageIndex = 1,
77          Tag = category.Key,
78        };
79        categoryNode.SelectedImageIndex = categoryNode.ImageIndex;
80
81        foreach (var creatable in category) {
82          string name = ItemAttribute.GetName(creatable);
83
84          var itemNode = new TreeNode(name) {
85            ImageIndex = 0,
86            Tag = creatable
87          };
88          categoryNode.Nodes.Add(itemNode);
89          var image = ItemAttribute.GetImage(creatable);
90          if (image != null) {
91            imageList.Images.Add(image);
92            itemNode.ImageIndex = imageList.Images.Count - 1;
93          }
94          itemNode.SelectedImageIndex = itemNode.ImageIndex;
95        }
96        if (categoryNode.Nodes.Count > 0)
97          treeNodes.Add(categoryNode);
98      }
99      foreach (var node in treeNodes)
100        typesTreeView.Nodes.Add((TreeNode)node.Clone());
101      isInitialized = true;
102    }
103    private void NewItemDialog_Shown(object sender, EventArgs e) {
104      searchTextBox.Text = string.Empty;
105      searchTextBox.Focus();
106    }
107
108    public virtual void Filter(string searchString) {
109      if (InvokeRequired) {
110        Invoke(new Action<string>(Filter), searchString);
111      } else {
112        searchString = searchString.ToLower();
113
114        if (!searchString.Contains(currentSearchString)) {
115          typesTreeView.BeginUpdate();
116          // expand saerch -> restore all tree nodes
117          var selectedNode = typesTreeView.SelectedNode;
118          typesTreeView.Nodes.Clear();
119          foreach (TreeNode node in treeNodes)
120            typesTreeView.Nodes.Add((TreeNode)node.Clone());
121          RestoreSelectedNode(selectedNode);
122          typesTreeView.EndUpdate();
123        }
124
125        // remove nodes
126        typesTreeView.BeginUpdate();
127        int i = 0;
128        var searchTokens = searchString.Split(' ');
129        while (i < typesTreeView.Nodes.Count) {
130          int j = 0;
131          while (j < typesTreeView.Nodes[i].Nodes.Count) {
132            if (searchTokens.Any(searchToken => !typesTreeView.Nodes[i].Nodes[j].Text.ToLower().Contains(searchToken))) {
133              if ((typesTreeView.Nodes[i].Nodes[j].Tag as Type).Equals(SelectedType))
134                SelectedType = null;
135              typesTreeView.Nodes[i].Nodes[j].Remove();
136            } else
137              j++;
138          }
139          if (typesTreeView.Nodes[i].Nodes.Count == 0)
140            typesTreeView.Nodes[i].Remove();
141          else
142            i++;
143        }
144        typesTreeView.EndUpdate();
145        currentSearchString = searchString;
146
147        // if there is just one type node left, select by default
148        if (typesTreeView.Nodes.Count == 1) {
149          if (typesTreeView.Nodes[0].Nodes.Count == 1) {
150            typesTreeView.SelectedNode = typesTreeView.Nodes[0].Nodes[0];
151          }
152        }
153
154        if (typesTreeView.Nodes.Count == 0) {
155          SelectedType = null;
156          typesTreeView.Enabled = false;
157        } else {
158          SetTreeNodeVisibility();
159          typesTreeView.Enabled = true;
160        }
161        UpdateDescription();
162      }
163    }
164
165    protected virtual void UpdateDescription() {
166      descriptionTextBox.Text = string.Empty;
167
168      if (typesTreeView.SelectedNode != null) {
169        string category = typesTreeView.SelectedNode.Tag as string;
170        if (category != null) {
171          descriptionTextBox.Text = category;
172          pluginTextBox.Text = string.Empty;
173          versionTextBox.Text = string.Empty;
174        }
175        Type type = typesTreeView.SelectedNode.Tag as Type;
176        if (type != null) {
177          string description = ItemAttribute.GetDescription(type);
178          var version = ItemAttribute.GetVersion(type);
179          var plugin = ApplicationManager.Manager.GetDeclaringPlugin(type);
180          if (description != null)
181            descriptionTextBox.Text = description;
182          if (plugin != null)
183            pluginTextBox.Text = plugin.Name;
184          if (version != null)
185            versionTextBox.Text = version.ToString();
186        }
187      } else if (typesTreeView.Nodes.Count == 0) {
188        descriptionTextBox.Text = "No types found";
189        pluginTextBox.Text = string.Empty;
190        versionTextBox.Text = string.Empty;
191      }
192    }
193
194    #region Events
195    public event EventHandler SelectedTypeChanged;
196    protected virtual void OnSelectedTypeChanged() {
197      if (SelectedTypeChanged != null)
198        SelectedTypeChanged(this, EventArgs.Empty);
199    }
200    #endregion
201
202    #region Control Events
203    protected virtual void searchTextBox_TextChanged(object sender, EventArgs e) {
204      Filter(searchTextBox.Text);
205    }
206
207    protected virtual void itemsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
208      if (typesTreeView.SelectedNode == null) SelectedType = null;
209      else SelectedType = typesTreeView.SelectedNode.Tag as Type;
210      UpdateDescription();
211    }
212
213    protected virtual void itemsTreeView_VisibleChanged(object sender, EventArgs e) {
214      if (Visible) SetTreeNodeVisibility();
215    }
216    #endregion
217
218    #region Helpers
219    private void RestoreSelectedNode(TreeNode selectedNode) {
220      if (selectedNode != null) {
221        foreach (TreeNode node in typesTreeView.Nodes) {
222          if (node.Text.Equals(selectedNode.Text)) typesTreeView.SelectedNode = node;
223          foreach (TreeNode child in node.Nodes) {
224            if ((child.Text.Equals(selectedNode.Text)) && (child.Tag == selectedNode.Tag))
225              typesTreeView.SelectedNode = child;
226          }
227        }
228        if (typesTreeView.SelectedNode == null) SelectedType = null;
229      }
230    }
231    private void SetTreeNodeVisibility() {
232      TreeNode selectedNode = typesTreeView.SelectedNode;
233      if (string.IsNullOrEmpty(currentSearchString) && (typesTreeView.Nodes.Count > 1)) {
234        typesTreeView.CollapseAll();
235        if (selectedNode != null) typesTreeView.SelectedNode = selectedNode;
236      } else {
237        typesTreeView.ExpandAll();
238      }
239      if (selectedNode != null) selectedNode.EnsureVisible();
240    }
241    #endregion
242
243    private void okButton_Click(object sender, EventArgs e) {
244      if (SelectedType != null) {
245        item = (IItem)Activator.CreateInstance(SelectedType);
246        DialogResult = DialogResult.OK;
247        Close();
248      }
249    }
250    private void itemTreeView_DoubleClick(object sender, EventArgs e) {
251      if (SelectedType != null) {
252        item = (IItem)Activator.CreateInstance(SelectedType);
253        DialogResult = DialogResult.OK;
254        Close();
255      }
256    }
257    private void this_SelectedTypeChanged(object sender, EventArgs e) {
258      okButton.Enabled = SelectedType != null;
259    }
260
261    private void expandAllButton_Click(object sender, EventArgs e) {
262      typesTreeView.ExpandAll();
263    }
264    private void collapseAllButton_Click(object sender, EventArgs e) {
265      typesTreeView.CollapseAll();
266    }
267
268    private TreeNode toolStripMenuNode = null;
269    private void typesTreeView_MouseDown(object sender, MouseEventArgs e) {
270      if (e.Button == MouseButtons.Right) {
271        Point coordinates = typesTreeView.PointToClient(Cursor.Position);
272        toolStripMenuNode = typesTreeView.GetNodeAt(coordinates);
273
274        if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left &&
275            coordinates.X <= toolStripMenuNode.Bounds.Right) {
276          typesTreeView.SelectedNode = toolStripMenuNode;
277
278          expandToolStripMenuItem.Enabled =
279            expandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
280          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
281        } else {
282          expandToolStripMenuItem.Enabled = expandToolStripMenuItem.Visible = false;
283          collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = false;
284        }
285        expandAllToolStripMenuItem.Enabled =
286          expandAllToolStripMenuItem.Visible =
287            !typesTreeView.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x));
288        collapseAllToolStripMenuItem.Enabled =
289          collapseAllToolStripMenuItem.Visible = typesTreeView.Nodes.OfType<TreeNode>().Any(x => x.IsExpanded);
290        if (contextMenuStrip.Items.Cast<ToolStripMenuItem>().Any(item => item.Enabled))
291          contextMenuStrip.Show(Cursor.Position);
292      }
293    }
294    private bool TreeNodeIsFullyExpanded(TreeNode node) {
295      return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x)));
296    }
297
298    private void expandToolStripMenuItem_Click(object sender, EventArgs e) {
299      if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
300    }
301    private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) {
302      typesTreeView.ExpandAll();
303    }
304    private void collapseToolStripMenuItem_Click(object sender, EventArgs e) {
305      if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
306    }
307    private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
308      typesTreeView.CollapseAll();
309    }
310  }
311}
Note: See TracBrowser for help on using the repository browser.