Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OaaS/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarEditorView.cs @ 10308

Last change on this file since 10308 was 8106, checked in by mkommend, 12 years ago

#1722: Corrected behavior of SymbolicExpressionGrammarEditorView.

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