#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using HeuristicLab.Core;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Optimizer {
internal partial class NewItemDialog : Form {
private bool isInitialized;
private List treeNodes;
private string currentSearchString;
private Type selectedType;
public Type SelectedType {
get { return selectedType; }
private set {
if (value != selectedType) {
selectedType = value;
OnSelectedTypeChanged();
}
}
}
private IItem item;
public IItem Item {
get { return item; }
}
public NewItemDialog() {
InitializeComponent();
treeNodes = new List();
currentSearchString = string.Empty;
item = null;
SelectedTypeChanged += this_SelectedTypeChanged;
}
private void NewItemDialog_Load(object sender, EventArgs e) {
if (isInitialized) return;
var categories =
from t in ApplicationManager.Manager.GetTypes(typeof(IItem))
where CreatableAttribute.IsCreatable(t)
orderby CreatableAttribute.GetCategory(t), ItemAttribute.GetName(t), ItemAttribute.GetVersion(t) ascending
group t by CreatableAttribute.GetCategory(t) into c
select c;
imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Class); // default icon
imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Namespace); // plugins
foreach (var category in categories) {
var categoryNode = new TreeNode(category.Key) {
ImageIndex = 1,
Tag = category.Key,
};
categoryNode.SelectedImageIndex = categoryNode.ImageIndex;
foreach (var creatable in category) {
string name = ItemAttribute.GetName(creatable);
var itemNode = new TreeNode(name) {
ImageIndex = 0,
Tag = creatable
};
categoryNode.Nodes.Add(itemNode);
var image = ItemAttribute.GetImage(creatable);
if (image != null) {
imageList.Images.Add(image);
itemNode.ImageIndex = imageList.Images.Count - 1;
}
itemNode.SelectedImageIndex = itemNode.ImageIndex;
}
if (categoryNode.Nodes.Count > 0)
treeNodes.Add(categoryNode);
}
foreach (var node in treeNodes)
typesTreeView.Nodes.Add((TreeNode)node.Clone());
isInitialized = true;
}
private void NewItemDialog_Shown(object sender, EventArgs e) {
searchTextBox.Text = string.Empty;
searchTextBox.Focus();
}
public virtual void Filter(string searchString) {
if (InvokeRequired) {
Invoke(new Action(Filter), searchString);
} else {
searchString = searchString.ToLower();
if (!searchString.Contains(currentSearchString)) {
typesTreeView.BeginUpdate();
// expand saerch -> restore all tree nodes
var selectedNode = typesTreeView.SelectedNode;
typesTreeView.Nodes.Clear();
foreach (TreeNode node in treeNodes)
typesTreeView.Nodes.Add((TreeNode)node.Clone());
RestoreSelectedNode(selectedNode);
typesTreeView.EndUpdate();
}
// remove nodes
typesTreeView.BeginUpdate();
int i = 0;
var searchTokens = searchString.Split(' ');
while (i < typesTreeView.Nodes.Count) {
int j = 0;
while (j < typesTreeView.Nodes[i].Nodes.Count) {
if (searchTokens.Any(searchToken => !typesTreeView.Nodes[i].Nodes[j].Text.ToLower().Contains(searchToken))) {
if ((typesTreeView.Nodes[i].Nodes[j].Tag as Type).Equals(SelectedType))
SelectedType = null;
typesTreeView.Nodes[i].Nodes[j].Remove();
} else
j++;
}
if (typesTreeView.Nodes[i].Nodes.Count == 0)
typesTreeView.Nodes[i].Remove();
else
i++;
}
typesTreeView.EndUpdate();
currentSearchString = searchString;
// if there is just one type node left, select by default
if (typesTreeView.Nodes.Count == 1) {
if (typesTreeView.Nodes[0].Nodes.Count == 1) {
typesTreeView.SelectedNode = typesTreeView.Nodes[0].Nodes[0];
}
}
if (typesTreeView.Nodes.Count == 0) {
SelectedType = null;
typesTreeView.Enabled = false;
} else {
SetTreeNodeVisibility();
typesTreeView.Enabled = true;
}
UpdateDescription();
}
}
protected virtual void UpdateDescription() {
descriptionTextBox.Text = string.Empty;
if (typesTreeView.SelectedNode != null) {
string category = typesTreeView.SelectedNode.Tag as string;
if (category != null) {
descriptionTextBox.Text = category;
pluginTextBox.Text = string.Empty;
versionTextBox.Text = string.Empty;
}
Type type = typesTreeView.SelectedNode.Tag as Type;
if (type != null) {
string description = ItemAttribute.GetDescription(type);
var version = ItemAttribute.GetVersion(type);
var plugin = ApplicationManager.Manager.GetDeclaringPlugin(type);
if (description != null)
descriptionTextBox.Text = description;
if (plugin != null)
pluginTextBox.Text = plugin.Name;
if (version != null)
versionTextBox.Text = version.ToString();
}
} else if (typesTreeView.Nodes.Count == 0) {
descriptionTextBox.Text = "No types found";
pluginTextBox.Text = string.Empty;
versionTextBox.Text = string.Empty;
}
}
#region Events
public event EventHandler SelectedTypeChanged;
protected virtual void OnSelectedTypeChanged() {
if (SelectedTypeChanged != null)
SelectedTypeChanged(this, EventArgs.Empty);
}
#endregion
#region Control Events
protected virtual void searchTextBox_TextChanged(object sender, EventArgs e) {
Filter(searchTextBox.Text);
}
protected virtual void itemsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
if (typesTreeView.SelectedNode == null) SelectedType = null;
else SelectedType = typesTreeView.SelectedNode.Tag as Type;
UpdateDescription();
}
protected virtual void itemsTreeView_VisibleChanged(object sender, EventArgs e) {
if (Visible) SetTreeNodeVisibility();
}
#endregion
#region Helpers
private void RestoreSelectedNode(TreeNode selectedNode) {
if (selectedNode != null) {
foreach (TreeNode node in typesTreeView.Nodes) {
if (node.Text.Equals(selectedNode.Text)) typesTreeView.SelectedNode = node;
foreach (TreeNode child in node.Nodes) {
if ((child.Text.Equals(selectedNode.Text)) && (child.Tag == selectedNode.Tag))
typesTreeView.SelectedNode = child;
}
}
if (typesTreeView.SelectedNode == null) SelectedType = null;
}
}
private void SetTreeNodeVisibility() {
TreeNode selectedNode = typesTreeView.SelectedNode;
if (string.IsNullOrEmpty(currentSearchString) && (typesTreeView.Nodes.Count > 1)) {
typesTreeView.CollapseAll();
if (selectedNode != null) typesTreeView.SelectedNode = selectedNode;
} else {
typesTreeView.ExpandAll();
}
if (selectedNode != null) selectedNode.EnsureVisible();
}
#endregion
private void okButton_Click(object sender, EventArgs e) {
if (SelectedType != null) {
item = (IItem)Activator.CreateInstance(SelectedType);
DialogResult = DialogResult.OK;
Close();
}
}
private void itemTreeView_DoubleClick(object sender, EventArgs e) {
if (SelectedType != null) {
item = (IItem)Activator.CreateInstance(SelectedType);
DialogResult = DialogResult.OK;
Close();
}
}
private void this_SelectedTypeChanged(object sender, EventArgs e) {
okButton.Enabled = SelectedType != null;
}
private void expandAllButton_Click(object sender, EventArgs e) {
typesTreeView.ExpandAll();
}
private void collapseAllButton_Click(object sender, EventArgs e) {
typesTreeView.CollapseAll();
}
private TreeNode toolStripMenuNode = null;
private void typesTreeView_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Right) {
Point coordinates = typesTreeView.PointToClient(Cursor.Position);
toolStripMenuNode = typesTreeView.GetNodeAt(coordinates);
if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left &&
coordinates.X <= toolStripMenuNode.Bounds.Right) {
typesTreeView.SelectedNode = toolStripMenuNode;
expandToolStripMenuItem.Enabled =
expandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
} else {
expandToolStripMenuItem.Enabled = expandToolStripMenuItem.Visible = false;
collapseToolStripMenuItem.Enabled = collapseToolStripMenuItem.Visible = false;
}
expandAllToolStripMenuItem.Enabled =
expandAllToolStripMenuItem.Visible =
!typesTreeView.Nodes.OfType().All(x => TreeNodeIsFullyExpanded(x));
collapseAllToolStripMenuItem.Enabled =
collapseAllToolStripMenuItem.Visible = typesTreeView.Nodes.OfType().Any(x => x.IsExpanded);
if (contextMenuStrip.Items.Cast().Any(item => item.Enabled))
contextMenuStrip.Show(Cursor.Position);
}
}
private bool TreeNodeIsFullyExpanded(TreeNode node) {
return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType().All(x => TreeNodeIsFullyExpanded(x)));
}
private void expandToolStripMenuItem_Click(object sender, EventArgs e) {
if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
}
private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) {
typesTreeView.ExpandAll();
}
private void collapseToolStripMenuItem_Click(object sender, EventArgs e) {
if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
}
private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
typesTreeView.CollapseAll();
}
private void clearSearchButton_Click(object sender, EventArgs e) {
searchTextBox.Text = string.Empty;
searchTextBox.Focus();
}
}
}