#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 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.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Core {
///
/// The visual representation of an .
///
public partial class OperatorGraphView : ViewBase {
private ChooseOperatorDialog chooseOperatorDialog;
private Dictionary> operatorNodeTable;
///
/// Gets or sets the operator graph to represent visually.
///
/// Uses property of base class .
/// No own data storage present.
public IOperatorGraph OperatorGraph {
get { return (IOperatorGraph)Item; }
set { base.Item = value; }
}
///
/// Initializes a new instance of with caption "Operator Graph".
///
public OperatorGraphView() {
InitializeComponent();
operatorNodeTable = new Dictionary>();
operatorsListView.Columns[0].Width = Math.Max(0, operatorsListView.Width - 25);
Caption = "Operator Graph";
}
///
/// Initializes a new instance of
/// with the given .
///
/// Calls .
/// The operator graph to represent visually.
public OperatorGraphView(IOperatorGraph operatorGraph)
: this() {
OperatorGraph = operatorGraph;
}
///
/// Removes the eventhandlers from the underlying .
///
/// Calls of base class .
protected override void RemoveItemEvents() {
OperatorGraph.OperatorAdded -= new EventHandler(OperatorGraph_OperatorAdded);
OperatorGraph.OperatorRemoved -= new EventHandler(OperatorGraph_OperatorRemoved);
OperatorGraph.InitialOperatorChanged -= new EventHandler(OperatorGraph_InitialOperatorChanged);
base.RemoveItemEvents();
}
///
/// Adds eventhandlers to the underlying .
///
/// Calls of base class .
protected override void AddItemEvents() {
base.AddItemEvents();
OperatorGraph.OperatorAdded += new EventHandler(OperatorGraph_OperatorAdded);
OperatorGraph.OperatorRemoved += new EventHandler(OperatorGraph_OperatorRemoved);
OperatorGraph.InitialOperatorChanged += new EventHandler(OperatorGraph_InitialOperatorChanged);
}
///
/// Updates all controls with the latest data of the model.
///
/// Calls of base class .
protected override void UpdateControls() {
base.UpdateControls();
if (graphTreeView.Nodes.Count > 0)
RemoveTreeNode(graphTreeView.Nodes[0]);
graphTreeView.SelectedNode = null;
graphTreeView.Nodes.Clear();
graphTreeView.Enabled = false;
operatorsListView.Items.Clear();
removeButton.Enabled = false;
if (OperatorGraph == null) {
Caption = "Operator Graph";
operatorsListView.Enabled = false;
addOperatorButton.Enabled = false;
} else {
Caption = "Operator Graph (" + OperatorGraph.GetType().Name + ")";
foreach (IOperator op in OperatorGraph.Operators) {
operatorsListView.Items.Add(CreateListViewItem(op));
}
operatorsListView.Enabled = true;
addOperatorButton.Enabled = true;
if (OperatorGraph.InitialOperator != null) {
graphTreeView.Nodes.Add(CreateTreeNode(OperatorGraph.InitialOperator));
graphTreeView.Enabled = true;
}
}
}
private ListViewItem CreateListViewItem(IOperator op) {
ListViewItem item = new ListViewItem();
item.Text = op.Name;
item.Tag = op;
item.ImageIndex = 0;
if (op.GetType().Name == "CombinedOperator")
item.ImageIndex = 1;
else if (op.GetType().Name == "ProgrammableOperator")
item.ImageIndex = 2;
if (op == OperatorGraph.InitialOperator)
item.Font = new Font(operatorsListView.Font, FontStyle.Bold);
return item;
}
private TreeNode CreateTreeNode(IOperator op) {
TreeNode node = new TreeNode();
node.Text = op.Name;
node.Tag = op;
if (op.Breakpoint)
node.ForeColor = Color.Red;
if (!operatorNodeTable.ContainsKey(op)) {
operatorNodeTable.Add(op, new List());
op.NameChanged += new EventHandler(Operator_NameChanged);
op.BreakpointChanged += new EventHandler(Operator_BreakpointChanged);
op.SubOperatorAdded += new EventHandler(Operator_SubOperatorAdded);
op.SubOperatorRemoved += new EventHandler(Operator_SubOperatorRemoved);
}
operatorNodeTable[op].Add(node);
for (int i = 0; i < op.SubOperators.Count; i++)
node.Nodes.Add(new TreeNode());
return node;
}
private void RemoveTreeNode(TreeNode node) {
foreach (TreeNode child in node.Nodes)
RemoveTreeNode(child);
IOperator op = (IOperator)node.Tag;
if (op != null) {
operatorNodeTable[op].Remove(node);
if (operatorNodeTable[op].Count == 0) {
op.NameChanged -= new EventHandler(Operator_NameChanged);
op.BreakpointChanged -= new EventHandler(Operator_BreakpointChanged);
op.SubOperatorAdded -= new EventHandler(Operator_SubOperatorAdded);
op.SubOperatorRemoved -= new EventHandler(Operator_SubOperatorRemoved);
operatorNodeTable.Remove(op);
}
}
}
#region ListView Events
private void operatorsListView_SelectedIndexChanged(object sender, EventArgs e) {
removeButton.Enabled = false;
if (operatorsListView.SelectedItems.Count > 0) {
removeButton.Enabled = true;
}
}
private void operatorsListView_DoubleClick(object sender, EventArgs e) {
if (operatorsListView.SelectedItems.Count == 1) {
IOperator op = (IOperator)operatorsListView.SelectedItems[0].Tag;
IView view = op.CreateView();
if (view != null)
PluginManager.ControlManager.ShowControl(view);
}
}
#endregion
#region TreeView Events
private void graphTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
TreeNode node = e.Node;
IOperator op = (IOperator)node.Tag;
for (int i = 0; i < node.Nodes.Count; i++) {
if (node.Nodes[i].Tag == null) {
node.Nodes[i].Remove();
node.Nodes.Insert(i, CreateTreeNode(op.SubOperators[i]));
}
}
}
private void graphTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
IOperator op = (IOperator)e.Node.Tag;
foreach (ListViewItem item in operatorsListView.Items)
item.Selected = item.Tag == op;
}
#endregion
#region Size Changed Events
private void operatorsListView_SizeChanged(object sender, EventArgs e) {
if (operatorsListView.Columns.Count > 0)
operatorsListView.Columns[0].Width = Math.Max(0, operatorsListView.Width - 25);
}
#endregion
#region Key Events
private void operatorsListView_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.Delete) {
if (operatorsListView.SelectedItems.Count > 0) {
foreach (ListViewItem item in operatorsListView.SelectedItems)
OperatorGraph.RemoveOperator(((IOperator)item.Tag).Guid);
}
}
if (e.KeyCode == Keys.F2) {
if (operatorsListView.SelectedItems.Count == 1)
operatorsListView.SelectedItems[0].BeginEdit();
}
}
private void graphTreeView_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.Delete) {
TreeNode node = graphTreeView.SelectedNode;
if ((node != null) && (node.Parent != null)) {
IOperator parent = (IOperator)node.Parent.Tag;
parent.RemoveSubOperator(node.Index);
}
}
}
#endregion
#region Edit Events
private void operatorsListView_AfterLabelEdit(object sender, LabelEditEventArgs e) {
e.CancelEdit = false;
string name = e.Label;
if (name != null) {
IOperator op = (IOperator)operatorsListView.Items[e.Item].Tag;
op.Name = name;
}
}
#endregion
#region Button Events
private void addOperatorButton_Click(object sender, EventArgs e) {
if (chooseOperatorDialog == null) chooseOperatorDialog = new ChooseOperatorDialog();
if (chooseOperatorDialog.ShowDialog(this) == DialogResult.OK)
OperatorGraph.AddOperator(chooseOperatorDialog.Operator);
}
private void removeButton_Click(object sender, EventArgs e) {
if (operatorsListView.SelectedItems.Count > 0) {
foreach (ListViewItem item in operatorsListView.SelectedItems)
OperatorGraph.RemoveOperator(((IOperator)item.Tag).Guid);
}
}
#endregion
#region Drag and Drop Events
private void operatorsListView_ItemDrag(object sender, ItemDragEventArgs e) {
ListViewItem item = (ListViewItem)e.Item;
IOperator op = (IOperator)item.Tag;
DataObject data = new DataObject();
data.SetData("IOperator", op);
data.SetData("DragSource", operatorsListView);
DoDragDrop(data, DragDropEffects.Copy);
}
private void operatorsListView_DragEnter(object sender, DragEventArgs e) {
e.Effect = DragDropEffects.None;
if (e.Data.GetDataPresent("IOperator"))
e.Effect = DragDropEffects.Copy;
}
private void operatorsListView_DragOver(object sender, DragEventArgs e) {
e.Effect = DragDropEffects.None;
if (e.Data.GetDataPresent("IOperator"))
e.Effect = DragDropEffects.Copy;
}
private void operatorsListView_DragDrop(object sender, DragEventArgs e) {
if (e.Effect != DragDropEffects.None) {
if (e.Data.GetDataPresent("IOperator")) {
IOperator op = (IOperator)e.Data.GetData("IOperator");
op = (IOperator)op.Clone();
OperatorGraph.AddOperator(op);
}
}
}
private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
TreeNode node = (TreeNode)e.Item;
if (node.Parent != null) {
IOperator op = (IOperator)node.Tag;
IOperator parent = (IOperator)node.Parent.Tag;
int index = node.Index;
DataObject data = new DataObject();
data.SetData("IOperator", op);
data.SetData("DragSource", graphTreeView);
data.SetData("ParentOperator", parent);
data.SetData("Index", index);
DoDragDrop(data, DragDropEffects.Move);
}
}
private void graphTreeView_DragEnter(object sender, DragEventArgs e) {
e.Effect = DragDropEffects.None;
if (e.Data.GetDataPresent("IOperator")) {
Point p = graphTreeView.PointToClient(new Point(e.X, e.Y));
TreeNode node = graphTreeView.GetNodeAt(p);
if (node != null) {
if ((e.Data.GetDataPresent("ParentOperator")) && (node.Parent != null)) {
if ((e.Data.GetDataPresent("DragSource")) && (e.Data.GetData("DragSource") == graphTreeView))
e.Effect = DragDropEffects.Move;
} else {
if ((e.Data.GetDataPresent("DragSource")) && (e.Data.GetData("DragSource") == operatorsListView))
e.Effect = DragDropEffects.Copy;
}
}
}
}
private void graphTreeView_DragOver(object sender, DragEventArgs e) {
e.Effect = DragDropEffects.None;
if (e.Data.GetDataPresent("IOperator")) {
Point p = graphTreeView.PointToClient(new Point(e.X, e.Y));
TreeNode node = graphTreeView.GetNodeAt(p);
if (node != null) {
if ((e.Data.GetDataPresent("ParentOperator")) && (node.Parent != null)) {
if ((e.Data.GetDataPresent("DragSource")) && (e.Data.GetData("DragSource") == graphTreeView))
e.Effect = DragDropEffects.Move;
} else {
if ((e.Data.GetDataPresent("DragSource")) && (e.Data.GetData("DragSource") == operatorsListView))
e.Effect = DragDropEffects.Copy;
}
}
}
}
private void graphTreeView_DragDrop(object sender, DragEventArgs e) {
if (e.Effect != DragDropEffects.None) {
if (e.Data.GetDataPresent("IOperator")) {
IOperator op = (IOperator)e.Data.GetData("IOperator");
Point p = graphTreeView.PointToClient(new Point(e.X, e.Y));
TreeNode node = graphTreeView.GetNodeAt(p);
if (e.Data.GetDataPresent("ParentOperator")) {
if (node.Parent != null) {
TreeNode parentNode = node.Parent;
IOperator oldParent = (IOperator)e.Data.GetData("ParentOperator");
int oldIndex = (int)e.Data.GetData("Index");
IOperator newParent = (IOperator)node.Parent.Tag;
int newIndex = node.Index;
ICollection violatedConstraints;
ICollection violatedConstraints2;
oldParent.TryRemoveSubOperator(oldIndex, out violatedConstraints);
newParent.TryAddSubOperator(op, newIndex, out violatedConstraints2);
if ((violatedConstraints.Count == 0) && (violatedConstraints2.Count == 0)) {
graphTreeView.SelectedNode = parentNode.Nodes[newIndex];
} else {
List allViolatedConstraints = new List(violatedConstraints);
allViolatedConstraints.AddRange(violatedConstraints2);
if (Auxiliary.ShowIgnoreConstraintViolationMessageBox(allViolatedConstraints) == DialogResult.Yes) {
if (violatedConstraints.Count > 0)
oldParent.RemoveSubOperator(oldIndex);
if (violatedConstraints2.Count > 0)
newParent.AddSubOperator(op, newIndex);
graphTreeView.SelectedNode = parentNode.Nodes[newIndex];
} else {
if (violatedConstraints.Count == 0)
oldParent.AddSubOperator(op, oldIndex);
if (violatedConstraints2.Count == 0)
newParent.RemoveSubOperator(newIndex);
}
}
}
} else {
if (node != null) {
IOperator parent = (IOperator)node.Tag;
ICollection violatedConstraints;
if (parent.TryAddSubOperator(op, out violatedConstraints)) {
graphTreeView.SelectedNode = node.Nodes[node.Nodes.Count - 1];
} else if (Auxiliary.ShowIgnoreConstraintViolationMessageBox(violatedConstraints) == DialogResult.Yes) {
parent.AddSubOperator(op);
graphTreeView.SelectedNode = node.Nodes[node.Nodes.Count - 1];
}
}
}
}
}
}
#endregion
#region Context Menu Events
private void operatorsContextMenuStrip_Opening(object sender, CancelEventArgs e) {
viewToolStripMenuItem.Enabled = false;
initialOperatorToolStripMenuItem.Enabled = false;
initialOperatorToolStripMenuItem.Checked = false;
if (operatorsListView.SelectedItems.Count == 1) {
IOperator op = (IOperator)operatorsListView.SelectedItems[0].Tag;
IView view = op.CreateView();
if (view != null) {
viewToolStripMenuItem.Enabled = true;
viewToolStripMenuItem.Tag = view;
}
initialOperatorToolStripMenuItem.Enabled = true;
initialOperatorToolStripMenuItem.Tag = op;
if (op == OperatorGraph.InitialOperator)
initialOperatorToolStripMenuItem.Checked = true;
}
}
private void viewToolStripMenuItem_Click(object sender, EventArgs e) {
IView view = (IView)((ToolStripMenuItem)sender).Tag;
PluginManager.ControlManager.ShowControl(view);
}
private void initialOperatorToolStripMenuItem_Click(object sender, EventArgs e) {
if (initialOperatorToolStripMenuItem.Checked) {
foreach (ListViewItem item in operatorsListView.Items)
item.Font = operatorsListView.Font;
operatorsListView.SelectedItems[0].Font = new Font(operatorsListView.Font, FontStyle.Bold);
OperatorGraph.InitialOperator = (IOperator)initialOperatorToolStripMenuItem.Tag;
} else {
operatorsListView.SelectedItems[0].Font = operatorsListView.Font;
OperatorGraph.InitialOperator = null;
}
}
private void graphContextMenuStrip_Opening(object sender, CancelEventArgs e) {
viewToolStripMenuItem1.Enabled = false;
breakpointToolStripMenuItem.Enabled = false;
breakpointToolStripMenuItem.Checked = false;
if (graphTreeView.SelectedNode != null) {
IOperator op = (IOperator)graphTreeView.SelectedNode.Tag;
IView view = op.CreateView();
if (view != null) {
viewToolStripMenuItem1.Enabled = true;
viewToolStripMenuItem1.Tag = view;
}
breakpointToolStripMenuItem.Enabled = true;
breakpointToolStripMenuItem.Tag = op;
if (op.Breakpoint)
breakpointToolStripMenuItem.Checked = true;
}
}
private void breakpointToolStripMenuItem_Click(object sender, EventArgs e) {
IOperator op = (IOperator)breakpointToolStripMenuItem.Tag;
op.Breakpoint = breakpointToolStripMenuItem.Checked;
}
#endregion
#region OperatorGraph Events
private void OperatorGraph_OperatorAdded(object sender, OperatorEventArgs e) {
operatorsListView.Items.Add(CreateListViewItem(e.Operator));
}
private void OperatorGraph_OperatorRemoved(object sender, OperatorEventArgs e) {
ListViewItem itemToDelete = null;
foreach (ListViewItem item in operatorsListView.Items) {
if (item.Tag == e.Operator)
itemToDelete = item;
}
itemToDelete.Remove();
}
private void OperatorGraph_InitialOperatorChanged(object sender, EventArgs e) {
Refresh();
}
#endregion
#region Operator Events
private void Operator_NameChanged(object sender, EventArgs e) {
IOperator op = (IOperator)sender;
foreach (TreeNode node in operatorNodeTable[op])
node.Text = op.Name;
}
private void Operator_BreakpointChanged(object sender, EventArgs e) {
IOperator op = (IOperator)sender;
foreach (TreeNode node in operatorNodeTable[op]) {
if (op.Breakpoint)
node.ForeColor = Color.Red;
else
node.ForeColor = graphTreeView.ForeColor;
}
}
private void Operator_SubOperatorAdded(object sender, OperatorIndexEventArgs e) {
IOperator op = (IOperator)sender;
if (operatorNodeTable.ContainsKey(op)) {
TreeNode[] nodes = new TreeNode[operatorNodeTable[op].Count];
operatorNodeTable[op].CopyTo(nodes, 0);
foreach (TreeNode node in nodes)
node.Nodes.Insert(e.Index, CreateTreeNode(e.Operator));
}
}
private void Operator_SubOperatorRemoved(object sender, OperatorIndexEventArgs e) {
IOperator op = (IOperator)sender;
if (operatorNodeTable.ContainsKey(op)) {
TreeNode[] nodes = new TreeNode[operatorNodeTable[op].Count];
operatorNodeTable[op].CopyTo(nodes, 0);
foreach (TreeNode node in nodes) {
RemoveTreeNode(node.Nodes[e.Index]);
node.Nodes.RemoveAt(e.Index);
}
}
}
#endregion
#region Mouse Events
private void graphTreeView_MouseDown(object sender, MouseEventArgs e) {
if (e.Button != MouseButtons.Right) return;
TreeNode clickedNode = graphTreeView.GetNodeAt(e.X, e.Y);
if (clickedNode != null) {
graphTreeView.SelectedNode = clickedNode;
graphTreeView.Refresh();
}
}
#endregion
}
}