Changeset 9006


Ignore:
Timestamp:
12/06/12 13:52:01 (10 years ago)
Author:
bburlacu
Message:

#1763: Refactored the tree simplifier again: moved tree editing functionality into the view, fixed minor display bugs.

Location:
trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.Designer.cs

    r8980 r9006  
    5252      this.btnSimplify = new System.Windows.Forms.Button();
    5353      this.btnOptimizeConstants = new System.Windows.Forms.Button();
     54      this.grpViewHost = new System.Windows.Forms.GroupBox();
     55      this.treeStatusLabel = new System.Windows.Forms.Label();
     56      this.treeStatusValue = new System.Windows.Forms.Label();
    5457      this.treeChart = new HeuristicLab.Problems.DataAnalysis.Symbolic.Views.InteractiveSymbolicExpressionTreeChart();
    55       this.grpViewHost = new System.Windows.Forms.GroupBox();
    5658      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
    5759      this.splitContainer.Panel1.SuspendLayout();
     
    7476      this.viewHost.Name = "viewHost";
    7577      this.viewHost.ReadOnly = false;
    76       this.viewHost.Size = new System.Drawing.Size(335, 326);
     78      this.viewHost.Size = new System.Drawing.Size(336, 383);
    7779      this.viewHost.TabIndex = 0;
    7880      this.viewHost.ViewsLabelVisible = true;
     
    9294      //
    9395      this.splitContainer.Panel2.Controls.Add(this.grpViewHost);
    94       this.splitContainer.Size = new System.Drawing.Size(564, 348);
     96      this.splitContainer.Size = new System.Drawing.Size(565, 405);
    9597      this.splitContainer.SplitterDistance = 213;
    9698      this.splitContainer.TabIndex = 1;
     
    99101      //
    100102      this.grpSimplify.AutoSize = true;
     103      this.grpSimplify.Controls.Add(this.treeStatusValue);
    101104      this.grpSimplify.Controls.Add(this.flowLayoutPanel);
     105      this.grpSimplify.Controls.Add(this.treeStatusLabel);
    102106      this.grpSimplify.Controls.Add(this.treeChart);
    103107      this.grpSimplify.Dock = System.Windows.Forms.DockStyle.Fill;
    104108      this.grpSimplify.Location = new System.Drawing.Point(0, 0);
    105109      this.grpSimplify.Name = "grpSimplify";
    106       this.grpSimplify.Size = new System.Drawing.Size(213, 348);
     110      this.grpSimplify.Size = new System.Drawing.Size(213, 405);
    107111      this.grpSimplify.TabIndex = 1;
    108112      this.grpSimplify.TabStop = false;
     
    113117      this.flowLayoutPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
    114118            | System.Windows.Forms.AnchorStyles.Right)));
     119      this.flowLayoutPanel.Controls.Add(this.btnOptimizeConstants);
    115120      this.flowLayoutPanel.Controls.Add(this.btnSimplify);
    116       this.flowLayoutPanel.Controls.Add(this.btnOptimizeConstants);
    117       this.flowLayoutPanel.Location = new System.Drawing.Point(6, 313);
     121      this.flowLayoutPanel.Location = new System.Drawing.Point(6, 370);
    118122      this.flowLayoutPanel.Name = "flowLayoutPanel";
    119123      this.flowLayoutPanel.Size = new System.Drawing.Size(204, 29);
     
    123127      // btnSimplify
    124128      //
    125       this.btnSimplify.Location = new System.Drawing.Point(3, 3);
     129      this.btnSimplify.Location = new System.Drawing.Point(106, 3);
    126130      this.btnSimplify.Name = "btnSimplify";
    127131      this.btnSimplify.Size = new System.Drawing.Size(95, 23);
     
    135139      this.btnOptimizeConstants.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
    136140      this.btnOptimizeConstants.Enabled = false;
    137       this.btnOptimizeConstants.Location = new System.Drawing.Point(104, 3);
     141      this.btnOptimizeConstants.Location = new System.Drawing.Point(3, 3);
    138142      this.btnOptimizeConstants.Name = "btnOptimizeConstants";
    139143      this.btnOptimizeConstants.Size = new System.Drawing.Size(97, 23);
     
    143147      this.btnOptimizeConstants.Click += new System.EventHandler(this.btnOptimizeConstants_Click);
    144148      //
     149      // grpViewHost
     150      //
     151      this.grpViewHost.Controls.Add(this.viewHost);
     152      this.grpViewHost.Dock = System.Windows.Forms.DockStyle.Fill;
     153      this.grpViewHost.Location = new System.Drawing.Point(0, 0);
     154      this.grpViewHost.Name = "grpViewHost";
     155      this.grpViewHost.Size = new System.Drawing.Size(348, 405);
     156      this.grpViewHost.TabIndex = 1;
     157      this.grpViewHost.TabStop = false;
     158      this.grpViewHost.Text = "Details";
     159      //
     160      // treeStatusLabel
     161      //
     162      this.treeStatusLabel.AutoSize = true;
     163      this.treeStatusLabel.BackColor = System.Drawing.Color.Transparent;
     164      this.treeStatusLabel.Location = new System.Drawing.Point(6, 16);
     165      this.treeStatusLabel.Name = "treeStatusLabel";
     166      this.treeStatusLabel.Size = new System.Drawing.Size(68, 13);
     167      this.treeStatusLabel.TabIndex = 2;
     168      this.treeStatusLabel.Text = "Tree Status: ";
     169      //
     170      // treeStatusValue
     171      //
     172      this.treeStatusValue.AutoSize = true;
     173      this.treeStatusValue.BackColor = System.Drawing.Color.Transparent;
     174      this.treeStatusValue.ForeColor = System.Drawing.Color.Green;
     175      this.treeStatusValue.Location = new System.Drawing.Point(72, 16);
     176      this.treeStatusValue.Name = "treeStatusValue";
     177      this.treeStatusValue.Size = new System.Drawing.Size(30, 13);
     178      this.treeStatusValue.TabIndex = 3;
     179      this.treeStatusValue.Text = "Valid";
     180      //
    145181      // treeChart
    146182      //
     
    150186      this.treeChart.BackgroundColor = System.Drawing.Color.White;
    151187      this.treeChart.LineColor = System.Drawing.Color.Black;
    152       this.treeChart.Location = new System.Drawing.Point(6, 16);
     188      this.treeChart.Location = new System.Drawing.Point(6, 32);
     189      this.treeChart.ModifyTree = null;
    153190      this.treeChart.Name = "treeChart";
    154       this.treeChart.Size = new System.Drawing.Size(201, 291);
     191      this.treeChart.Size = new System.Drawing.Size(201, 332);
    155192      this.treeChart.Spacing = 5;
    156193      this.treeChart.SuspendRepaint = false;
     
    158195      this.treeChart.TextFont = new System.Drawing.Font("Times New Roman", 8F);
    159196      this.treeChart.Tree = null;
    160       this.treeChart.SymbolicExpressionTreeChanged += new System.EventHandler(this.treeChart_SymbolicExpressionTreeChanged);
     197      this.treeChart.SymbolicExpressionTreeNodeClicked += new System.Windows.Forms.MouseEventHandler(this.treeChart_SymbolicExpressionTreeNodeClicked);
    161198      this.treeChart.SymbolicExpressionTreeNodeDoubleClicked += new System.Windows.Forms.MouseEventHandler(this.treeChart_SymbolicExpressionTreeNodeDoubleClicked);
    162       //
    163       // grpViewHost
    164       //
    165       this.grpViewHost.Controls.Add(this.viewHost);
    166       this.grpViewHost.Dock = System.Windows.Forms.DockStyle.Fill;
    167       this.grpViewHost.Location = new System.Drawing.Point(0, 0);
    168       this.grpViewHost.Name = "grpViewHost";
    169       this.grpViewHost.Size = new System.Drawing.Size(347, 348);
    170       this.grpViewHost.TabIndex = 1;
    171       this.grpViewHost.TabStop = false;
    172       this.grpViewHost.Text = "Details";
    173199      //
    174200      // InteractiveSymbolicDataAnalysisSolutionSimplifierView
     
    179205      this.DoubleBuffered = true;
    180206      this.Name = "InteractiveSymbolicDataAnalysisSolutionSimplifierView";
    181       this.Size = new System.Drawing.Size(564, 348);
     207      this.Size = new System.Drawing.Size(565, 405);
    182208      this.splitContainer.Panel1.ResumeLayout(false);
    183209      this.splitContainer.Panel1.PerformLayout();
     
    186212      this.splitContainer.ResumeLayout(false);
    187213      this.grpSimplify.ResumeLayout(false);
     214      this.grpSimplify.PerformLayout();
    188215      this.flowLayoutPanel.ResumeLayout(false);
    189216      this.grpViewHost.ResumeLayout(false);
    190217      this.ResumeLayout(false);
     218
    191219    }
    192220
     
    201229    private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel;
    202230    protected System.Windows.Forms.Button btnOptimizeConstants;
     231    private System.Windows.Forms.Label treeStatusValue;
     232    private System.Windows.Forms.Label treeStatusLabel;
    203233  }
    204234}
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs

    r8990 r9006  
    3232namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
    3333  public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView {
    34     private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> replacementNodes;
     34    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes;
     35    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> changedNodes;
    3536    private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts;
     37    private enum TreeState { Valid, Invalid }
     38    private TreeState treeState;
    3639
    3740    public InteractiveSymbolicDataAnalysisSolutionSimplifierView() {
    3841      InitializeComponent();
    39       replacementNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     42      foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     43      changedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    4044      nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
    4145      this.Caption = "Interactive Solution Simplifier";
     46
     47      // initialize the tree modifier that will be used to perform edit operations over the tree
     48      treeChart.ModifyTree = Modify;
     49    }
     50
     51    /// <summary>
     52    /// Remove, Replace or Insert subtrees
     53    /// </summary>
     54    /// <param name="tree">The symbolic expression tree</param>
     55    /// <param name="node">The insertion point (the parent node who will receive a new child)</param>
     56    /// <param name="oldChild">The subtree to be replaced</param>
     57    /// <param name="newChild">The replacement subtree</param>
     58    /// <param name="removeSubtree">Flag used to indicate if whole subtrees should be removed (default behavior), or just the subtree root</param>
     59    private void Modify(ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode node, ISymbolicExpressionTreeNode oldChild, ISymbolicExpressionTreeNode newChild,
     60                        bool removeSubtree = true) {
     61      if (oldChild == null && newChild == null) throw new ArgumentException();
     62      if (oldChild == null) { // insertion operation
     63        node.AddSubtree(newChild);
     64        newChild.Parent = node;
     65        treeChart.Tree = tree; // because a new node is present in the tree, the visualNodes dictionary needs to be updated
     66      } else if (newChild == null) { // removal operation
     67        // use switch instead of if/else purely for aesthetical reasons (to avoid nested ifs and elses)
     68        switch (removeSubtree) {
     69          case true:
     70            // remove the whole subtree
     71            node.RemoveSubtree(node.IndexOfSubtree(oldChild));
     72            if (oldChild.SubtreeCount > 0)
     73              foreach (var subtree in oldChild.IterateNodesBreadth()) {
     74                changedNodes.Remove(subtree);
     75                foldedNodes.Remove(subtree);
     76              }
     77            break;
     78          case false:
     79            // only remove the current node and try to preserve its subtrees
     80            node.RemoveSubtree(node.IndexOfSubtree(oldChild));
     81            if (oldChild.SubtreeCount > 0)
     82              for (int i = oldChild.SubtreeCount - 1; i >= 0; --i) {
     83                var subtree = oldChild.GetSubtree(i);
     84                oldChild.RemoveSubtree(i);
     85                node.AddSubtree(subtree);
     86              }
     87            break;
     88        }
     89        changedNodes.Remove(oldChild);
     90        foldedNodes.Remove(oldChild);
     91      } else { // replacement operation
     92        var replacementIndex = node.IndexOfSubtree(oldChild);
     93        node.RemoveSubtree(replacementIndex);
     94        node.InsertSubtree(replacementIndex, newChild);
     95        newChild.Parent = node;
     96        if (changedNodes.ContainsKey(oldChild)) {
     97          changedNodes.Add(newChild, changedNodes[oldChild]); // so that on double click the original node is restored
     98          changedNodes.Remove(oldChild);
     99        } else {
     100          changedNodes.Add(newChild, oldChild);
     101        }
     102      }
     103
     104      if (IsValid(tree)) {
     105        treeState = TreeState.Valid;
     106        UpdateModel(Content.Model.SymbolicExpressionTree);
     107        btnOptimizeConstants.Enabled = true;
     108        btnSimplify.Enabled = true;
     109        treeStatusValue.Text = "Valid";
     110        treeStatusValue.ForeColor = Color.Green;
     111        this.Refresh();
     112      } else {
     113        treeState = TreeState.Invalid;
     114        btnOptimizeConstants.Enabled = true;
     115        btnSimplify.Enabled = true;
     116        treeStatusValue.Text = "Invalid";
     117        treeStatusValue.ForeColor = Color.Red;
     118        treeChart.Repaint();
     119        this.Refresh();
     120      }
     121      foreach (var changedNode in changedNodes.Keys) {
     122        var visualNode = treeChart.GetVisualSymbolicExpressionTreeNode(changedNode);
     123        visualNode.LineColor = Color.DodgerBlue;
     124        treeChart.RepaintNode(visualNode);
     125      }
     126    }
     127
     128    private static bool IsValid(ISymbolicExpressionTree tree) {
     129      return !tree.IterateNodesPostfix().Any(node => node.SubtreeCount < node.Symbol.MinimumArity || node.SubtreeCount > node.Symbol.MaximumArity);
    42130    }
    43131
     
    64152    protected override void OnContentChanged() {
    65153      base.OnContentChanged();
    66       replacementNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    67 
     154      foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    68155      UpdateView();
    69156      viewHost.Content = this.Content;
     
    77164      var replacementValues = CalculateReplacementValues(tree);
    78165      foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) {
    79         replacementNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
     166        foldedNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
    80167      }
    81168
     
    95182    }
    96183
     184    private void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
     185      var visualNode = (VisualSymbolicExpressionTreeNode)sender;
     186      if (visualNode == null) return;
     187      var treeNode = visualNode.SymbolicExpressionTreeNode;
     188      if (changedNodes.ContainsKey(treeNode)) {
     189        visualNode.LineColor = Color.DodgerBlue;
     190      } else if (treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) {
     191        visualNode.LineColor = Color.DarkOrange;
     192      } else {
     193        visualNode.LineColor = Color.Black;
     194      }
     195      visualNode.TextColor = Color.Black;
     196      treeChart.RepaintNode(visualNode);
     197    }
     198
    97199    private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
    98       if (!treeChart.TreeValid) return;
     200      if (treeState == TreeState.Invalid) return;
    99201      var visualNode = (VisualSymbolicExpressionTreeNode)sender;
    100202      var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.SymbolicExpressionTreeNode;
    101203      if (symbExprTreeNode == null) return;
    102       if (!replacementNodes.ContainsKey(symbExprTreeNode)) return;
    103 
    104204      var tree = Content.Model.SymbolicExpressionTree;
    105       int indexOfReplacementNode = symbExprTreeNode.Parent.IndexOfSubtree(symbExprTreeNode);
    106       SwitchNodeWithReplacementNode(symbExprTreeNode.Parent, indexOfReplacementNode);
    107       UpdateModel(tree);
    108     }
    109 
    110     private void treeChart_SymbolicExpressionTreeChanged(object sender, EventArgs e) {
    111       UpdateModel(Content.Model.SymbolicExpressionTree);
     205      var parent = symbExprTreeNode.Parent;
     206      int indexOfSubtree = parent.IndexOfSubtree(symbExprTreeNode);
     207      if (changedNodes.ContainsKey(symbExprTreeNode)) {
     208        parent.RemoveSubtree(indexOfSubtree);
     209        ISymbolicExpressionTreeNode originalNode = changedNodes[symbExprTreeNode];
     210        parent.InsertSubtree(indexOfSubtree, originalNode);
     211        changedNodes.Remove(symbExprTreeNode);
     212        UpdateModel(tree);
     213      } else if (foldedNodes.ContainsKey(symbExprTreeNode)) {
     214        SwitchNodeWithReplacementNode(parent, indexOfSubtree);
     215        UpdateModel(tree);
     216      }
    112217    }
    113218
     
    115220      ISymbolicExpressionTreeNode subTree = parent.GetSubtree(subTreeIndex);
    116221      parent.RemoveSubtree(subTreeIndex);
    117       if (replacementNodes.ContainsKey(subTree)) {
    118         var replacementNode = replacementNodes[subTree];
     222      if (foldedNodes.ContainsKey(subTree)) {
     223        var replacementNode = foldedNodes[subTree];
    119224        parent.InsertSubtree(subTreeIndex, replacementNode);
    120225        // exchange key and value
    121         replacementNodes.Remove(subTree);
    122         replacementNodes.Add(replacementNode, subTree);
     226        foldedNodes.Remove(subTree);
     227        foldedNodes.Add(replacementNode, subTree);
    123228      }
    124229    }
     
    147252          }
    148253          visualTree.ToolTip += Environment.NewLine + "Node impact: " + impact;
    149           var constantReplacementNode = replacementNodes[treeNode] as ConstantTreeNode;
     254          var constantReplacementNode = foldedNodes[treeNode] as ConstantTreeNode;
    150255          if (constantReplacementNode != null) {
    151256            visualTree.ToolTip += Environment.NewLine + "Replacement value: " + constantReplacementNode.Value;
    152257          }
    153258        }
    154         if (visualTree != null && treeNode is ConstantTreeNode && replacementNodes.ContainsKey(treeNode)) {
     259        if (visualTree != null && treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) {
    155260          visualTree.LineColor = Color.DarkOrange;
    156261        }
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.Designer.cs

    r8991 r9006  
    5454      this.removeSubtreeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    5555      this.pasteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    56       this.treeStatusLabel = new System.Windows.Forms.Label();
    57       this.treeStatusValue = new System.Windows.Forms.Label();
    5856      this.toolStripSeparator = new System.Windows.Forms.ToolStripSeparator();
    5957      this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
     
    6361      //
    6462      this.insertNodeToolStripMenuItem.Name = "insertNodeToolStripMenuItem";
    65       this.insertNodeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     63      this.insertNodeToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
    6664      this.insertNodeToolStripMenuItem.Text = "Insert Node";
    6765      this.insertNodeToolStripMenuItem.Click += new System.EventHandler(this.insertNodeToolStripMenuItem_Click);
     
    6967      // changeNodeToolStripMenuItem
    7068      //
    71       this.changeNodeToolStripMenuItem.Name = "editNodeToolStripMenuItem";
    72       this.changeNodeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     69      this.changeNodeToolStripMenuItem.Name = "changeNodeToolStripMenuItem";
     70      this.changeNodeToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
    7371      this.changeNodeToolStripMenuItem.Text = "Change Node";
    7472      this.changeNodeToolStripMenuItem.Click += new System.EventHandler(this.changeNodeToolStripMenuItem_Click);
    75       //
    76       // copyToolStripMenuItem
    77       //
    78       this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
    79       this.copyToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
    80       this.copyToolStripMenuItem.Text = "Copy";
    81       this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
    8273      //
    8374      // cutToolStripMenuItem
    8475      //
    8576      this.cutToolStripMenuItem.Name = "cutToolStripMenuItem";
    86       this.cutToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     77      this.cutToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
    8778      this.cutToolStripMenuItem.Text = "Cut";
    8879      this.cutToolStripMenuItem.Click += new System.EventHandler(this.cutToolStripMenuItem_Click);
     
    9485            this.removeSubtreeToolStripMenuItem});
    9586      this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
    96       this.removeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     87      this.removeToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
    9788      this.removeToolStripMenuItem.Text = "Remove";
    9889      this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeSubtreeToolStripMenuItem_Click);
     
    10192      //
    10293      this.removeNodeToolStripMenuItem.Name = "removeNodeToolStripMenuItem";
    103       this.removeNodeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     94      this.removeNodeToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
    10495      this.removeNodeToolStripMenuItem.Text = "Node";
    10596      this.removeNodeToolStripMenuItem.Click += new System.EventHandler(this.removeNodeToolStripMenuItem_Click);
     
    10899      //
    109100      this.removeSubtreeToolStripMenuItem.Name = "removeSubtreeToolStripMenuItem";
    110       this.removeSubtreeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     101      this.removeSubtreeToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
    111102      this.removeSubtreeToolStripMenuItem.Text = "Subtree";
    112103      this.removeSubtreeToolStripMenuItem.Click += new System.EventHandler(this.removeSubtreeToolStripMenuItem_Click);
     
    115106      //
    116107      this.pasteToolStripMenuItem.Name = "pasteToolStripMenuItem";
    117       this.pasteToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     108      this.pasteToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
    118109      this.pasteToolStripMenuItem.Text = "Paste";
    119110      this.pasteToolStripMenuItem.Click += new System.EventHandler(this.pasteToolStripMenuItem_Clicked);
    120       //
    121       // contextMenuStrip
    122       //
    123       this.contextMenuStrip.Opened += this.contextMenuStrip_Opened;
    124       this.contextMenuStrip.Items.AddRange(new ToolStripItem[] { insertNodeToolStripMenuItem,
    125                                                                  changeNodeToolStripMenuItem,
    126                                                                  copyToolStripMenuItem,
    127                                                                  cutToolStripMenuItem,
    128                                                                  removeToolStripMenuItem,
    129                                                                  pasteToolStripMenuItem });
    130       //
    131       // treeStatusLabel
    132       //
    133       this.treeStatusLabel.AutoSize = true;
    134       this.treeStatusLabel.BackColor = System.Drawing.Color.Transparent;
    135       this.treeStatusLabel.Location = new System.Drawing.Point(3, 0);
    136       this.treeStatusLabel.Name = "treeStatusLabel";
    137       this.treeStatusLabel.Size = new System.Drawing.Size(68, 13);
    138       this.treeStatusLabel.TabIndex = 0;
    139       this.treeStatusLabel.Text = "Tree Status: ";
    140       //
    141       // treeStatusValue
    142       //
    143       this.treeStatusValue.AutoSize = true;
    144       this.treeStatusValue.BackColor = System.Drawing.Color.Transparent;
    145       this.treeStatusValue.ForeColor = System.Drawing.Color.Green;
    146       this.treeStatusValue.Location = new System.Drawing.Point(77, 0);
    147       this.treeStatusValue.Name = "treeStatusValue";
    148       this.treeStatusValue.Size = new System.Drawing.Size(30, 13);
    149       this.treeStatusValue.TabIndex = 1;
    150       this.treeStatusValue.Text = "Valid";
    151111      //
    152112      // toolStripSeparator
     
    155115      this.toolStripSeparator.Size = new System.Drawing.Size(149, 6);
    156116      //
     117      // copyToolStripMenuItem
     118      //
     119      this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
     120      this.copyToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
     121      this.copyToolStripMenuItem.Text = "Copy";
     122      this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
     123      //
     124      // contextMenuStrip
     125      //
     126      this.contextMenuStrip.Opened += this.contextMenuStrip_Opened;
     127      this.contextMenuStrip.Items.AddRange(new ToolStripItem[] { insertNodeToolStripMenuItem,
     128                                                                 changeNodeToolStripMenuItem,
     129                                                                 copyToolStripMenuItem,
     130                                                                 cutToolStripMenuItem,
     131                                                                 removeToolStripMenuItem,
     132                                                                 pasteToolStripMenuItem });
     133      //
    157134      // InteractiveSymbolicExpressionTreeChart
    158135      //
    159136      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    160137      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    161       this.Controls.Add(this.treeStatusLabel);
    162       this.Controls.Add(this.treeStatusValue);
    163138      this.DoubleBuffered = true;
    164139      this.Name = "InteractiveSymbolicExpressionTreeChart";
    165       this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.InteractiveSymbolicExpressionTreeChart_MouseClick);
    166140      this.ResumeLayout(false);
    167       this.PerformLayout();
    168141
    169142    }
     
    178151
    179152    #endregion
    180     private Label treeStatusLabel;
    181     private Label treeStatusValue;
     153
    182154    private ToolStripSeparator toolStripSeparator;
    183155    private ToolStripMenuItem copyToolStripMenuItem;
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs

    r8991 r9006  
    2121
    2222using System;
    23 using System.Collections.Generic;
    2423using System.Drawing;
    2524using System.Linq;
     
    2928
    3029namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
    31   public sealed partial class InteractiveSymbolicExpressionTreeChart : SymbolicExpressionTreeChart {
     30  internal delegate void
     31  ModifyTree(ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode node, ISymbolicExpressionTreeNode oldChild, ISymbolicExpressionTreeNode newChild,
     32             bool removeSubtree = true);
     33
     34  internal sealed partial class InteractiveSymbolicExpressionTreeChart : SymbolicExpressionTreeChart {
    3235    private ISymbolicExpressionTreeNode tempNode; // node in clipboard (to be cut/copy/pasted etc)
    3336    private VisualSymbolicExpressionTreeNode currSelected; // currently selected node
    34     private enum EditOp { NoOp, CopyNode, CopySubtree, CutNode, CutSubtree, RemoveNode, RemoveSubtree }
    35     private enum TreeState { Valid, Invalid }
     37    public enum EditOp { NoOp, CopySubtree, CutSubtree, ChangeNode, InsertNode, InsertSubtree, RemoveNode, RemoveSubtree }
    3638    private EditOp lastOp = EditOp.NoOp;
    37     private TreeState treeState = TreeState.Valid; // tree edit operations must leave the tree in a valid state
    38 
    39     private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> originalNodes; // map a new node to the original node it replaced
     39
     40    // delegate to notify the parent container (the view) about the tree edit operations that it needs to perform
     41    public ModifyTree ModifyTree { get; set; }
    4042
    4143    public InteractiveSymbolicExpressionTreeChart() {
     
    4345      currSelected = null;
    4446      tempNode = null;
    45 
    46       originalNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    47     }
    48 
    49     public bool TreeValid { get { return TreeState.Valid == treeState; } }
    50     // expose an additional event for signaling to the parent view when the tree structure was modified
    51     // the emitting of the signal is conditional on the tree being valid, otherwise only a Repaint is issued
    52     public event EventHandler SymbolicExpressionTreeChanged;
    53     private void OnSymbolicExpressionTreeChanged(object sender, EventArgs e) {
    54       if (IsValid(Tree)) {
    55         treeStatusValue.Text = "Valid";
    56         treeStatusValue.ForeColor = Color.Green;
    57         treeState = TreeState.Valid;
    58         var changed = SymbolicExpressionTreeChanged;
    59         if (changed != null)
    60           changed(sender, e);
    61       } else {
    62         treeStatusValue.Text = "Invalid";
    63         treeStatusValue.ForeColor = Color.Red;
    64         treeState = TreeState.Invalid;
    65         Tree = Tree; // reinitialize the dictionaries and repaint
    66       }
    67       foreach (var node in originalNodes.Keys) {
    68         var visualNode = GetVisualSymbolicExpressionTreeNode(node);
    69         if (visualNode == null) continue;
    70         visualNode.LineColor = Color.DodgerBlue;
    71         RepaintNode(visualNode);
    72       }
    7347    }
    7448
     
    7751      var point = menuStrip.SourceControl.PointToClient(Cursor.Position);
    7852      var ea = new MouseEventArgs(MouseButtons.Left, 1, point.X, point.Y, 0);
    79       InteractiveSymbolicExpressionTreeChart_MouseClick(null, ea);
     53      var visualNode = FindVisualSymbolicExpressionTreeNodeAt(ea.X, ea.Y);
     54      if (visualNode != null) { OnSymbolicExpressionTreeNodeClicked(visualNode, ea); };
    8055
    8156      if (currSelected == null) {
     
    10378      var visualTreeNode = (VisualSymbolicExpressionTreeNode)sender;
    10479      var lastSelected = currSelected;
    105       if (lastSelected != null) {
    106         lastSelected.LineColor = originalNodes.ContainsKey(lastSelected.SymbolicExpressionTreeNode) ? Color.DodgerBlue : Color.Black;
    107         RepaintNode(lastSelected);
    108       }
    109 
    11080      currSelected = visualTreeNode;
    11181      if (currSelected != null) {
     
    11383        RepaintNode(currSelected);
    11484      }
     85      if (lastSelected != null)
     86        base.OnSymbolicExpressionTreeNodeClicked(lastSelected, e);
    11587    }
    11688
    11789    protected override void OnSymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
    118       var visualTreeNode = (VisualSymbolicExpressionTreeNode)sender;
    119       if (originalNodes.ContainsKey(visualTreeNode.SymbolicExpressionTreeNode)) {
    120         var originalNode = originalNodes[visualTreeNode.SymbolicExpressionTreeNode];
    121 
    122         var parent = visualTreeNode.SymbolicExpressionTreeNode.Parent;
    123         var i = parent.IndexOfSubtree(visualTreeNode.SymbolicExpressionTreeNode);
    124         parent.RemoveSubtree(i);
    125         parent.InsertSubtree(i, originalNode);
    126 
    127         originalNodes.Remove(visualTreeNode.SymbolicExpressionTreeNode);
    128         visualTreeNode.SymbolicExpressionTreeNode = originalNode;
    129         OnSymbolicExpressionTreeChanged(sender, EventArgs.Empty);
    130       } else {
    131         currSelected = null; // because the tree node will be folded/unfolded
    132         base.OnSymbolicExpressionTreeNodeDoubleClicked(sender, e);
    133         // at this point the tree got redrawn, so we mark the edited nodes
    134         foreach (var node in originalNodes.Keys) {
    135           var visualNode = GetVisualSymbolicExpressionTreeNode(node);
    136           if (visualNode == null) continue;
    137           visualNode.LineColor = Color.DodgerBlue;
    138           RepaintNode(visualNode);
    139         }
    140       }
     90      currSelected = null;
     91      base.OnSymbolicExpressionTreeNodeDoubleClicked(sender, e);
    14192    }
    14293
     
    14899        dialog.SetAllowedSymbols(parent.Grammar.AllowedSymbols.Where(s => s.Enabled && s.InitialFrequency > 0.0 && !(s is ProgramRootSymbol || s is StartSymbol || s is Defun)));
    149100        dialog.ShowDialog(this);
    150 
    151         if (dialog.DialogResult == DialogResult.OK) {
    152           var symbol = dialog.SelectedSymbol();
    153           var node = symbol.CreateTreeNode();
    154           if (node is ConstantTreeNode) {
    155             var constant = node as ConstantTreeNode;
    156             constant.Value = double.Parse(dialog.constantValueTextBox.Text);
    157           } else if (node is VariableTreeNode) {
    158             var variable = node as VariableTreeNode;
    159             variable.Weight = double.Parse(dialog.variableWeightTextBox.Text);
    160             variable.VariableName = dialog.variableNamesCombo.Text;
    161           } else {
    162             if (node.Symbol.MinimumArity <= parent.SubtreeCount && node.Symbol.MaximumArity >= parent.SubtreeCount) {
    163               for (int i = parent.SubtreeCount - 1; i >= 0; --i) {
    164                 var child = parent.GetSubtree(i);
    165                 parent.RemoveSubtree(i);
    166                 node.AddSubtree(child);
    167               }
    168             }
    169           }
    170           if (parent.Symbol.MaximumArity > parent.SubtreeCount) {
    171             parent.AddSubtree(node);
    172             Tree = Tree;
    173           }
    174           OnSymbolicExpressionTreeChanged(sender, e);
    175           currSelected = null;
    176         }
    177       }
     101        if (dialog.DialogResult != DialogResult.OK) return;
     102
     103        var symbol = dialog.SelectedSymbol();
     104        var node = symbol.CreateTreeNode();
     105        if (node is ConstantTreeNode) {
     106          var constant = node as ConstantTreeNode;
     107          constant.Value = double.Parse(dialog.constantValueTextBox.Text);
     108        } else if (node is VariableTreeNode) {
     109          var variable = node as VariableTreeNode;
     110          variable.Weight = double.Parse(dialog.variableWeightTextBox.Text);
     111          variable.VariableName = dialog.variableNamesCombo.Text;
     112        } else if (node.Symbol.MinimumArity <= parent.SubtreeCount && node.Symbol.MaximumArity >= parent.SubtreeCount) {
     113          for (int i = parent.SubtreeCount - 1; i >= 0; --i) {
     114            var child = parent.GetSubtree(i);
     115            parent.RemoveSubtree(i);
     116            node.AddSubtree(child);
     117          }
     118        }
     119        // the if condition will always be true for the final else clause above
     120        if (parent.Symbol.MaximumArity > parent.SubtreeCount) {
     121          ModifyTree(Tree, parent, null, node);
     122        }
     123      }
     124      currSelected = null;
    178125    }
    179126
     
    181128      if (currSelected == null) return;
    182129
    183       ISymbolicExpressionTreeNode node;
    184       if (originalNodes.ContainsKey(currSelected.SymbolicExpressionTreeNode)) {
    185         node = currSelected.SymbolicExpressionTreeNode;
    186       } else {
    187         node = (ISymbolicExpressionTreeNode)currSelected.SymbolicExpressionTreeNode.Clone();
    188       }
     130      var node = (ISymbolicExpressionTreeNode)currSelected.SymbolicExpressionTreeNode.Clone();
    189131      var originalNode = currSelected.SymbolicExpressionTreeNode;
     132
    190133      ISymbolicExpressionTreeNode newNode = null;
    191134      var result = DialogResult.Cancel;
     
    204147      }
    205148      if (result != DialogResult.OK) return;
    206       if (originalNode != newNode) {
    207         var parent = originalNode.Parent;
    208         int i = parent.IndexOfSubtree(originalNode);
    209         parent.RemoveSubtree(i);
    210         parent.InsertSubtree(i, newNode);
    211         originalNodes[newNode] = originalNode;
    212         currSelected.SymbolicExpressionTreeNode = newNode;
    213       }
    214       OnSymbolicExpressionTreeChanged(sender, EventArgs.Empty);
     149      ModifyTree(Tree, originalNode.Parent, originalNode, newNode); // this will replace the original node with the new node
     150      currSelected = null;
    215151    }
    216152
    217153    private void cutToolStripMenuItem_Click(object sender, EventArgs e) {
    218154      lastOp = EditOp.CutSubtree;
     155      if (tempNode != null) {
     156        foreach (var subtree in tempNode.IterateNodesBreadth()) {
     157          var vNode = GetVisualSymbolicExpressionTreeNode(subtree);
     158          base.OnSymbolicExpressionTreeNodeClicked(vNode, null);
     159          if (subtree.Parent != null) {
     160            var vArc = GetVisualSymbolicExpressionTreeNodeConnection(subtree.Parent, subtree);
     161            vArc.LineColor = Color.Black;
     162          }
     163        }
     164      }
    219165      tempNode = currSelected.SymbolicExpressionTreeNode;
    220166      foreach (var node in tempNode.IterateNodesPostfix()) {
     
    229175        }
    230176      }
     177      currSelected = null;
    231178      Repaint();
    232179    }
    233 
    234180    private void copyToolStripMenuItem_Click(object sender, EventArgs e) {
    235181      lastOp = EditOp.CopySubtree;
     182      if (tempNode != null) {
     183        foreach (var subtree in tempNode.IterateNodesBreadth()) {
     184          var vNode = GetVisualSymbolicExpressionTreeNode(subtree);
     185          base.OnSymbolicExpressionTreeNodeClicked(vNode, null);
     186          if (subtree.Parent != null) {
     187            var vArc = GetVisualSymbolicExpressionTreeNodeConnection(subtree.Parent, subtree);
     188            vArc.LineColor = Color.Black;
     189          }
     190        }
     191      }
    236192      tempNode = currSelected.SymbolicExpressionTreeNode;
    237193      foreach (var node in tempNode.IterateNodesPostfix()) {
     
    245201        }
    246202      }
     203      currSelected = null;
    247204      Repaint();
    248205    }
    249 
    250206    private void removeNodeToolStripMenuItem_Click(object sender, EventArgs e) {
    251207      lastOp = EditOp.RemoveNode;
    252208      var node = currSelected.SymbolicExpressionTreeNode;
    253       var parent = node.Parent;
    254       if (parent == null || parent.Symbol is StartSymbol || parent.Symbol is ProgramRootSymbol)
    255         return; // the operation would result in the deletion of the entire tree
    256       if (parent.Symbol.MaximumArity >= node.SubtreeCount + parent.SubtreeCount - 1) { // -1 because tempNode will be removed
    257         parent.RemoveSubtree(parent.IndexOfSubtree(node));
    258         for (int i = node.SubtreeCount - 1; i >= 0; --i) {
    259           var child = node.GetSubtree(i);
    260           node.RemoveSubtree(i);
    261           parent.AddSubtree(child);
    262         }
    263       }
    264       OnSymbolicExpressionTreeChanged(sender, e);
     209      ModifyTree(Tree, node.Parent, node, null, removeSubtree: false);
    265210      currSelected = null; // because the currently selected node was just deleted
    266211    }
    267 
    268212    private void removeSubtreeToolStripMenuItem_Click(object sender, EventArgs e) {
    269       lastOp = EditOp.RemoveSubtree;
     213      lastOp = EditOp.RemoveNode;
    270214      var node = currSelected.SymbolicExpressionTreeNode;
    271       var parent = node.Parent;
    272       if (parent == null || parent.Symbol is StartSymbol || parent.Symbol is ProgramRootSymbol)
    273         return; // the operation makes no sense as it would result in the deletion of the entire tree
    274       parent.RemoveSubtree(parent.IndexOfSubtree(node));
    275       OnSymbolicExpressionTreeChanged(sender, e);
     215      ModifyTree(Tree, node.Parent, node, null, removeSubtree: true);
    276216      currSelected = null; // because the currently selected node was just deleted
    277     }
    278 
     217      contextMenuStrip.Close(); // avoid display of submenus since the action has already been performed
     218    }
    279219    private void pasteToolStripMenuItem_Clicked(object sender, EventArgs e) {
    280       if (!(lastOp == EditOp.CopyNode || lastOp == EditOp.CopySubtree || lastOp == EditOp.CutNode || lastOp == EditOp.CutSubtree))
    281         return;
     220      if (!(lastOp == EditOp.CopySubtree || lastOp == EditOp.CutSubtree)) return;
    282221      // check if the copied/cut node (stored in the tempNode) can be inserted as a child of the current selected node
    283222      var node = currSelected.SymbolicExpressionTreeNode;
     
    285224      // check if the currently selected node can accept the copied node as a child
    286225      // no need to check the grammar, an arity check will do just fine here
    287       if (node.Symbol.MaximumArity > node.SubtreeCount) {
    288         switch (lastOp) {
    289           case (EditOp.CutNode): {
    290               // when cutting a node from the tree, it's children become children of it's parent
    291               var parent = tempNode.Parent;
    292               // arity checks to see if parent can accept node's children (we assume the grammar is already ok with that)
    293               // (otherise, the 'cut' part of the operation will just not do anything)
    294               if (parent.Symbol.MaximumArity >= tempNode.SubtreeCount + parent.SubtreeCount - 1) { // -1 because tempNode will be removed
    295                 parent.RemoveSubtree(parent.IndexOfSubtree(tempNode));
    296                 for (int i = tempNode.SubtreeCount - 1; i >= 0; --i) {
    297                   var child = tempNode.GetSubtree(i);
    298                   tempNode.RemoveSubtree(i);
    299                   parent.AddSubtree(child);
    300                 }
    301                 lastOp = EditOp.CopyNode;
    302               }
    303               break;
    304             }
    305           case (EditOp.CutSubtree): {
    306               // cut subtree
    307               var parent = tempNode.Parent;
    308               parent.RemoveSubtree(parent.IndexOfSubtree(tempNode));
    309               lastOp = EditOp.CopySubtree; // do this so the next paste will actually perform a copy   
    310               break;
    311             }
    312           case (EditOp.CopyNode): {
    313               // copy node
    314               var clone = (SymbolicExpressionTreeNode)tempNode.Clone();
    315               clone.Parent = tempNode.Parent;
    316               tempNode = clone;
    317               for (int i = tempNode.SubtreeCount - 1; i >= 0; --i) tempNode.RemoveSubtree(i);
    318               break;
    319             }
    320           case (EditOp.CopySubtree): {
    321               // copy subtree
    322               var clone = (SymbolicExpressionTreeNode)tempNode.Clone();
    323               clone.Parent = tempNode.Parent;
    324               tempNode = clone;
    325               break;
    326             }
    327         }
    328         node.AddSubtree(tempNode);
    329         Tree = Tree; // hack in order to trigger the reinitialization of the dictionaries after new nodes appeared in the tree
    330         OnSymbolicExpressionTreeChanged(sender, e);
    331         currSelected = null; // because the tree changed and was completely redrawn
    332       }
    333     }
    334 
    335     private bool IsValid(ISymbolicExpressionTree tree) {
    336       if (tree.IterateNodesPostfix().Any(node => node.SubtreeCount < node.Symbol.MinimumArity || node.SubtreeCount > node.Symbol.MaximumArity)) {
    337         treeState = TreeState.Invalid;
    338         return false;
    339       }
    340       treeState = TreeState.Valid;
    341       return true;
    342     }
    343 
    344     private void InteractiveSymbolicExpressionTreeChart_MouseClick(object sender, MouseEventArgs e) {
    345       var visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
    346       if (currSelected != null) {
    347         currSelected.LineColor = originalNodes.ContainsKey(currSelected.SymbolicExpressionTreeNode) ? Color.DodgerBlue : Color.Black;
    348         RepaintNode(currSelected);
    349       }
    350       currSelected = visualTreeNode;
    351       if (currSelected != null) {
    352         currSelected.LineColor = Color.LightGreen;
    353         RepaintNode(currSelected);
    354       }
     226      if (node.Symbol.MaximumArity <= node.SubtreeCount) return;
     227      switch (lastOp) {
     228        case EditOp.CutSubtree: {
     229            ModifyTree(Tree, tempNode.Parent, tempNode, null); //remove node from its original parent
     230            ModifyTree(Tree, node, null, tempNode);//insert it as a child to the new parent
     231            lastOp = EditOp.CopySubtree; //do this so the next paste will actually perform a copy   
     232            break;
     233          }
     234        case EditOp.CopySubtree: {
     235            var clone = (SymbolicExpressionTreeNode)tempNode.Clone();
     236            clone.Parent = tempNode.Parent;
     237            tempNode = clone;
     238            ModifyTree(Tree, node, null, tempNode);
     239            break;
     240          }
     241      }
     242      currSelected = null; // because the tree will have changed
    355243    }
    356244  }
Note: See TracChangeset for help on using the changeset viewer.