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

Last change on this file since 6415 was 6415, checked in by mkommend, 8 years ago

#1479: Merged trunk changes, refactored grammar editor and added copy functionality.

File size: 14.2 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.Common;
28using HeuristicLab.Core.Views;
29using HeuristicLab.MainForm;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
33  [View("Symbolic Expression Grammar Editor")]
34  [Content(typeof(ISymbolicExpressionGrammar), false)]
35  public partial class SymbolicExpressionGrammarEditorView : NamedItemView {
36    public SymbolicExpressionGrammarEditorView() {
37      InitializeComponent();
38    }
39
40    public override bool ReadOnly {
41      get {
42        if ((Content != null) && Content.ReadOnly) return true;
43        return base.ReadOnly;
44      }
45      set {
46        if ((Content != null) && Content.ReadOnly) base.ReadOnly = true;
47        else base.ReadOnly = value;
48      }
49    }
50
51    public new ISymbolicExpressionGrammar Content {
52      get { return (ISymbolicExpressionGrammar)base.Content; }
53      set { base.Content = value; }
54    }
55
56    protected override void SetEnabledStateOfControls() {
57      base.SetEnabledStateOfControls();
58      addButton.Enabled = Content != null;
59      removeButton.Enabled = symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol);
60      copyButton.Enabled = symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol);
61    }
62
63    protected override void OnContentChanged() {
64      base.OnContentChanged();
65      if (Content != null) {
66        symbolsTreeView.Nodes.Clear();
67        UpdateSymbolsTreeView();
68        symbolsTreeView.ExpandAll();
69        allowedChildSymbolsControl.Grammar = Content;
70        allowedChildSymbolsControl.Symbol = null;
71        symbolDetailsViewHost.Content = null;
72      } else {
73        symbolsTreeView.Nodes.Clear();
74        allowedChildSymbolsControl.Grammar = null;
75        symbolDetailsViewHost.Content = null;
76      }
77    }
78
79    #region events
80    protected override void RegisterContentEvents() {
81      base.RegisterContentEvents();
82      Content.ReadOnlyChanged += new System.EventHandler(Content_ReadOnlyChanged);
83      Content.Changed += new System.EventHandler(Content_Changed);
84    }
85    protected override void DeregisterContentEvents() {
86      Content.ReadOnlyChanged -= new System.EventHandler(Content_ReadOnlyChanged);
87      Content.Changed -= new System.EventHandler(Content_Changed);
88      base.DeregisterContentEvents();
89    }
90
91    private void Content_ReadOnlyChanged(object sender, EventArgs e) {
92      ReadOnly = Content.ReadOnly;
93    }
94
95    private void Content_Changed(object sender, EventArgs e) {
96      ISymbol symbol = null;
97      if (symbolsTreeView.SelectedNode != null)
98        symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
99
100      allowedChildSymbolsControl.Grammar = Content;
101
102      UpdateSymbolsTreeView();
103      if (symbol != null && Content.ContainsSymbol(symbol)) {
104        allowedChildSymbolsControl.Symbol = symbol;
105        symbolDetailsViewHost.Content = symbol;
106        symbolsTreeView.SelectedNode = IterateSymbolTreeNodes().Where(n => n.Tag == symbol).ToList().FirstOrDefault();
107      }
108    }
109    #endregion
110
111    private void UpdateSymbolsTreeView() {
112      var symbols = Content.Symbols.ToList();
113      foreach (var treeNode in IterateSymbolTreeNodes().ToList()) {
114        var symbol = treeNode.Tag as ISymbol;
115        if (!symbols.Contains(symbol))
116          treeNode.Remove();
117      }
118
119      var groupSymbols = symbols.OfType<GroupSymbol>().ToList();
120      var topLevelSymbols = Content.Symbols.Where(s => !groupSymbols.Any(g => g.Symbols.Contains(s)));
121      AddChildTreeNodes(symbolsTreeView.Nodes, topLevelSymbols);
122
123      RebuildImageList();
124    }
125
126    private void AddChildTreeNodes(TreeNodeCollection collection, IEnumerable<ISymbol> symbols) {
127      foreach (ISymbol symbol in symbols) {
128        TreeNode node = collection.Cast<TreeNode>().Where(n => n.Tag == symbol).FirstOrDefault();
129        if (node == null) {
130          node = new TreeNode();
131          node.Name = symbol.Name;
132          node.Text = symbol.Name;
133          node.Tag = symbol;
134          node.Checked = symbol.Enabled;
135          collection.Add(node);
136        }
137        var groupSymbol = symbol as GroupSymbol;
138        if (groupSymbol != null) AddChildTreeNodes(node.Nodes, groupSymbol.Symbols);
139      }
140    }
141
142    private void symbolsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
143      if (e.Action != TreeViewAction.Unknown) {
144        var symbol = (ISymbol)e.Node.Tag;
145        symbolDetailsViewHost.Content = symbol;
146        allowedChildSymbolsControl.Symbol = symbol;
147      }
148      removeButton.Enabled = symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol);
149      copyButton.Enabled = symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol);
150    }
151
152    private void symbolsTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
153      if (e.Action != TreeViewAction.Unknown) {
154        Content.StartGrammarManipulation();
155        allowedChildSymbolsControl.Symbol = null;
156        var symbol = (ISymbol)e.Node.Tag;
157        symbol.Enabled = e.Node.Checked;
158        foreach (var node in IterateSymbolTreeNodes())
159          node.Checked = ((ISymbol)node.Tag).Enabled;
160
161        if (symbolsTreeView.SelectedNode != null) {
162          symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
163          allowedChildSymbolsControl.Symbol = symbol;
164        }
165        Content.FinishedGrammarManipulation();
166      }
167    }
168
169    #region drag & drop operations
170    private GroupSymbol parentOfDraggedSymbol;
171    private void symbolsTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
172      if (!Locked) {
173        var treeNode = e.Item as TreeNode;
174        if (treeNode.Parent != null) parentOfDraggedSymbol = treeNode.Parent.Tag as GroupSymbol;
175        var data = new DataObject();
176        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, treeNode.Tag);
177        validDragOperation = true;
178        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Move);
179      }
180    }
181
182
183    private bool validDragOperation;
184    private void symbolsTreeView_DragEnter(object sender, DragEventArgs e) {
185      validDragOperation = false;
186      if (Content == null) return;
187
188      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
189      var symbol = data as ISymbol;
190      if (symbol != null && !(symbol is IReadOnlySymbol)) validDragOperation = true;
191    }
192    private void symbolsTreeView_DragOver(object sender, DragEventArgs e) {
193      e.Effect = DragDropEffects.None;
194      if (validDragOperation) {
195        GroupSymbol groupSymbol = null;
196        Point mouse = symbolsTreeView.PointToClient(new Point(e.X, e.Y));
197        TreeNode node = symbolsTreeView.GetNodeAt(mouse);
198        if (node != null) groupSymbol = node.Tag as GroupSymbol;
199        if (node != null && groupSymbol == null) groupSymbol = node.Parent.Tag as GroupSymbol;
200        var symbol = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
201        if (symbol == groupSymbol) return;
202
203        if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
204      }
205    }
206    private void symbolsTreeView_DragDrop(object sender, DragEventArgs e) {
207      var symbol = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as ISymbol;
208
209      GroupSymbol groupSymbol = null;
210      Point mouse = symbolsTreeView.PointToClient(new Point(e.X, e.Y));
211      TreeNode node = symbolsTreeView.GetNodeAt(mouse);
212      if (node != null) groupSymbol = node.Tag as GroupSymbol;
213      if (node != null && groupSymbol == null) groupSymbol = node.Parent.Tag as GroupSymbol;
214
215      Content.StartGrammarManipulation();
216      Cloner cloner = new Cloner();
217      var clonedSymbol = cloner.Clone(symbol);
218      ChangeDuplicateSymbolNames(clonedSymbol);
219
220      if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(clonedSymbol);
221      else Content.AddSymbol(clonedSymbol);
222
223      UpdateGrammerConstraintsForClonedSymbol(symbol, cloner);
224      Content.FinishedGrammarManipulation();
225    }
226    #endregion
227
228    #region button events
229    private TypeSelectorDialog typeSelectorDialog;
230    private void addButton_Click(object sender, EventArgs e) {
231      if (typeSelectorDialog == null) {
232        typeSelectorDialog = new TypeSelectorDialog();
233        typeSelectorDialog.Caption = "Select Symbol";
234        typeSelectorDialog.TypeSelector.Caption = "Available Symbols";
235        typeSelectorDialog.TypeSelector.Configure(typeof(ISymbol), false, false, (t) => { return !typeof(IReadOnlySymbol).IsAssignableFrom(t); });
236      }
237      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
238        try {
239          ISymbol symbol = (ISymbol)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
240          ChangeDuplicateSymbolNames(symbol);
241
242          var selectedNode = symbolsTreeView.SelectedNode;
243          GroupSymbol groupSymbol = selectedNode.Tag as GroupSymbol;
244          if (groupSymbol == null && selectedNode.Parent != null) groupSymbol = selectedNode.Parent.Tag as GroupSymbol;
245
246          if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(symbol);
247          else Content.AddSymbol(symbol);
248        }
249        catch (Exception ex) {
250          ErrorHandling.ShowErrorDialog(this, ex);
251        }
252      }
253    }
254
255    private void copyButton_Click(object sender, EventArgs e) {
256      var symbol = symbolsTreeView.SelectedNode.Tag as ISymbol;
257      if (symbol != null && !(symbol is IReadOnlySymbol)) {
258        allowedChildSymbolsControl.Symbol = null;
259        symbolDetailsViewHost.Content = null;
260
261        Content.StartGrammarManipulation();
262        Cloner cloner = new Cloner();
263        var clonedSymbol = cloner.Clone(symbol);
264        ChangeDuplicateSymbolNames(clonedSymbol);
265
266        GroupSymbol groupSymbol = null;
267        if (symbolsTreeView.SelectedNode.Parent != null) groupSymbol = symbolsTreeView.SelectedNode.Parent.Tag as GroupSymbol;
268
269        if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(clonedSymbol);
270        else Content.AddSymbol(clonedSymbol);
271
272        UpdateGrammerConstraintsForClonedSymbol(symbol, cloner);
273        Content.FinishedGrammarManipulation();
274      }
275    }
276
277    private void removeButton_Click(object sender, EventArgs e) {
278      var symbol = symbolsTreeView.SelectedNode.Tag as ISymbol;
279      if (symbol != null && !(symbol is IReadOnlySymbol)) {
280        Content.RemoveSymbol(symbol);
281        allowedChildSymbolsControl.Symbol = null;
282        symbolDetailsViewHost.Content = null;
283      }
284    }
285
286    private void showDetailsCheckBox_CheckedChanged(object sender, EventArgs e) {
287      splitContainer1.Panel2Collapsed = !showDetailsCheckBox.Checked;
288    }
289    #endregion
290
291    #region helpers
292    private void UpdateGrammerConstraintsForClonedSymbol(ISymbol symbol, Cloner cloner) {
293      foreach (var s in symbol.Flatten().Where(x => !(x is GroupSymbol))) {
294        if (!cloner.ClonedObjectRegistered(s)) throw new InvalidOperationException();
295        var clone = cloner.Clone(s);
296        Content.SetSubtreeCount(clone, Content.GetMinimumSubtreeCount(s), Content.GetMaximumSubtreeCount(s));
297        foreach (var childSymbol in Content.GetAllowedChildSymbols(s)) {
298          var newChildSymbol = childSymbol;
299          if (cloner.ClonedObjectRegistered(childSymbol)) newChildSymbol = cloner.Clone(childSymbol);
300          Content.AddAllowedChildSymbol(clone, newChildSymbol);
301        }
302        for (int i = 0; i < Content.GetMaximumSubtreeCount(s); i++) {
303          foreach (var childSymbol in Content.GetAllowedChildSymbols(s, i)) {
304            var newChildSymbol = childSymbol;
305            if (cloner.ClonedObjectRegistered(childSymbol)) newChildSymbol = cloner.Clone(childSymbol);
306            Content.AddAllowedChildSymbol(clone, newChildSymbol, i);
307          }
308        }
309      }
310    }
311
312
313    private void ChangeDuplicateSymbolNames(ISymbol symbol) {
314      foreach (var s in symbol.Flatten()) {
315        var originalSymbolName = s.Name;
316        int i = 1;
317        while (Content.ContainsSymbol(s)) {
318          s.Name = originalSymbolName + i;
319          i++;
320        }
321      }
322    }
323
324    private IEnumerable<TreeNode> IterateSymbolTreeNodes(TreeNode node = null) {
325      TreeNodeCollection nodes;
326      if (node == null)
327        nodes = symbolsTreeView.Nodes;
328      else {
329        nodes = node.Nodes;
330        yield return node;
331      }
332
333      foreach (var childNode in nodes.OfType<TreeNode>())
334        foreach (var n in IterateSymbolTreeNodes(childNode))
335          yield return n;
336    }
337
338    protected virtual void RebuildImageList() {
339      symbolsTreeView.ImageList.Images.Clear();
340      foreach (TreeNode treeNode in IterateSymbolTreeNodes()) {
341        var symbol = (ISymbol)treeNode.Tag;
342        symbolsTreeView.ImageList.Images.Add(symbol == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : symbol.ItemImage);
343        treeNode.ImageIndex = symbolsTreeView.ImageList.Images.Count - 1;
344      }
345    }
346    #endregion
347  }
348
349  //this class is necessary to prevent double clicks which do not fire the checkbox checked event
350  internal class CheckBoxTreeView : TreeView {
351    protected override void WndProc(ref Message m) {
352      // Suppress WM_LBUTTONDBLCLK
353      if (m.Msg == 0x203) { m.Result = IntPtr.Zero; } else base.WndProc(ref m);
354    }
355  }
356}
Note: See TracBrowser for help on using the repository browser.