source: branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarEditorView.cs @ 11185

Last change on this file since 11185 was 11185, checked in by pfleck, 8 years ago

#2208 merged trunk and updated version info

File size: 17.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 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), true)]
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    private Color treeViewBackColor = Color.Empty;
57    protected override void SetEnabledStateOfControls() {
58      base.SetEnabledStateOfControls();
59      if (Content == null || Content.ReadOnly || ReadOnly || Locked) {
60        addButton.Enabled = false;
61        removeButton.Enabled = false;
62        copyButton.Enabled = false;
63        treeViewBackColor = symbolsTreeView.BackColor;
64        symbolsTreeView.BackColor = Color.FromArgb(255, 240, 240, 240);
65      } else {
66        addButton.Enabled = true;
67        if (symbolsTreeView.SelectedNode != null && !(symbolsTreeView.SelectedNode.Tag is IReadOnlySymbol)) {
68          removeButton.Enabled = true;
69          copyButton.Enabled = true;
70        }
71        treeViewBackColor = Color.Empty;
72        symbolsTreeView.BackColor = treeViewBackColor;
73      }
74    }
75
76    protected override void OnContentChanged() {
77      base.OnContentChanged();
78      if (Content != null) {
79        symbolsTreeView.Nodes.Clear();
80        UpdateSymbolsTreeView();
81
82        symbolsTreeView.CollapseAll();
83        foreach (var node in IterateTreeNodes())
84          if (node.Checked) node.Expand();
85
86        //mkommend: scrolls to the top node
87        symbolsTreeView.Nodes[0].EnsureVisible();
88
89        allowedChildSymbolsControl.Grammar = Content;
90        allowedChildSymbolsControl.Symbol = null;
91        symbolDetailsViewHost.Content = null;
92      } else {
93        symbolsTreeView.Nodes.Clear();
94        allowedChildSymbolsControl.Grammar = null;
95        symbolDetailsViewHost.Content = null;
96      }
97    }
98
99    #region events
100    protected override void RegisterContentEvents() {
101      base.RegisterContentEvents();
102      Content.ReadOnlyChanged += new System.EventHandler(Content_ReadOnlyChanged);
103      Content.Changed += new System.EventHandler(Content_Changed);
104    }
105    protected override void DeregisterContentEvents() {
106      Content.ReadOnlyChanged -= new System.EventHandler(Content_ReadOnlyChanged);
107      Content.Changed -= new System.EventHandler(Content_Changed);
108      base.DeregisterContentEvents();
109    }
110
111    private void Content_ReadOnlyChanged(object sender, EventArgs e) {
112      ReadOnly = Content.ReadOnly;
113    }
114
115    private void Content_Changed(object sender, EventArgs e) {
116      ISymbol symbol = null;
117      if (symbolsTreeView.SelectedNode != null)
118        symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
119
120      allowedChildSymbolsControl.Grammar = Content;
121
122      UpdateSymbolsTreeView();
123      if (symbol != null && Content.ContainsSymbol(symbol)) {
124        symbolsTreeView.SelectedNode = IterateTreeNodes().Where(n => n.Tag == symbol).ToList().FirstOrDefault();
125        UpdateSymbolDetailsViews();
126      }
127    }
128    #endregion
129
130    private void UpdateSymbolsTreeView() {
131      var symbols = Content.Symbols.ToList();
132      foreach (var treeNode in IterateTreeNodes().ToList()) {
133        var symbol = treeNode.Tag as ISymbol;
134        if (!symbols.Contains(symbol))
135          treeNode.Remove();
136      }
137
138      var groupSymbols = symbols.OfType<GroupSymbol>().ToList();
139      var topLevelSymbols = Content.Symbols.Where(s => !groupSymbols.Any(g => g.Symbols.Contains(s)));
140      UpdateChildTreeNodes(symbolsTreeView.Nodes, topLevelSymbols);
141      RebuildImageList();
142    }
143
144    private void UpdateChildTreeNodes(TreeNodeCollection collection, IEnumerable<ISymbol> symbols) {
145      foreach (ISymbol symbol in symbols) {
146        if (symbol is ProgramRootSymbol) continue;
147        if (symbol is Defun) continue;
148
149        TreeNode node = collection.Cast<TreeNode>().Where(n => n.Tag == symbol).FirstOrDefault();
150        if (node == null) {
151          node = new TreeNode();
152          node.Tag = symbol;
153          collection.Add(node);
154        }
155        node.Checked = symbol.Enabled;
156        node.Text = symbol.Name;
157
158        var groupSymbol = symbol as GroupSymbol;
159        if (groupSymbol != null) UpdateChildTreeNodes(node.Nodes, groupSymbol.Symbols);
160      }
161    }
162
163    private void symbolsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
164      if (e.Action != TreeViewAction.Unknown) UpdateSymbolDetailsViews();
165      SetEnabledStateOfControls();
166    }
167
168    private void symbolsTreeView_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
169      if (e.Action == TreeViewAction.Unknown) return;
170      e.Cancel = Content == null || Content.ReadOnly || ReadOnly || Locked;
171    }
172
173    private void symbolsTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
174      if (e.Action == TreeViewAction.Unknown) return;
175      Content.StartGrammarManipulation();
176      allowedChildSymbolsControl.Symbol = null;
177      var symbol = (ISymbol)e.Node.Tag;
178      symbol.Enabled = e.Node.Checked;
179      foreach (var node in IterateTreeNodes())
180        node.Checked = ((ISymbol)node.Tag).Enabled;
181
182      Content.FinishedGrammarManipulation();
183    }
184
185    #region drag & drop operations
186    private void symbolsTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
187      if (!Locked) {
188        var treeNode = e.Item as TreeNode;
189        var data = new DataObject();
190        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, treeNode.Tag);
191        validDragOperation = true;
192        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Move);
193      }
194    }
195
196
197    private bool validDragOperation;
198    private void symbolsTreeView_DragEnter(object sender, DragEventArgs e) {
199      validDragOperation = false;
200      if (Content == null || Content.ReadOnly || ReadOnly || Locked) return;
201
202      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
203      var symbol = data as ISymbol;
204      if (symbol != null && !(symbol is IReadOnlySymbol)) validDragOperation = true;
205    }
206    private void symbolsTreeView_DragOver(object sender, DragEventArgs e) {
207      e.Effect = DragDropEffects.None;
208      if (validDragOperation) {
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) return;
213        groupSymbol = node.Tag as GroupSymbol;
214        if (groupSymbol == null) return;
215        var symbol = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
216        if (symbol == groupSymbol) return;
217
218        if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
219      }
220    }
221    private void symbolsTreeView_DragDrop(object sender, DragEventArgs e) {
222      var symbol = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as ISymbol;
223
224      GroupSymbol groupSymbol = null;
225      Point mouse = symbolsTreeView.PointToClient(new Point(e.X, e.Y));
226      TreeNode node = symbolsTreeView.GetNodeAt(mouse);
227      if (node != null) groupSymbol = node.Tag as GroupSymbol;
228      if (node != null && groupSymbol == null) groupSymbol = node.Parent.Tag as GroupSymbol;
229
230      Content.StartGrammarManipulation();
231      Cloner cloner = new Cloner();
232      var clonedSymbol = cloner.Clone(symbol);
233      ChangeDuplicateSymbolNames(clonedSymbol);
234
235      if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(clonedSymbol);
236      else Content.AddSymbol(clonedSymbol);
237
238      UpdateGrammerConstraintsForClonedSymbol(symbol, cloner);
239      Content.FinishedGrammarManipulation();
240    }
241    #endregion
242
243    private void symbolsTreeView_MouseDown(object sender, MouseEventArgs e) {
244      // enables deselection of treeNodes
245      Point coordinates = new Point(e.X, e.Y);
246      TreeNode node = symbolsTreeView.GetNodeAt(coordinates);
247      if (e.Button == MouseButtons.Left && node == null) {
248        symbolsTreeView.SelectedNode = null;
249        symbolDetailsViewHost.Content = null;
250        SetEnabledStateOfControls();
251      }
252    }
253
254    private void symbolsTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
255      var symbol = e.Node.Tag as ISymbol;
256      if (symbol == null) return;
257      if (e.Button != MouseButtons.Left) return;
258      if (e.X < e.Node.Bounds.Left - symbolsTreeView.ImageList.Images[e.Node.ImageIndex].Width || e.X > e.Node.Bounds.Right) return;
259      MainFormManager.MainForm.ShowContent(symbol);
260      e.Node.Toggle();
261    }
262
263    private void symbolsTreeView_KeyDown(object sender, KeyEventArgs e) {
264      if (Content == null || Content.ReadOnly || ReadOnly || Locked) return;
265      if (symbolsTreeView.SelectedNode == null) return;
266      if (e.KeyCode != Keys.Delete) return;
267
268      var symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
269      if (!(symbol is IReadOnlySymbol))
270        Content.RemoveSymbol(symbol);
271
272      SetEnabledStateOfControls();
273      UpdateSymbolDetailsViews();
274      RebuildImageList();
275    }
276
277    #region button events
278    private TypeSelectorDialog typeSelectorDialog;
279    private void addButton_Click(object sender, EventArgs e) {
280      if (typeSelectorDialog == null) {
281        typeSelectorDialog = new TypeSelectorDialog();
282        typeSelectorDialog.Caption = "Select Symbol";
283        typeSelectorDialog.TypeSelector.Caption = "Available Symbols";
284        typeSelectorDialog.TypeSelector.Configure(typeof(ISymbol), false, false, (t) => { return !typeof(IReadOnlySymbol).IsAssignableFrom(t); });
285      }
286      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
287        try {
288          ISymbol symbol = (ISymbol)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
289          ChangeDuplicateSymbolNames(symbol);
290          GroupSymbol groupSymbol = null;
291
292          TreeNode selectedNode = symbolsTreeView.SelectedNode;
293          if (selectedNode != null) {
294            groupSymbol = selectedNode.Tag as GroupSymbol;
295            if (groupSymbol == null && selectedNode.Parent != null) groupSymbol = selectedNode.Parent.Tag as GroupSymbol;
296          }
297          if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(symbol);
298          else Content.AddSymbol(symbol);
299        }
300        catch (Exception ex) {
301          ErrorHandling.ShowErrorDialog(this, ex);
302        }
303      }
304    }
305
306    private void copyButton_Click(object sender, EventArgs e) {
307      var symbol = symbolsTreeView.SelectedNode.Tag as ISymbol;
308      if (symbol != null && !(symbol is IReadOnlySymbol)) {
309
310        Content.StartGrammarManipulation();
311        Cloner cloner = new Cloner();
312        var clonedSymbol = cloner.Clone(symbol);
313        ChangeDuplicateSymbolNames(clonedSymbol);
314
315        GroupSymbol groupSymbol = null;
316        if (symbolsTreeView.SelectedNode.Parent != null) groupSymbol = symbolsTreeView.SelectedNode.Parent.Tag as GroupSymbol;
317
318        if (groupSymbol != null) groupSymbol.SymbolsCollection.Add(clonedSymbol);
319        else Content.AddSymbol(clonedSymbol);
320
321        UpdateGrammerConstraintsForClonedSymbol(symbol, cloner);
322        Content.FinishedGrammarManipulation();
323      }
324    }
325
326    private void removeButton_Click(object sender, EventArgs e) {
327      var symbol = symbolsTreeView.SelectedNode.Tag as ISymbol;
328      if (symbol != null && !(symbol is IReadOnlySymbol)) {
329        Content.RemoveSymbol(symbol);
330      }
331    }
332
333    private void showDetailsCheckBox_CheckedChanged(object sender, EventArgs e) {
334      splitContainer1.Panel2Collapsed = !showDetailsCheckBox.Checked;
335    }
336
337    private void showSampleTreeButton_Click(object sender, EventArgs e) {
338      SymbolicExpressionGrammarSampleExpressionTreeView view = new SymbolicExpressionGrammarSampleExpressionTreeView();
339      view.Content = Content;
340      view.Show();
341    }
342
343    #endregion
344
345    #region helpers
346    private void UpdateGrammerConstraintsForClonedSymbol(ISymbol symbol, Cloner cloner) {
347      foreach (var s in symbol.Flatten().Where(x => !(x is GroupSymbol))) {
348        if (!cloner.ClonedObjectRegistered(s)) throw new InvalidOperationException();
349        var clone = cloner.Clone(s);
350        Content.SetSubtreeCount(clone, Content.GetMinimumSubtreeCount(s), Content.GetMaximumSubtreeCount(s));
351        foreach (var childSymbol in Content.GetAllowedChildSymbols(s)) {
352          var newChildSymbol = childSymbol;
353          if (cloner.ClonedObjectRegistered(childSymbol)) newChildSymbol = cloner.Clone(childSymbol);
354          Content.AddAllowedChildSymbol(clone, newChildSymbol);
355        }
356        for (int i = 0; i < Content.GetMaximumSubtreeCount(s); i++) {
357          foreach (var childSymbol in Content.GetAllowedChildSymbols(s, i)) {
358            var newChildSymbol = childSymbol;
359            if (cloner.ClonedObjectRegistered(childSymbol)) newChildSymbol = cloner.Clone(childSymbol);
360            Content.AddAllowedChildSymbol(clone, newChildSymbol, i);
361          }
362        }
363      }
364    }
365
366    private void ChangeDuplicateSymbolNames(ISymbol symbol) {
367      foreach (var s in symbol.Flatten()) {
368        var originalSymbolName = s.Name;
369        int i = 1;
370        while (Content.ContainsSymbol(s)) {
371          s.Name = originalSymbolName + i;
372          i++;
373        }
374      }
375    }
376
377    private void UpdateSymbolDetailsViews() {
378      if (symbolsTreeView.SelectedNode != null) {
379        symbolDetailsViewHost.Content = (ISymbol)symbolsTreeView.SelectedNode.Tag;
380        allowedChildSymbolsControl.Symbol = (ISymbol)symbolsTreeView.SelectedNode.Tag;
381      } else {
382        symbolDetailsViewHost.Content = null;
383        allowedChildSymbolsControl.Symbol = null;
384      }
385    }
386
387    private IEnumerable<TreeNode> IterateTreeNodes(TreeNode node = null) {
388      TreeNodeCollection nodes;
389      if (node == null)
390        nodes = symbolsTreeView.Nodes;
391      else {
392        nodes = node.Nodes;
393        yield return node;
394      }
395
396      foreach (var childNode in nodes.OfType<TreeNode>())
397        foreach (var n in IterateTreeNodes(childNode))
398          yield return n;
399    }
400
401    protected virtual void RebuildImageList() {
402      symbolsTreeView.ImageList.Images.Clear();
403      foreach (TreeNode treeNode in IterateTreeNodes()) {
404        var symbol = (ISymbol)treeNode.Tag;
405        symbolsTreeView.ImageList.Images.Add(symbol == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : symbol.ItemImage);
406        treeNode.ImageIndex = symbolsTreeView.ImageList.Images.Count - 1;
407      }
408    }
409
410    //necessary code to handle dock correctly regarding the expanded nodes
411    bool[] expandendedState;
412    protected override void OnHandleCreated(EventArgs e) {
413      base.OnHandleCreated(e);
414      if (expandendedState == null) return;
415      var nodes = IterateTreeNodes().ToList();
416      for (int i = 0; i < nodes.Count; i++)
417        if (expandendedState[i]) nodes[i].Expand();
418    }
419    protected override void OnHandleDestroyed(EventArgs e) {
420      base.OnHandleDestroyed(e);
421      var nodes = IterateTreeNodes().ToList();
422      expandendedState = new bool[nodes.Count];
423      for (int i = 0; i < nodes.Count; i++)
424        expandendedState[i] = nodes[i].IsExpanded;
425    }
426    #endregion
427  }
428
429  //this class is necessary to prevent double clicks which do not fire the checkbox checked event
430  //workaround taken from http://connect.microsoft.com/VisualStudio/feedback/details/374516/treeview-control-does-not-fire-events-reliably-when-double-clicking-on-checkbox
431  internal class CheckBoxTreeView : TreeView {
432    protected override void WndProc(ref Message m) {
433      // Suppress WM_LBUTTONDBLCLK
434      if (m.Msg == 0x203 && IsOnCheckBox(m)) { m.Result = IntPtr.Zero; } else base.WndProc(ref m);
435    }
436
437    private int GetXLParam(IntPtr lParam) {
438      return lParam.ToInt32() & 0xffff;
439    }
440
441    private int GetYLParam(IntPtr lParam) {
442      return lParam.ToInt32() >> 16;
443    }
444
445    private bool IsOnCheckBox(Message m) {
446      int x = GetXLParam(m.LParam);
447      int y = GetYLParam(m.LParam);
448      TreeNode node = this.GetNodeAt(x, y);
449      return ((x <= node.Bounds.Left - 20) && (x >= node.Bounds.Left - 32));
450    }
451  }
452}
Note: See TracBrowser for help on using the repository browser.