Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GP.Grammar.Editor/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarEditorView.cs @ 6403

Last change on this file since 6403 was 6403, checked in by mkommend, 13 years ago

#1479: Allowed modificiation of the subtree count in grammars and adapted SymbolicExpressionTreeChart to handle different styles for connection lines.

File size: 21.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core.Views;
30using HeuristicLab.MainForm;
31using HeuristicLab.PluginInfrastructure;
32
33namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
34  [View("Symbolic Expression Grammar Editor")]
35  [Content(typeof(ISymbolicExpressionGrammar), false)]
36  public partial class SymbolicExpressionGrammarEditorView : NamedItemView {
37    private ObservableList<ISymbolicExpressionTreeNode> selectedSymbolicExpressionTreeNodes;
38
39    public SymbolicExpressionGrammarEditorView() {
40      InitializeComponent();
41      selectedSymbolicExpressionTreeNodes = new ObservableList<ISymbolicExpressionTreeNode>();
42    }
43
44    public override bool ReadOnly {
45      get {
46        if ((Content != null) && Content.ReadOnly) return true;
47        return base.ReadOnly;
48      }
49      set {
50        if ((Content != null) && Content.ReadOnly) base.ReadOnly = true;
51        else base.ReadOnly = value;
52      }
53    }
54
55    public new ISymbolicExpressionGrammar Content {
56      get { return (ISymbolicExpressionGrammar)base.Content; }
57      set { base.Content = value; }
58    }
59
60    #region events
61    protected override void RegisterContentEvents() {
62      base.RegisterContentEvents();
63      Content.ReadOnlyChanged += new System.EventHandler(Content_ReadOnlyChanged);
64      Content.Changed += new System.EventHandler(Content_Changed);
65    }
66    protected override void DeregisterContentEvents() {
67      Content.ReadOnlyChanged -= new System.EventHandler(Content_ReadOnlyChanged);
68      Content.Changed -= new System.EventHandler(Content_Changed);
69      base.DeregisterContentEvents();
70    }
71
72    private void Content_ReadOnlyChanged(object sender, EventArgs e) {
73      ReadOnly = Content.ReadOnly;
74    }
75
76    private void Content_Changed(object sender, EventArgs e) {
77      ISymbol symbol = null;
78      if (symbolsTreeView.SelectedNode != null)
79        symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
80
81      RebuildSymbolsTreeView();
82      if (symbol != null && Content.ContainsSymbol(symbol)) {
83        BuildAllowedChildSymbolsTree(symbol);
84        symbolDetailsViewHost.Content = symbol;
85        symbolsTreeView.SelectedNode = IterateSymbolTreeNodes().Where(n => n.Tag == symbol).ToList().FirstOrDefault();
86      }
87    }
88    #endregion
89
90    protected override void SetEnabledStateOfControls() {
91      base.SetEnabledStateOfControls();
92    }
93
94    protected override void OnContentChanged() {
95      base.OnContentChanged();
96      if (Content != null) {
97        RebuildSymbolsTreeView();
98        allowedChildSymbolsControl.Tree = null;
99        symbolDetailsViewHost.Content = null;
100      } else {
101        symbolsTreeView.Nodes.Clear();
102        allowedChildSymbolsControl.Tree = null;
103        symbolDetailsViewHost.Content = null;
104      }
105    }
106
107    private void AddChildTreeNodes(TreeNodeCollection collection, IEnumerable<ISymbol> symbols) {
108      foreach (ISymbol symbol in symbols) {
109        var node = new TreeNode();
110        node.Name = symbol.Name;
111        node.Text = symbol.Name;
112        node.Tag = symbol;
113        node.Checked = symbol.Enabled;
114        collection.Add(node);
115        var groupSymbol = symbol as GroupSymbol;
116        if (groupSymbol != null) AddChildTreeNodes(node.Nodes, groupSymbol.Symbols);
117      }
118    }
119
120    private void symbolsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
121      if (e.Action != TreeViewAction.Unknown) {
122        var symbol = (ISymbol)e.Node.Tag;
123        symbolDetailsViewHost.Content = symbol;
124        selectedSymbolicExpressionTreeNodes.Clear();
125        BuildAllowedChildSymbolsTree(symbol);
126      }
127      removeButton.Enabled = symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol);
128    }
129
130    private void symbolsTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
131      if (e.Action != TreeViewAction.Unknown) {
132        DeregisterContentEvents();
133        var symbol = (ISymbol)e.Node.Tag;
134        symbol.Enabled = e.Node.Checked;
135        foreach (var node in IterateSymbolTreeNodes())
136          node.Checked = ((ISymbol)node.Tag).Enabled;
137
138        if (symbolsTreeView.SelectedNode != null) {
139          symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
140          selectedSymbolicExpressionTreeNodes.Clear();
141          BuildAllowedChildSymbolsTree(symbol);
142        }
143        RegisterContentEvents();
144      }
145    }
146
147    private void RebuildSymbolsTreeView() {
148      symbolsTreeView.Nodes.Clear();
149      var symbols = Content.Symbols.ToList();
150      var groupSymbols = symbols.OfType<GroupSymbol>().ToList();
151      var topLevelSymbols = Content.Symbols.Where(s => !groupSymbols.Any(g => g.Symbols.Contains(s)));
152      AddChildTreeNodes(symbolsTreeView.Nodes, topLevelSymbols);
153
154      RebuildImageList();
155      symbolsTreeView.ExpandAll();
156    }
157
158    private void BuildAllowedChildSymbolsTree(ISymbol symbol) {
159      var tree = new SymbolicExpressionTree(new SymbolicExpressionTreeNode(symbol));
160
161      allowedChildSymbolsControl.SuspendRepaint = true;
162      if (Content.GetMaximumSubtreeCount(symbol) > 0) {
163        for (int i = 0; i < Content.GetMaximumSubtreeCount(symbol); i++) {
164          var node = new DummySymbol("Subtree " + i).CreateTreeNode();
165          foreach (var childSymbol in Content.GetAllowedChildSymbols(symbol, i)) {
166            node.AddSubtree(new SymbolicExpressionTreeNode(childSymbol));
167          }
168          tree.Root.AddSubtree(node);
169        }
170      }
171      allowedChildSymbolsControl.Tree = tree;
172
173      foreach (var subtreeNode in tree.Root.Subtrees) {
174        foreach (var allowedChildNode in subtreeNode.Subtrees) {
175          var visualLine = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNodeConnection(subtreeNode, allowedChildNode);
176          visualLine.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
177        }
178      }
179
180      for (int i = Content.GetMinimumSubtreeCount(symbol); i < Content.GetMaximumSubtreeCount(symbol); i++) {
181        var subtreeNode = tree.Root.GetSubtree(i);
182        var visualTreeNode = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNode(subtreeNode);
183        visualTreeNode.TextColor = Color.Gray;
184        visualTreeNode.LineColor = Color.LightGray;
185
186        var visualLine = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNodeConnection(tree.Root, subtreeNode);
187        visualLine.LineColor = Color.LightGray;
188
189        foreach (var allowedChildNode in subtreeNode.Subtrees) {
190          visualTreeNode = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNode(allowedChildNode);
191          visualTreeNode.TextColor = Color.Gray;
192          visualTreeNode.LineColor = Color.LightGray;
193
194          visualLine = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNodeConnection(subtreeNode, allowedChildNode);
195          visualLine.LineColor = Color.LightGray;
196        }
197      }
198
199      allowedChildSymbolsControl.SuspendRepaint = false;
200      allowedChildSymbolsControl.Repaint();
201      UpdateSelectedSymbolicExpressionTreeNodes();
202    }
203
204    private void symbolicExpressionTreeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
205      if ((Control.ModifierKeys & Keys.Control) == 0)
206        selectedSymbolicExpressionTreeNodes.Clear();
207
208      VisualSymbolicExpressionTreeNode clickedNode = (VisualSymbolicExpressionTreeNode)sender;
209      var selectedNode = clickedNode.SymbolicExpressionTreeNode;
210      if (selectedNode.SubtreeCount == 0) {
211        if (!selectedSymbolicExpressionTreeNodes.Contains(selectedNode))
212          selectedSymbolicExpressionTreeNodes.Add(selectedNode);
213        else
214          selectedSymbolicExpressionTreeNodes.Remove(selectedNode);
215      }
216
217      UpdateSelectedSymbolicExpressionTreeNodes();
218    }
219
220    private void symbolicExpressionTreeChart_KeyDown(object sender, KeyEventArgs e) {
221      if (e.KeyCode == Keys.Delete) {
222        DeregisterContentEvents();
223        var root = allowedChildSymbolsControl.Tree.Root;
224        foreach (var node in selectedSymbolicExpressionTreeNodes) {
225          int argIndex = root.IndexOfSubtree(node.Parent);
226          Content.RemoveAllowedChildSymbol(root.Symbol, node.Symbol, argIndex);
227        }
228        RegisterContentEvents();
229        selectedSymbolicExpressionTreeNodes.Clear();
230        BuildAllowedChildSymbolsTree(root.Symbol);
231      }
232    }
233
234    private void symbolsTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
235      if (!Locked) {
236        DataObject data = new DataObject();
237        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, ((TreeNode)e.Item).Tag);
238        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
239      }
240    }
241
242    private bool validDragOperation;
243    private void symbolicExpressionTreeChart_DragEnter(object sender, DragEventArgs e) {
244      validDragOperation = false;
245      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
246      var symbol = data as ISymbol;
247      var symbols = data as IEnumerable<ISymbol>;
248      if (symbol != null && !(symbol is IReadOnlySymbol) && Content.ContainsSymbol(symbol)) validDragOperation = true;
249      else if (symbols != null && symbols.All(s => !(symbol is IReadOnlySymbol) && Content.ContainsSymbol(s))) validDragOperation = true;
250    }
251
252    private void symbolicExpressionTreeChart_DragOver(object sender, DragEventArgs e) {
253      e.Effect = DragDropEffects.None;
254      if (validDragOperation) {
255        Point coordinates = allowedChildSymbolsControl.PointToClient(new Point(e.X, e.Y));
256        var visualNode = allowedChildSymbolsControl.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
257        if (visualNode != null) {
258          var node = visualNode.SymbolicExpressionTreeNode;
259          var root = allowedChildSymbolsControl.Tree.Root;
260          if (root.Symbol is ProgramRootSymbol) return;
261          if (node == root || node.Parent == root) e.Effect = DragDropEffects.Copy;
262        }
263      }
264    }
265
266    private void symbolicExpressionTreeChart_DragDrop(object sender, DragEventArgs e) {
267      Point coordinates = allowedChildSymbolsControl.PointToClient(new Point(e.X, e.Y));
268      var node = allowedChildSymbolsControl.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
269      var root = allowedChildSymbolsControl.Tree.Root;
270
271      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
272      var symbol = data as ISymbol;
273      var symbols = data as IEnumerable<ISymbol>;
274
275      DeregisterContentEvents();
276      if (node.SymbolicExpressionTreeNode == root) {
277        if (symbol != null)
278          Content.AddAllowedChildSymbol(root.Symbol, symbol);
279        else if (symbols != null)
280          foreach (var s in symbols) Content.AddAllowedChildSymbol(root.Symbol, s);
281      } else {
282        int argumentIndex = root.IndexOfSubtree(node.SymbolicExpressionTreeNode);
283        if (symbol != null)
284          Content.AddAllowedChildSymbol(root.Symbol, symbol, argumentIndex);
285        else if (symbols != null)
286          foreach (var s in symbols) Content.AddAllowedChildSymbol(root.Symbol, s, argumentIndex);
287      }
288      RegisterContentEvents();
289      BuildAllowedChildSymbolsTree(root.Symbol);
290    }
291
292    private void UpdateSelectedSymbolicExpressionTreeNodes() {
293      foreach (var node in allowedChildSymbolsControl.Tree.IterateNodesPrefix()) {
294        var visualNode = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNode(node);
295        if (!selectedSymbolicExpressionTreeNodes.Contains(node)) visualNode.FillColor = Color.White;
296        else visualNode.FillColor = Color.LightSteelBlue;
297
298      }
299      allowedChildSymbolsControl.Repaint();
300    }
301
302    private RectangleF increaseMinimumSubtreeCountRectangle;
303    private RectangleF decreaseMinimumSubtreeCountRectangle;
304    private RectangleF increaseMaximumSubtreeCountRectangle;
305    private RectangleF decreaseMaximumSubtreeCountRectangle;
306    private void allowedChildSymbolsControl_Paint(object sender, PaintEventArgs e) {
307      increaseMinimumSubtreeCountRectangle = RectangleF.Empty;
308      decreaseMinimumSubtreeCountRectangle = RectangleF.Empty;
309      increaseMaximumSubtreeCountRectangle = RectangleF.Empty;
310      decreaseMaximumSubtreeCountRectangle = RectangleF.Empty;
311
312      if (Content == null) return;
313      if (allowedChildSymbolsControl.Tree == null) return;
314
315      var rootNode = allowedChildSymbolsControl.Tree.Root;
316      var visualRootNode = allowedChildSymbolsControl.GetVisualSymbolicExpressionTreeNode(rootNode);
317      var graphics = e.Graphics;
318
319      if (rootNode.Symbol is IReadOnlySymbol) return;
320      if (rootNode.Symbol.MinimumArity == rootNode.Symbol.MaximumArity) return;
321
322      using (Pen pen = new Pen(Color.Black)) {
323        using (Font font = new Font("Times New Roman", 8)) {
324          var stringFormat = new StringFormat();
325          stringFormat.Alignment = StringAlignment.Center;
326          stringFormat.LineAlignment = StringAlignment.Center;
327          int spacing = 5;
328          int size = (visualRootNode.Height - spacing * 3) / 2;
329
330          increaseMinimumSubtreeCountRectangle = new RectangleF(visualRootNode.X - spacing - size, visualRootNode.Y + spacing, size, size);
331          decreaseMinimumSubtreeCountRectangle = new RectangleF(visualRootNode.X - spacing - size, visualRootNode.Y + size + 2 * spacing, size, size);
332          increaseMaximumSubtreeCountRectangle = new RectangleF(visualRootNode.X + visualRootNode.Width + spacing, visualRootNode.Y + spacing, size, size);
333          decreaseMaximumSubtreeCountRectangle = new RectangleF(visualRootNode.X + visualRootNode.Width + spacing, visualRootNode.Y + size + 2 * spacing, size, size);
334
335          pen.Color = Content.GetMaximumSubtreeCount(rootNode.Symbol) == Content.GetMinimumSubtreeCount(rootNode.Symbol) ? Color.LightGray : Color.Black;
336          graphics.DrawString("+", font, pen.Brush, increaseMinimumSubtreeCountRectangle, stringFormat);
337          graphics.DrawRectangle(pen, Rectangle.Round(increaseMinimumSubtreeCountRectangle));
338          if (pen.Color == Color.LightGray) increaseMinimumSubtreeCountRectangle = RectangleF.Empty;
339
340          pen.Color = Content.GetMinimumSubtreeCount(rootNode.Symbol) == rootNode.Symbol.MinimumArity ? Color.LightGray : Color.Black;
341          graphics.DrawString("-", font, pen.Brush, decreaseMinimumSubtreeCountRectangle, stringFormat);
342          graphics.DrawRectangle(pen, Rectangle.Round(decreaseMinimumSubtreeCountRectangle));
343          if (pen.Color == Color.LightGray) decreaseMinimumSubtreeCountRectangle = RectangleF.Empty;
344
345          pen.Color = Content.GetMaximumSubtreeCount(rootNode.Symbol) == rootNode.Symbol.MaximumArity ? Color.LightGray : Color.Black;
346          graphics.DrawRectangle(pen, Rectangle.Round(increaseMaximumSubtreeCountRectangle));
347          graphics.DrawString("+", font, pen.Brush, increaseMaximumSubtreeCountRectangle, stringFormat);
348          if (pen.Color == Color.LightGray) increaseMaximumSubtreeCountRectangle = RectangleF.Empty;
349
350          pen.Color = Content.GetMaximumSubtreeCount(rootNode.Symbol) == Content.GetMinimumSubtreeCount(rootNode.Symbol) ? Color.LightGray : Color.Black;
351          graphics.DrawRectangle(pen, Rectangle.Round(decreaseMaximumSubtreeCountRectangle));
352          graphics.DrawString("-", font, pen.Brush, decreaseMaximumSubtreeCountRectangle, stringFormat);
353          if (pen.Color == Color.LightGray) decreaseMaximumSubtreeCountRectangle = RectangleF.Empty;
354        }
355      }
356    }
357
358    private TypeSelectorDialog typeSelectorDialog;
359    private void addButton_Click(object sender, EventArgs e) {
360      if (typeSelectorDialog == null) {
361        typeSelectorDialog = new TypeSelectorDialog();
362        typeSelectorDialog.Caption = "Select Symbol";
363        typeSelectorDialog.TypeSelector.Caption = "Available Symbols";
364        typeSelectorDialog.TypeSelector.Configure(typeof(ISymbol), false, false, (t) => { return !typeof(IReadOnlySymbol).IsAssignableFrom(t); });
365      }
366      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
367        try {
368          ISymbol symbol = (ISymbol)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
369          var originalSymbolName = symbol.Name;
370          int i = 1;
371          while (Content.ContainsSymbol(symbol)) {
372            symbol.Name = originalSymbolName + i;
373            i++;
374          }
375
376          var selectedNode = symbolsTreeView.SelectedNode;
377          GroupSymbol groupSymbol = null;
378          while (selectedNode != null) {
379            groupSymbol = selectedNode.Tag as GroupSymbol;
380            if (groupSymbol != null && Content.ContainsSymbol(groupSymbol)) break;
381            selectedNode = selectedNode.Parent;
382          }
383
384          if (groupSymbol != null && Content.ContainsSymbol(groupSymbol)) groupSymbol.SymbolsCollection.Add(symbol);
385          else Content.AddSymbol(symbol);
386        }
387        catch (Exception ex) {
388          ErrorHandling.ShowErrorDialog(this, ex);
389        }
390      }
391    }
392
393    private void removeButton_Click(object sender, EventArgs e) {
394      var symbol = symbolsTreeView.SelectedNode.Tag as ISymbol;
395      if (symbol != null && !(symbol is IReadOnlySymbol))
396        Content.RemoveSymbol(symbol);
397      removeButton.Enabled = false;
398      allowedChildSymbolsControl.Tree = null;
399      symbolDetailsViewHost.Content = null;
400    }
401
402    private void showDetailsCheckBox_CheckedChanged(object sender, EventArgs e) {
403      splitContainer1.Panel2Collapsed = !showDetailsCheckBox.Checked;
404    }
405
406    #region helpers
407    private IEnumerable<TreeNode> IterateSymbolTreeNodes(TreeNode node = null) {
408      TreeNodeCollection nodes;
409      if (node == null)
410        nodes = symbolsTreeView.Nodes;
411      else {
412        nodes = node.Nodes;
413        yield return node;
414      }
415
416      foreach (var childNode in nodes.OfType<TreeNode>())
417        foreach (var n in IterateSymbolTreeNodes(childNode))
418          yield return n;
419    }
420
421    protected virtual void RebuildImageList() {
422      symbolsTreeView.ImageList.Images.Clear();
423      foreach (TreeNode treeNode in IterateSymbolTreeNodes()) {
424        var symbol = (ISymbol)treeNode.Tag;
425        symbolsTreeView.ImageList.Images.Add(symbol == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : symbol.ItemImage);
426        treeNode.ImageIndex = symbolsTreeView.ImageList.Images.Count - 1;
427      }
428    }
429    #endregion
430
431    private void allowedChildSymbolsControl_MouseDown(object sender, MouseEventArgs e) {
432      if (Content == null) return;
433      if (allowedChildSymbolsControl.Tree == null) return;
434
435      var pointF = new PointF(e.X, e.Y);
436      var rootSymbol = allowedChildSymbolsControl.Tree.Root.Symbol;
437      int minimumSubtreeCount = Content.GetMinimumSubtreeCount(rootSymbol);
438      int maximumSubtreecount = Content.GetMaximumSubtreeCount(rootSymbol);
439
440      bool changed = true;
441      DeregisterContentEvents();
442      if (increaseMinimumSubtreeCountRectangle.Contains(pointF))
443        Content.SetSubtreeCount(rootSymbol, minimumSubtreeCount + 1, maximumSubtreecount);
444      else if (decreaseMinimumSubtreeCountRectangle.Contains(pointF))
445        Content.SetSubtreeCount(rootSymbol, minimumSubtreeCount - 1, maximumSubtreecount);
446      else if (increaseMaximumSubtreeCountRectangle.Contains(pointF))
447        Content.SetSubtreeCount(rootSymbol, minimumSubtreeCount, maximumSubtreecount + 1);
448      else if (decreaseMaximumSubtreeCountRectangle.Contains(pointF))
449        Content.SetSubtreeCount(rootSymbol, minimumSubtreeCount, maximumSubtreecount - 1);
450      else
451        changed = false;
452
453      if (changed) BuildAllowedChildSymbolsTree(rootSymbol);
454      RegisterContentEvents();
455    }
456  }
457
458  [NonDiscoverableType]
459  internal class DummySymbol : Symbol {
460    private const int minimumArity = 1;
461    private const int maximumArity = byte.MaxValue;
462
463    public override int MinimumArity {
464      get { return minimumArity; }
465    }
466    public override int MaximumArity {
467      get { return maximumArity; }
468    }
469
470    public DummySymbol(DummySymbol original, Cloner cloner) : base(original, cloner) { }
471    public DummySymbol(string name) : base(name, "DummySymbol for views") { }
472    public override IDeepCloneable Clone(Cloner cloner) { return new DummySymbol(this, cloner); }
473  }
474}
Note: See TracBrowser for help on using the repository browser.