#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.Linq; using System.Windows.Forms; using HeuristicLab.Collections; using HeuristicLab.MainForm; namespace HeuristicLab.Core.Views { /// /// The visual representation of an . /// [View("Operator View (Successors)")] [Content(typeof(IOperator), false)] public sealed partial class OperatorTreeView : ItemView { private Dictionary> 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; } } private IOperator selectedOperator; public IOperator SelectedOperator { get { return selectedOperator; } private set { if (value != selectedOperator) { selectedOperator = value; OnSelectedOperatorChanged(); } } } /// /// Initializes a new instance of with caption "Operator Graph". /// public OperatorTreeView() { InitializeComponent(); graphTreeView.Sorted = true; opParamNodeTable = new Dictionary>(); operatorNodeTable = new Dictionary>(); parametersOperatorTable = new Dictionary, IOperator>(); Caption = "Operator"; } /// /// 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]); Caption = "Operator"; if (Content != null) { Caption = Content.Name + " (" + Content.GetType().Name + ")"; TreeNode root = new TreeNode(); FillTreeNode(root, Content); graphTreeView.Nodes.Add(root); } SetEnabledStateOfControls(); } protected override void OnReadOnlyChanged() { base.OnReadOnlyChanged(); SetEnabledStateOfControls(); } private void SetEnabledStateOfControls() { graphTreeView.Enabled = Content != null; } public event EventHandler SelectedOperatorChanged; private void OnSelectedOperatorChanged() { if (SelectedOperatorChanged != null) SelectedOperatorChanged(this, EventArgs.Empty); } #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); FillTreeNode(node, (IOperator)opParam.Value); return node; } private void FillTreeNode(TreeNode node, IOperator op) { if (op == null) { node.Text += "-"; node.ToolTipText = ""; graphTreeView.ImageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.Nothing); node.ImageIndex = graphTreeView.ImageList.Images.Count - 1; node.SelectedImageIndex = node.ImageIndex; node.ForeColor = graphTreeView.ForeColor; } else { node.Text += op.Name; node.ToolTipText = op.ItemName + ": " + op.ItemDescription; graphTreeView.ImageList.Images.Add(op.ItemImage); node.ImageIndex = graphTreeView.ImageList.Images.Count - 1; node.SelectedImageIndex = node.ImageIndex; SetOperatorTag(node, op); if (!operatorNodeTable.ContainsKey(op)) { operatorNodeTable.Add(op, new List()); op.ItemImageChanged += new EventHandler(op_ItemImageChanged); 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; else node.ForeColor = graphTreeView.ForeColor; foreach (IValueParameter param in op.Parameters.OfType()) { if (typeof(IOperator).IsAssignableFrom(param.DataType)) node.Nodes.Add(new TreeNode()); } node.Collapse(); } } private void ClearTreeNode(TreeNode node) { while (node.Nodes.Count > 0) RemoveTreeNode(node.Nodes[0]); if (node.ImageIndex != -1) { int i = node.ImageIndex; CorrectImageIndexes(graphTreeView.Nodes, i); graphTreeView.ImageList.Images.RemoveAt(i); } IOperator op = GetOperatorTag(node); if (op != null) { operatorNodeTable[op].Remove(node); if (operatorNodeTable[op].Count == 0) { op.ItemImageChanged -= new EventHandler(op_ItemImageChanged); 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 (IValueParameter param in parameters.OfType()) { if (typeof(IOperator).IsAssignableFrom(param.DataType)) { foreach (TreeNode node in operatorNodeTable[op]) node.Nodes.Add(CreateTreeNode(param)); } } } private void RemoveParameterNodes(IEnumerable parameters) { foreach (IValueParameter param in parameters.OfType()) { if (typeof(IOperator).IsAssignableFrom(param.DataType)) { while (opParamNodeTable.ContainsKey(param)) RemoveTreeNode(opParamNodeTable[param][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 + ": "; FillTreeNode(node, (IOperator)opParam.Value); } } } void op_ItemImageChanged(object sender, EventArgs e) { if (InvokeRequired) Invoke(new EventHandler(op_ItemImageChanged), sender, e); else { IOperator op = (IOperator)sender; foreach (TreeNode node in operatorNodeTable[op]) { int i = node.ImageIndex; graphTreeView.ImageList.Images[i] = op.ItemImage; node.ImageIndex = -1; node.SelectedImageIndex = -1; node.ImageIndex = i; node.SelectedImageIndex = i; } } } 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 { IKeyedItemCollection coll = (IKeyedItemCollection)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); IKeyedItemCollection coll = (IKeyedItemCollection)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); IKeyedItemCollection coll = (IKeyedItemCollection)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 (IValueParameter param in op.Parameters.OfType()) { if (typeof(IOperator).IsAssignableFrom(param.DataType)) node.Nodes.Add(CreateTreeNode(param)); } } } 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 (!ReadOnly && (e.KeyCode == Keys.Delete) && (graphTreeView.SelectedNode != null)) { IValueParameter opParam = GetOperatorParameterTag(graphTreeView.SelectedNode); if (opParam != null) opParam.Value = null; } } private void graphTreeView_AfterSelect(object sender, TreeViewEventArgs e) { SelectedOperator = graphTreeView.SelectedNode == null ? null : GetOperatorTag(graphTreeView.SelectedNode); } 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) { Type viewType = MainFormManager.GetDefaultViewType(op.GetType()); if (viewType != null) { viewToolStripMenuItem.Enabled = true; viewToolStripMenuItem.Tag = op; } breakpointToolStripMenuItem.Enabled = true; breakpointToolStripMenuItem.Tag = op; if (op.Breakpoint) breakpointToolStripMenuItem.Checked = true; } } } private void graphTreeView_ItemDrag(object sender, ItemDragEventArgs e) { if (!Locked) { 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 (ReadOnly || (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 (!ReadOnly && (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) { IOperator op = ((ToolStripMenuItem)sender).Tag as IOperator; IContentView view = MainFormManager.MainForm.ShowContent(op); if (view != null) { view.ReadOnly = this.ReadOnly; view.Locked = this.Locked; } } 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)node.Tag).Item1; else return null; } private void SetOperatorParameterTag(TreeNode node, IValueParameter opParam) { if (node.Tag == null) node.Tag = new Tuple(opParam, null); else ((Tuple)node.Tag).Item1 = opParam; } private IOperator GetOperatorTag(TreeNode node) { if (node.Tag != null) return ((Tuple)node.Tag).Item2; else return null; } private void SetOperatorTag(TreeNode node, IOperator op) { if (node.Tag == null) node.Tag = new Tuple(null, op); else ((Tuple)node.Tag).Item2 = op; } private void CorrectImageIndexes(TreeNodeCollection nodes, int removedIndex) { foreach (TreeNode node in nodes) { if (node.ImageIndex > removedIndex) { node.ImageIndex--; node.SelectedImageIndex--; } CorrectImageIndexes(node.Nodes, removedIndex); } } #endregion } }