Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarEditorView.cs @ 7735

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

#1790: Opened a new symbol view on double click in the GrammarEditor and set the SymbolView as default view for ISymbols.

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