#region License Information /* HeuristicLab * Copyright (C) 2002-2010 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; using HeuristicLab.Common; using HeuristicLab.MainForm; using HeuristicLab.Collections; namespace HeuristicLab.Core.Views { /// /// The visual representation of an . /// [Content(typeof(IOperator), false)] public sealed partial class OperatorTreeView : ItemView { private Dictionary, List> opParamNodeTable; private Dictionary> operatorNodeTable; private Dictionary, IOperator> parametersOperatorTable; /// /// Gets or sets the operator graph to represent visually. /// /// Uses property of base class . /// No own data storage present. public new IOperator Content { get { return (IOperator)base.Content; } set { base.Content = value; } } /// /// Initializes a new instance of with caption "Operator Graph". /// public OperatorTreeView() { InitializeComponent(); graphTreeView.Sorted = true; opParamNodeTable = new Dictionary, List>(); operatorNodeTable = new Dictionary>(); parametersOperatorTable = new Dictionary, IOperator>(); Caption = "Operator"; } /// /// Initializes a new instance of /// with the given . /// /// Calls . /// The operator graph to represent visually. public OperatorTreeView(IOperator content) : this() { Content = content; } /// /// Updates all controls with the latest data of the model. /// /// Calls of base class . protected override void OnContentChanged() { base.OnContentChanged(); if (graphTreeView.Nodes.Count > 0) RemoveTreeNode(graphTreeView.Nodes[0]); graphTreeView.Enabled = false; Caption = "Operator"; if (Content != null) { Caption = Content.Name + " (" + Content.GetType().Name + ")"; TreeNode root = new TreeNode(); FillTreeNode(root, Content); graphTreeView.Nodes.Add(root); graphTreeView.Enabled = true; } } #region TreeNode Management private TreeNode CreateTreeNode(IValueParameter opParam) { TreeNode node = new TreeNode(); node.Text = opParam.Name + ": "; SetOperatorParameterTag(node, opParam); if (!opParamNodeTable.ContainsKey(opParam)) { opParamNodeTable.Add(opParam, new List()); opParam.ValueChanged += new EventHandler(opParam_ValueChanged); } opParamNodeTable[opParam].Add(node); IOperator op = opParam.Value; if (op == null) node.Text += "-"; else FillTreeNode(node, op); return node; } private void FillTreeNode(TreeNode node, IOperator op) { if (!graphTreeView.ImageList.Images.ContainsKey(op.GetType().FullName)) graphTreeView.ImageList.Images.Add(op.GetType().FullName, op.ItemImage); node.Text += op.Name; node.ToolTipText = op.ItemName + ": " + op.ItemDescription; node.ImageIndex = graphTreeView.ImageList.Images.IndexOfKey(op.GetType().FullName); node.SelectedImageIndex = node.ImageIndex; SetOperatorTag(node, op); if (!operatorNodeTable.ContainsKey(op)) { operatorNodeTable.Add(op, new List()); op.NameChanged += new EventHandler(op_NameChanged); op.BreakpointChanged += new EventHandler(op_BreakpointChanged); parametersOperatorTable.Add(op.Parameters, op); op.Parameters.ItemsAdded += new CollectionItemsChangedEventHandler(Parameters_ItemsAdded); op.Parameters.ItemsRemoved += new CollectionItemsChangedEventHandler(Parameters_ItemsRemoved); op.Parameters.ItemsReplaced += new CollectionItemsChangedEventHandler(Parameters_ItemsReplaced); op.Parameters.CollectionReset += new CollectionItemsChangedEventHandler(Parameters_CollectionReset); } operatorNodeTable[op].Add(node); if (op.Breakpoint) node.ForeColor = Color.Red; foreach (IParameter param in op.Parameters) { if (param is IValueParameter) node.Nodes.Add(new TreeNode()); } node.Collapse(); } private void ClearTreeNode(TreeNode node) { while (node.Nodes.Count > 0) RemoveTreeNode(node.Nodes[0]); IOperator op = GetOperatorTag(node); if (op != null) { operatorNodeTable[op].Remove(node); if (operatorNodeTable[op].Count == 0) { op.NameChanged -= new EventHandler(op_NameChanged); op.BreakpointChanged -= new EventHandler(op_BreakpointChanged); operatorNodeTable.Remove(op); op.Parameters.ItemsAdded -= new CollectionItemsChangedEventHandler(Parameters_ItemsAdded); op.Parameters.ItemsRemoved -= new CollectionItemsChangedEventHandler(Parameters_ItemsRemoved); op.Parameters.ItemsReplaced -= new CollectionItemsChangedEventHandler(Parameters_ItemsReplaced); op.Parameters.CollectionReset -= new CollectionItemsChangedEventHandler(Parameters_CollectionReset); parametersOperatorTable.Remove(op.Parameters); } } SetOperatorTag(node, null); } private void RemoveTreeNode(TreeNode node) { ClearTreeNode(node); IValueParameter opParam = GetOperatorParameterTag(node); if (opParam != null) { opParamNodeTable[opParam].Remove(node); if (opParamNodeTable[opParam].Count == 0) { opParam.ValueChanged -= new EventHandler(opParam_ValueChanged); opParamNodeTable.Remove(opParam); } } SetOperatorParameterTag(node, null); node.Remove(); } private void AddParameterNodes(IOperator op, IEnumerable parameters) { foreach (IParameter param in parameters) { IValueParameter opParam = param as IValueParameter; if (opParam != null) { foreach (TreeNode node in operatorNodeTable[op]) node.Nodes.Add(CreateTreeNode(opParam)); } } } private void RemoveParameterNodes(IEnumerable parameters) { foreach (IParameter param in parameters) { IValueParameter opParam = param as IValueParameter; if (opParam != null) { while (opParamNodeTable.ContainsKey(opParam)) RemoveTreeNode(opParamNodeTable[opParam][0]); } } } #endregion #region Parameter and Operator Events private void opParam_ValueChanged(object sender, EventArgs e) { if (InvokeRequired) Invoke(new EventHandler(opParam_ValueChanged), sender, e); else { IValueParameter opParam = (IValueParameter)sender; foreach (TreeNode node in opParamNodeTable[opParam].ToArray()) ClearTreeNode(node); foreach (TreeNode node in opParamNodeTable[opParam]) { node.Text = opParam.Name + ": "; if (opParam.Value == null) node.Text += "-"; else FillTreeNode(node, opParam.Value); } } } private void op_NameChanged(object sender, EventArgs e) { if (InvokeRequired) Invoke(new EventHandler(op_NameChanged), sender, e); else { IOperator op = (IOperator)sender; foreach (TreeNode node in operatorNodeTable[op]) { IValueParameter opParam = GetOperatorParameterTag(node); if (opParam == null) node.Text = op.Name + " (" + op.ItemName + ")"; else node.Text = opParam.Name + ": " + op.Name; } } } private void op_BreakpointChanged(object sender, EventArgs e) { if (InvokeRequired) Invoke(new EventHandler(op_BreakpointChanged), sender, e); else { IOperator op = (IOperator)sender; foreach (TreeNode node in operatorNodeTable[op]) { if (op.Breakpoint) node.ForeColor = Color.Red; else node.ForeColor = graphTreeView.ForeColor; } } } private void Parameters_ItemsAdded(object sender, CollectionItemsChangedEventArgs e) { if (InvokeRequired) Invoke(new CollectionItemsChangedEventHandler(Parameters_ItemsAdded), sender, e); else { IObservableKeyedCollection coll = (IObservableKeyedCollection)sender; IOperator op = parametersOperatorTable[coll]; AddParameterNodes(op, e.Items); } } private void Parameters_ItemsRemoved(object sender, CollectionItemsChangedEventArgs e) { if (InvokeRequired) Invoke(new CollectionItemsChangedEventHandler(Parameters_ItemsRemoved), sender, e); else RemoveParameterNodes(e.Items); } private void Parameters_ItemsReplaced(object sender, CollectionItemsChangedEventArgs e) { if (InvokeRequired) Invoke(new CollectionItemsChangedEventHandler(Parameters_ItemsReplaced), sender, e); else { RemoveParameterNodes(e.Items); IObservableKeyedCollection coll = (IObservableKeyedCollection)sender; IOperator op = parametersOperatorTable[coll]; AddParameterNodes(op, e.Items); } } private void Parameters_CollectionReset(object sender, CollectionItemsChangedEventArgs e) { if (InvokeRequired) Invoke(new CollectionItemsChangedEventHandler(Parameters_CollectionReset), sender, e); else { RemoveParameterNodes(e.Items); IObservableKeyedCollection coll = (IObservableKeyedCollection)sender; IOperator op = parametersOperatorTable[coll]; AddParameterNodes(op, e.Items); } } #endregion #region TreeView Events private void graphTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) { TreeNode node = e.Node; if ((node.Nodes.Count > 0) && (node.Nodes[0].Tag == null)) { node.Nodes.Clear(); IOperator op = GetOperatorTag(node); foreach (IParameter param in op.Parameters) { IValueParameter opParam = param as IValueParameter; if (opParam != null) node.Nodes.Add(CreateTreeNode(opParam)); } } } private void graphTreeView_MouseDown(object sender, MouseEventArgs e) { TreeNode node = graphTreeView.GetNodeAt(e.X, e.Y); graphTreeView.SelectedNode = node; graphTreeView.Refresh(); } private void graphTreeView_KeyDown(object sender, KeyEventArgs e) { if ((e.KeyCode == Keys.Delete) && (graphTreeView.SelectedNode != null)) { IValueParameter opParam = GetOperatorParameterTag(graphTreeView.SelectedNode); if (opParam != null) opParam.Value = null; } } private void graphContextMenuStrip_Opening(object sender, CancelEventArgs e) { viewToolStripMenuItem.Enabled = false; breakpointToolStripMenuItem.Enabled = false; breakpointToolStripMenuItem.Checked = false; if (graphTreeView.SelectedNode != null) { IOperator op = GetOperatorTag(graphTreeView.SelectedNode); if (op != null) { IView view = MainFormManager.CreateDefaultView(op); if (view != null) { viewToolStripMenuItem.Enabled = true; viewToolStripMenuItem.Tag = view; } breakpointToolStripMenuItem.Enabled = true; breakpointToolStripMenuItem.Tag = op; if (op.Breakpoint) breakpointToolStripMenuItem.Checked = true; } } } private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) { TreeNode node = (TreeNode)e.Item; IValueParameter opParam = GetOperatorParameterTag(node); IOperator op = GetOperatorTag(node); DataObject data = new DataObject(); data.SetData("Type", op.GetType()); data.SetData("Value", op); if (opParam == null) { DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link); } else { DragDropEffects action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move); if ((action & DragDropEffects.Move) == DragDropEffects.Move) opParam.Value = null; } } private void graphTreeView_DragEnterOver(object sender, DragEventArgs e) { e.Effect = DragDropEffects.None; Type type = e.Data.GetData("Type") as Type; if ((type != null) && (typeof(IOperator).IsAssignableFrom(type))) { TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y))); if ((node != null) && !node.IsExpanded) node.Expand(); if ((node != null) && (GetOperatorParameterTag(node) != null)) { if ((e.KeyState & 8) == 8) e.Effect = DragDropEffects.Copy; // CTRL key else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move; // SHIFT key else if ((e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link) e.Effect = DragDropEffects.Link; else if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) e.Effect = DragDropEffects.Copy; else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) e.Effect = DragDropEffects.Move; } } } private void graphTreeView_DragDrop(object sender, DragEventArgs e) { if (e.Effect != DragDropEffects.None) { IOperator op = e.Data.GetData("Value") as IOperator; if ((e.Effect & DragDropEffects.Copy) == DragDropEffects.Copy) op = (IOperator)op.Clone(); TreeNode node = graphTreeView.GetNodeAt(graphTreeView.PointToClient(new Point(e.X, e.Y))); IValueParameter opParam = GetOperatorParameterTag(node); opParam.Value = op; } } #endregion #region Context Menu Events private void viewToolStripMenuItem_Click(object sender, EventArgs e) { IView view = ((ToolStripMenuItem)sender).Tag as IView; if (view != null) view.Show(); } private void breakpointToolStripMenuItem_Click(object sender, EventArgs e) { IOperator op = (IOperator)breakpointToolStripMenuItem.Tag; op.Breakpoint = breakpointToolStripMenuItem.Checked; } #endregion #region Helpers private class Tuple { public T1 Item1 { get; set; } public T2 Item2 { get; set; } public Tuple() { Item1 = default(T1); Item2 = default(T2); } public Tuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2; } } private IValueParameter GetOperatorParameterTag(TreeNode node) { if (node.Tag != null) return ((Tuple, IOperator>)node.Tag).Item1; else return null; } private void SetOperatorParameterTag(TreeNode node, IValueParameter opParam) { if (node.Tag == null) node.Tag = new Tuple, IOperator>(opParam, null); else ((Tuple, IOperator>)node.Tag).Item1 = opParam; } private IOperator GetOperatorTag(TreeNode node) { if (node.Tag != null) return ((Tuple, IOperator>)node.Tag).Item2; else return null; } private void SetOperatorTag(TreeNode node, IOperator op) { if (node.Tag == null) node.Tag = new Tuple, IOperator>(null, op); else ((Tuple, IOperator>)node.Tag).Item2 = op; } #endregion } }