Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Scripting.Views/3.3/VariableStoreView.cs @ 11436

Last change on this file since 11436 was 11436, checked in by jkarder, 10 years ago

#2262:

  • IEnumerable<T> extension methods are supported by the variables collection
  • INamedItem variables get the item's name per default
  • variables can be renamed by pressing F2
  • variables are removed faster
  • multiple variables can be selected
  • the code editor supports scrolling while scripts are executed
File size: 17.3 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.Text.RegularExpressions;
27using System.Windows.Forms;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Core.Views;
32using HeuristicLab.MainForm;
33using HeuristicLab.MainForm.WindowsForms;
34using HeuristicLab.Persistence.Core;
35using HeuristicLab.Persistence.Default.Xml;
36using HeuristicLab.PluginInfrastructure;
37
38namespace HeuristicLab.Scripting.Views {
39  [View("ItemCollection View")]
40  [Content(typeof(VariableStore), true)]
41  public partial class VariableStoreView : AsynchronousContentView {
42    protected Dictionary<string, ListViewItem> itemListViewItemMapping;
43    protected TypeSelectorDialog typeSelectorDialog;
44    protected bool validDragOperation;
45
46    public new VariableStore Content {
47      get { return (VariableStore)base.Content; }
48      set { base.Content = value; }
49    }
50
51    public ListView ItemsListView {
52      get { return variableListView; }
53    }
54
55    public VariableStoreView() {
56      InitializeComponent();
57      itemListViewItemMapping = new Dictionary<string, ListViewItem>();
58      variableListView.SmallImageList.Images.AddRange(new Image[] {
59        HeuristicLab.Common.Resources.VSImageLibrary.Error,
60        HeuristicLab.Common.Resources.VSImageLibrary.Warning,
61        HeuristicLab.Common.Resources.VSImageLibrary.Object,
62        HeuristicLab.Common.Resources.VSImageLibrary.Nothing
63      });
64    }
65
66    protected override void Dispose(bool disposing) {
67      if (disposing) {
68        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
69        if (components != null) components.Dispose();
70      }
71      base.Dispose(disposing);
72    }
73
74    protected override void DeregisterContentEvents() {
75      Content.ItemsAdded -= Content_ItemsAdded;
76      Content.ItemsReplaced -= Content_ItemsReplaced;
77      Content.ItemsRemoved -= Content_ItemsRemoved;
78      Content.CollectionReset -= Content_CollectionReset;
79      base.DeregisterContentEvents();
80    }
81    protected override void RegisterContentEvents() {
82      base.RegisterContentEvents();
83      Content.ItemsAdded += Content_ItemsAdded;
84      Content.ItemsReplaced += Content_ItemsReplaced;
85      Content.ItemsRemoved += Content_ItemsRemoved;
86      Content.CollectionReset += Content_CollectionReset;
87    }
88
89    protected override void OnContentChanged() {
90      base.OnContentChanged();
91      variableListView.Items.Clear();
92      itemListViewItemMapping.Clear();
93      if (Content != null) {
94        Caption += " (" + Content.GetType().Name + ")";
95        foreach (var item in Content)
96          AddVariable(item);
97        AdjustListViewColumnSizes();
98        SortItemsListView(SortOrder.Ascending);
99      }
100    }
101
102    protected override void SetEnabledStateOfControls() {
103      base.SetEnabledStateOfControls();
104      if (Content == null) {
105        addButton.Enabled = false;
106        sortAscendingButton.Enabled = false;
107        sortDescendingButton.Enabled = false;
108        removeButton.Enabled = false;
109        variableListView.Enabled = false;
110      } else {
111        addButton.Enabled = !Locked && !ReadOnly;
112        sortAscendingButton.Enabled = variableListView.Items.Count > 1;
113        sortDescendingButton.Enabled = variableListView.Items.Count > 1;
114        removeButton.Enabled = !Locked && !ReadOnly && variableListView.SelectedItems.Count > 0;
115        variableListView.Enabled = true;
116        variableListView.LabelEdit = !Locked && !ReadOnly;
117      }
118    }
119
120    protected virtual object CreateItem() {
121      if (typeSelectorDialog == null) {
122        typeSelectorDialog = new TypeSelectorDialog { Caption = "Select Item" };
123        typeSelectorDialog.TypeSelector.Caption = "Available Items";
124        typeSelectorDialog.TypeSelector.Configure(typeof(IItem), false, true);
125      }
126
127      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
128        try {
129          return (object)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
130        } catch (Exception ex) {
131          ErrorHandling.ShowErrorDialog(this, ex);
132        }
133      }
134      return null;
135    }
136
137    protected virtual void AddVariable(KeyValuePair<string, object> variable) {
138      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
139      string value = (variable.Value ?? "null").ToString();
140      string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
141      bool serializable = IsSerializable(variable);
142      var listViewItem = new ListViewItem(new[] { variable.Key, value, type }) { ToolTipText = GetToolTipText(variable, serializable), Tag = variable };
143      bool validIdentifier = SafeVariableNameRegex.IsMatch(variable.Key);
144      if (!serializable) listViewItem.ImageIndex = 0;
145      else if (!validIdentifier) listViewItem.ImageIndex = 1;
146      else if (variable.Value != null) listViewItem.ImageIndex = 2;
147      else listViewItem.ImageIndex = 3;
148      variableListView.Items.Add(listViewItem);
149      itemListViewItemMapping[variable.Key] = listViewItem;
150      sortAscendingButton.Enabled = variableListView.Items.Count > 1;
151      sortDescendingButton.Enabled = variableListView.Items.Count > 1;
152      var item = variable.Value as IItem;
153      if (item != null) item.ToStringChanged += item_ToStringChanged;
154    }
155
156    protected virtual void RemoveVariable(KeyValuePair<string, object> variable) {
157      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
158      ListViewItem listViewItem;
159      if (itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem)) {
160        itemListViewItemMapping.Remove(variable.Key);
161        variableListView.Items.Remove(listViewItem);
162        sortAscendingButton.Enabled = variableListView.Items.Count > 1;
163        sortDescendingButton.Enabled = variableListView.Items.Count > 1;
164        var item = variable.Value as IItem;
165        if (item != null) item.ToStringChanged -= item_ToStringChanged;
166      }
167    }
168
169    protected virtual void UpdateVariable(KeyValuePair<string, object> variable) {
170      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
171      ListViewItem listViewItem;
172      if (itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem)) {
173        string value = (variable.Value ?? "null").ToString();
174        string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
175        bool serializable = IsSerializable(variable);
176        if (!serializable) listViewItem.ImageIndex = 0;
177        else if (variable.Value != null) listViewItem.ImageIndex = 2;
178        else listViewItem.ImageIndex = 3;
179        listViewItem.SubItems[1].Text = value;
180        listViewItem.SubItems[2].Text = type;
181        listViewItem.ToolTipText = GetToolTipText(variable, serializable);
182        listViewItem.Tag = variable;
183      } else throw new ArgumentException("A variable with the specified name does not exist.", "variable");
184    }
185
186    #region ListView Events
187    protected virtual void variableListView_SelectedIndexChanged(object sender, EventArgs e) {
188      removeButton.Enabled = (Content != null) && !Locked && !ReadOnly && variableListView.SelectedItems.Count > 0;
189      AdjustListViewColumnSizes();
190    }
191    protected virtual void variableListView_KeyDown(object sender, KeyEventArgs e) {
192      switch (e.KeyCode) {
193        case Keys.Delete:
194          if ((variableListView.SelectedItems.Count > 0) && !Locked && !ReadOnly) {
195            foreach (ListViewItem item in variableListView.SelectedItems)
196              Content.Remove(item.Text);
197          }
198          break;
199        case Keys.F2:
200          var focusedItem = variableListView.FocusedItem;
201          if (variableListView.LabelEdit && focusedItem.Selected)
202            focusedItem.BeginEdit();
203          break;
204        case Keys.A:
205          if (e.Modifiers.HasFlag(Keys.Control)) {
206            foreach (ListViewItem item in variableListView.Items)
207              item.Selected = true;
208          }
209          break;
210      }
211    }
212    protected virtual void variableListView_DoubleClick(object sender, EventArgs e) {
213      if (variableListView.SelectedItems.Count == 1) {
214        var item = variableListView.SelectedItems[0].Tag as KeyValuePair<string, object>?;
215        if (item != null) {
216          var value = item.Value.Value as IContent;
217          if (value != null) {
218            IContentView view = MainFormManager.MainForm.ShowContent(value);
219            if (view != null) {
220              view.ReadOnly = ReadOnly;
221              view.Locked = Locked;
222            }
223          }
224        }
225      }
226    }
227    protected virtual void variableListView_ItemDrag(object sender, ItemDragEventArgs e) {
228      if (!Locked && variableListView.SelectedItems.Count == 1) {
229        var listViewItem = variableListView.SelectedItems[0];
230        var item = (KeyValuePair<string, object>)listViewItem.Tag;
231        var data = new DataObject(HeuristicLab.Common.Constants.DragDropDataFormat, item.Value);
232        DoDragDrop(data, DragDropEffects.Copy);
233      }
234    }
235    protected virtual void variableListView_DragEnter(object sender, DragEventArgs e) {
236      validDragOperation = !Locked && !ReadOnly && e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) != null;
237    }
238    protected virtual void variableListView_DragOver(object sender, DragEventArgs e) {
239      e.Effect = DragDropEffects.None;
240      if (validDragOperation) {
241        if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
242      }
243    }
244    protected virtual void variableListView_DragDrop(object sender, DragEventArgs e) {
245      if (e.Effect == DragDropEffects.Copy) {
246        object item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
247        var cloner = new Cloner();
248        var dc = item as IDeepCloneable;
249        if (dc != null) item = cloner.Clone(dc);
250        var namedItem = item as INamedItem;
251        bool nameValid = namedItem != null && !string.IsNullOrEmpty(namedItem.Name);
252        string name = nameValid ? GenerateNewVariableName(namedItem.Name, false) : GenerateNewVariableName();
253        Content.Add(name, item);
254        var listViewItem = variableListView.FindItemWithText(name);
255        if (!nameValid) listViewItem.BeginEdit();
256      }
257    }
258
259    private readonly Regex SafeVariableNameRegex = new Regex("^[@]?[_a-zA-Z][_a-zA-Z0-9]*$");
260    private const string DefaultVariableName = "enter_name";
261
262    private void variableListView_AfterLabelEdit(object sender, LabelEditEventArgs e) {
263      string name = e.Label;
264      if (!string.IsNullOrEmpty(name) && SafeVariableNameRegex.IsMatch(name)) {
265        var variable = (KeyValuePair<string, object>)variableListView.Items[e.Item].Tag;
266        if (!Content.ContainsKey(name)) {
267          Content.Remove(variable.Key);
268          Content.Add(name, variable.Value);
269        }
270      }
271      e.CancelEdit = true;
272    }
273    #endregion
274
275    #region Button Events
276    protected virtual void addButton_Click(object sender, EventArgs e) {
277      object newVar = CreateItem();
278      if (newVar != null) {
279        string name = GenerateNewVariableName();
280        Content.Add(name, newVar);
281        var item = variableListView.FindItemWithText(name);
282        item.BeginEdit();
283      }
284    }
285    protected virtual void sortAscendingButton_Click(object sender, EventArgs e) {
286      SortItemsListView(SortOrder.Ascending);
287    }
288    protected virtual void sortDescendingButton_Click(object sender, EventArgs e) {
289      SortItemsListView(SortOrder.Descending);
290    }
291    protected virtual void removeButton_Click(object sender, EventArgs e) {
292      if (variableListView.SelectedItems.Count > 0) {
293        foreach (ListViewItem item in variableListView.SelectedItems)
294          Content.Remove(item.Text);
295        variableListView.SelectedItems.Clear();
296      }
297    }
298    #endregion
299
300    #region Content Events
301    protected virtual void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
302      if (InvokeRequired)
303        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsAdded), sender, e);
304      else {
305        foreach (var item in e.Items)
306          AddVariable(item);
307        AdjustListViewColumnSizes();
308      }
309    }
310
311    protected virtual void Content_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
312      if (InvokeRequired)
313        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsReplaced), sender, e);
314      else {
315        foreach (var item in e.Items)
316          UpdateVariable(item);
317        AdjustListViewColumnSizes();
318      }
319    }
320
321    protected virtual void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
322      if (InvokeRequired)
323        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsRemoved), sender, e);
324      else {
325        foreach (var item in e.Items)
326          RemoveVariable(item);
327        AdjustListViewColumnSizes();
328      }
329    }
330    protected virtual void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
331      if (InvokeRequired)
332        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_CollectionReset), sender, e);
333      else {
334        foreach (var item in e.OldItems)
335          RemoveVariable(item);
336        foreach (var item in e.Items)
337          AddVariable(item);
338        AdjustListViewColumnSizes();
339      }
340    }
341
342    private void item_ToStringChanged(object sender, EventArgs e) {
343      foreach (ListViewItem item in variableListView.Items) {
344        var variable = item.Tag as KeyValuePair<string, object>?;
345        if (variable != null && variable.Value.Value == sender) {
346          string value = (variable.Value.Value ?? "null").ToString();
347          item.SubItems[1].Text = value;
348          item.SubItems[2].Text = variable.Value.Value.GetType().ToString();
349          item.ToolTipText = GetToolTipText(variable.Value, item.ImageIndex != 0);
350        }
351      }
352    }
353    #endregion
354
355    #region Helpers
356    protected virtual void SortItemsListView(SortOrder sortOrder) {
357      variableListView.Sorting = SortOrder.None;
358      variableListView.Sorting = sortOrder;
359      variableListView.Sorting = SortOrder.None;
360    }
361    protected virtual void AdjustListViewColumnSizes() {
362      foreach (ColumnHeader ch in variableListView.Columns)
363        ch.Width = -2;
364    }
365
366    private string GetToolTipText(KeyValuePair<string, object> variable, bool serializable) {
367      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
368      string value = (variable.Value ?? "null").ToString();
369      string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
370      string[] lines = {
371        "Name: " + variable.Key,
372        "Value: " + value,
373        "Type: " + type
374      };
375      string toolTipText = string.Join(Environment.NewLine, lines);
376      if (!SafeVariableNameRegex.IsMatch(variable.Key))
377        toolTipText = "Caution: Identifier is no valid C# identifier!" + Environment.NewLine + toolTipText;
378      if (!serializable)
379        toolTipText = "Caution: Type is not serializable!" + Environment.NewLine + toolTipText;
380      return toolTipText;
381    }
382
383    private string GenerateNewVariableName(string defaultName = DefaultVariableName, bool generateValidIdentifier = true) {
384      if (generateValidIdentifier && !SafeVariableNameRegex.IsMatch(defaultName))
385        defaultName = DefaultVariableName;
386      if (Content.ContainsKey(defaultName)) {
387        int i = 1;
388        string formatString = generateValidIdentifier ? "{0}{1}" : "{0} ({1})";
389        string newName;
390        do {
391          newName = string.Format(formatString, defaultName, i++);
392        } while (Content.ContainsKey(newName));
393        return newName;
394      }
395      return defaultName;
396    }
397
398    private bool IsSerializable(KeyValuePair<string, object> variable) {
399      var ser = new Serializer(variable, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat()), "ROOT", true);
400      try {
401        return ser.Count() > 0;
402      } catch (PersistenceException) {
403        return false;
404      }
405    }
406    #endregion
407  }
408}
Note: See TracBrowser for help on using the repository browser.