Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 12055 was 12012, checked in by ascheibe, 10 years ago

#2212 merged r12008, r12009, r12010 back into trunk

File size: 20.0 KB
RevLine 
[10332]1#region License Information
2/* HeuristicLab
[12012]3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[10332]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.Linq;
[10506]25using System.Text.RegularExpressions;
[10332]26using System.Windows.Forms;
27using HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Core.Views;
31using HeuristicLab.MainForm;
32using HeuristicLab.MainForm.WindowsForms;
[10358]33using HeuristicLab.Persistence.Core;
34using HeuristicLab.Persistence.Default.Xml;
[10332]35using HeuristicLab.PluginInfrastructure;
36
[10506]37namespace HeuristicLab.Scripting.Views {
[10332]38  [View("ItemCollection View")]
39  [Content(typeof(VariableStore), true)]
40  public partial class VariableStoreView : AsynchronousContentView {
[11479]41    #region Image Names
42    private const string ErrorImageName = "Error";
43    private const string WarningImageName = "Warning";
44    private const string HeuristicLabObjectImageName = "HeuristicLabObject";
45    private const string ObjectImageName = "Object";
46    private const string NothingImageName = "Nothing";
47    #endregion
48
[11826]49    private readonly Regex SafeVariableNameRegex = new Regex("^[@]?[_a-zA-Z][_a-zA-Z0-9]*$");
50    private const string DefaultVariableName = "enter_name";
[11437]51    protected readonly Dictionary<string, ListViewItem> itemListViewItemMapping;
52    protected readonly Dictionary<Type, bool> serializableLookup;
[10332]53    protected TypeSelectorDialog typeSelectorDialog;
54    protected bool validDragOperation;
55
56    public new VariableStore Content {
57      get { return (VariableStore)base.Content; }
58      set { base.Content = value; }
59    }
60
61    public ListView ItemsListView {
62      get { return variableListView; }
63    }
64
65    public VariableStoreView() {
66      InitializeComponent();
67      itemListViewItemMapping = new Dictionary<string, ListViewItem>();
[11437]68      serializableLookup = new Dictionary<Type, bool>();
[11479]69
70      var images = variableListView.SmallImageList.Images;
71      images.Add(ErrorImageName, Common.Resources.VSImageLibrary.Error);
72      images.Add(WarningImageName, Common.Resources.VSImageLibrary.Warning);
73      images.Add(HeuristicLabObjectImageName, Common.Resources.HeuristicLab.Icon.ToBitmap());
74      images.Add(ObjectImageName, Common.Resources.VSImageLibrary.Object);
75      images.Add(NothingImageName, Common.Resources.VSImageLibrary.Nothing);
[10332]76    }
77
78    protected override void Dispose(bool disposing) {
79      if (disposing) {
80        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
81        if (components != null) components.Dispose();
82      }
83      base.Dispose(disposing);
84    }
85
86    protected override void DeregisterContentEvents() {
87      Content.ItemsAdded -= Content_ItemsAdded;
88      Content.ItemsReplaced -= Content_ItemsReplaced;
89      Content.ItemsRemoved -= Content_ItemsRemoved;
90      Content.CollectionReset -= Content_CollectionReset;
91      base.DeregisterContentEvents();
92    }
93    protected override void RegisterContentEvents() {
94      base.RegisterContentEvents();
95      Content.ItemsAdded += Content_ItemsAdded;
96      Content.ItemsReplaced += Content_ItemsReplaced;
97      Content.ItemsRemoved += Content_ItemsRemoved;
98      Content.CollectionReset += Content_CollectionReset;
99    }
100
101    protected override void OnContentChanged() {
102      base.OnContentChanged();
103      variableListView.Items.Clear();
104      itemListViewItemMapping.Clear();
105      if (Content != null) {
106        Caption += " (" + Content.GetType().Name + ")";
107        foreach (var item in Content)
108          AddVariable(item);
109        AdjustListViewColumnSizes();
110        SortItemsListView(SortOrder.Ascending);
111      }
112    }
113
114    protected override void SetEnabledStateOfControls() {
115      base.SetEnabledStateOfControls();
116      if (Content == null) {
117        addButton.Enabled = false;
118        sortAscendingButton.Enabled = false;
119        sortDescendingButton.Enabled = false;
120        removeButton.Enabled = false;
[11721]121        variableListView.LabelEdit = false;
[10332]122      } else {
[11480]123        bool enabled = !Locked && !ReadOnly;
124        addButton.Enabled = enabled;
[10332]125        sortAscendingButton.Enabled = variableListView.Items.Count > 1;
126        sortDescendingButton.Enabled = variableListView.Items.Count > 1;
[11480]127        removeButton.Enabled = enabled && variableListView.SelectedItems.Count > 0;
128        variableListView.LabelEdit = enabled;
[10332]129      }
130    }
131
132    protected virtual object CreateItem() {
133      if (typeSelectorDialog == null) {
134        typeSelectorDialog = new TypeSelectorDialog { Caption = "Select Item" };
135        typeSelectorDialog.TypeSelector.Caption = "Available Items";
136        typeSelectorDialog.TypeSelector.Configure(typeof(IItem), false, true);
137      }
138
139      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
140        try {
141          return (object)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
142        } catch (Exception ex) {
143          ErrorHandling.ShowErrorDialog(this, ex);
144        }
145      }
146      return null;
147    }
148
149    protected virtual void AddVariable(KeyValuePair<string, object> variable) {
150      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
[10358]151      bool serializable = IsSerializable(variable);
[11479]152
[11480]153      var listViewItem = new ListViewItem();
154      AssignVariableToListViewItem(listViewItem, variable);
[11479]155      SetImageKey(listViewItem, serializable);
156      SetToolTipText(listViewItem, serializable);
[10332]157      variableListView.Items.Add(listViewItem);
[11479]158
[10332]159      itemListViewItemMapping[variable.Key] = listViewItem;
160      sortAscendingButton.Enabled = variableListView.Items.Count > 1;
161      sortDescendingButton.Enabled = variableListView.Items.Count > 1;
162      var item = variable.Value as IItem;
163      if (item != null) item.ToStringChanged += item_ToStringChanged;
164    }
165
166    protected virtual void RemoveVariable(KeyValuePair<string, object> variable) {
167      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
[11480]168
[10332]169      ListViewItem listViewItem;
[11480]170      if (!itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem)) return;
171
172      itemListViewItemMapping.Remove(variable.Key);
173      variableListView.Items.Remove(listViewItem);
174      sortAscendingButton.Enabled = variableListView.Items.Count > 1;
175      sortDescendingButton.Enabled = variableListView.Items.Count > 1;
176      var item = variable.Value as IItem;
177      if (item != null) item.ToStringChanged -= item_ToStringChanged;
[10332]178    }
179
180    protected virtual void UpdateVariable(KeyValuePair<string, object> variable) {
181      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
[11480]182
[10332]183      ListViewItem listViewItem;
[11480]184      if (!itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem))
185        throw new ArgumentException("A variable with the specified name does not exist.", "variable");
[11479]186
[11480]187      bool serializable = IsSerializable(variable);
188      AssignVariableToListViewItem(listViewItem, variable);
189      SetImageKey(listViewItem, serializable);
190      SetToolTipText(listViewItem, serializable);
191
[10332]192    }
193
194    #region ListView Events
195    protected virtual void variableListView_SelectedIndexChanged(object sender, EventArgs e) {
[10358]196      removeButton.Enabled = (Content != null) && !Locked && !ReadOnly && variableListView.SelectedItems.Count > 0;
[10332]197      AdjustListViewColumnSizes();
198    }
199    protected virtual void variableListView_KeyDown(object sender, KeyEventArgs e) {
[11436]200      switch (e.KeyCode) {
201        case Keys.Delete:
202          if ((variableListView.SelectedItems.Count > 0) && !Locked && !ReadOnly) {
203            foreach (ListViewItem item in variableListView.SelectedItems)
204              Content.Remove(item.Text);
205          }
206          break;
207        case Keys.F2:
[11474]208          if (variableListView.SelectedItems.Count != 1) return;
209          var selectedItem = variableListView.SelectedItems[0];
210          if (variableListView.LabelEdit)
211            selectedItem.BeginEdit();
[11436]212          break;
213        case Keys.A:
214          if (e.Modifiers.HasFlag(Keys.Control)) {
215            foreach (ListViewItem item in variableListView.Items)
216              item.Selected = true;
217          }
218          break;
[10332]219      }
220    }
221    protected virtual void variableListView_DoubleClick(object sender, EventArgs e) {
[11480]222      if (variableListView.SelectedItems.Count != 1) return;
223      var item = variableListView.SelectedItems[0].Tag as KeyValuePair<string, object>?;
224      if (item == null) return;
225
226      var value = item.Value.Value as IContent;
227      if (value == null) return;
228
229      IContentView view = MainFormManager.MainForm.ShowContent(value);
230      if (view == null) return;
231
232      view.ReadOnly = ReadOnly;
233      view.Locked = Locked;
[10332]234    }
235    protected virtual void variableListView_ItemDrag(object sender, ItemDragEventArgs e) {
[11480]236      if (Locked || variableListView.SelectedItems.Count != 1) return;
237
238      var listViewItem = variableListView.SelectedItems[0];
239      var item = (KeyValuePair<string, object>)listViewItem.Tag;
240      if (!(item.Value is IDeepCloneable)) return;
241      var data = new DataObject(HeuristicLab.Common.Constants.DragDropDataFormat, item);
242      DoDragDrop(data, DragDropEffects.Copy);
[10332]243    }
244    protected virtual void variableListView_DragEnter(object sender, DragEventArgs e) {
[11734]245      validDragOperation = !Locked && !ReadOnly;
246
247      object item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
248      if (item is KeyValuePair<string, object>) {
249        var variable = (KeyValuePair<string, object>)item;
250        validDragOperation &= variable.Value is IDeepCloneable;
251      } else {
252        validDragOperation &= item is IDeepCloneable;
253      }
[10332]254    }
255    protected virtual void variableListView_DragOver(object sender, DragEventArgs e) {
256      e.Effect = DragDropEffects.None;
257      if (validDragOperation) {
[11734]258        if (e.AllowedEffect.HasFlag(DragDropEffects.Copy))
259          e.Effect = DragDropEffects.Copy;
[10332]260      }
261    }
262    protected virtual void variableListView_DragDrop(object sender, DragEventArgs e) {
[11480]263      if (e.Effect != DragDropEffects.Copy) return;
264      object item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
[11474]265
[11480]266      string variableName;
267      bool editLabel;
[11479]268
[11480]269      if (item is KeyValuePair<string, object>) {
270        var variable = (KeyValuePair<string, object>)item;
271        variableName = GenerateNewVariableName(out editLabel, variable.Key, false);
272        item = variable.Value;
273      } else {
274        var namedItem = item as INamedItem;
275        if (namedItem != null)
276          variableName = GenerateNewVariableName(out editLabel, namedItem.Name, false);
277        else
278          variableName = GenerateNewVariableName(out editLabel);
279      }
[11474]280
[11480]281      var cloneable = item as IDeepCloneable;
[11734]282      if (cloneable == null) return;
[11479]283
[11734]284      var clonedItem = cloneable.Clone();
285      Content.Add(variableName, clonedItem);
[11480]286
287      var listViewItem = variableListView.FindItemWithText(variableName);
288      variableListView.SelectedItems.Clear();
289      if (editLabel) listViewItem.BeginEdit();
[10332]290    }
291
292    private void variableListView_AfterLabelEdit(object sender, LabelEditEventArgs e) {
[10506]293      string name = e.Label;
[11471]294      if (!string.IsNullOrEmpty(name)) {
[10332]295        var variable = (KeyValuePair<string, object>)variableListView.Items[e.Item].Tag;
[10506]296        if (!Content.ContainsKey(name)) {
[10332]297          Content.Remove(variable.Key);
[10506]298          Content.Add(name, variable.Value);
[10332]299        }
300      }
301      e.CancelEdit = true;
302    }
303    #endregion
304
305    #region Button Events
306    protected virtual void addButton_Click(object sender, EventArgs e) {
[11479]307      object variableValue = CreateItem();
308      if (variableValue == null) return;
[11474]309
[11479]310      string variableName;
311      var namedItem = variableValue as INamedItem;
312      if (namedItem != null)
313        variableName = GenerateNewVariableName(namedItem.Name, false);
314      else
315        variableName = GenerateNewVariableName();
[11474]316
[11479]317      Content.Add(variableName, variableValue);
318
319      var item = variableListView.FindItemWithText(variableName);
320      variableListView.SelectedItems.Clear();
[11474]321      item.BeginEdit();
[10332]322    }
323    protected virtual void sortAscendingButton_Click(object sender, EventArgs e) {
324      SortItemsListView(SortOrder.Ascending);
325    }
326    protected virtual void sortDescendingButton_Click(object sender, EventArgs e) {
327      SortItemsListView(SortOrder.Descending);
328    }
329    protected virtual void removeButton_Click(object sender, EventArgs e) {
330      if (variableListView.SelectedItems.Count > 0) {
331        foreach (ListViewItem item in variableListView.SelectedItems)
332          Content.Remove(item.Text);
333        variableListView.SelectedItems.Clear();
334      }
335    }
336    #endregion
337
338    #region Content Events
339    protected virtual void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
340      if (InvokeRequired)
341        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsAdded), sender, e);
342      else {
343        foreach (var item in e.Items)
344          AddVariable(item);
345        AdjustListViewColumnSizes();
346      }
347    }
348
349    protected virtual void Content_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
350      if (InvokeRequired)
351        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsReplaced), sender, e);
352      else {
353        foreach (var item in e.Items)
354          UpdateVariable(item);
355        AdjustListViewColumnSizes();
356      }
357    }
358
359    protected virtual void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
360      if (InvokeRequired)
361        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_ItemsRemoved), sender, e);
362      else {
363        foreach (var item in e.Items)
364          RemoveVariable(item);
365        AdjustListViewColumnSizes();
366      }
367    }
368    protected virtual void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
369      if (InvokeRequired)
370        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_CollectionReset), sender, e);
371      else {
372        foreach (var item in e.OldItems)
373          RemoveVariable(item);
374        foreach (var item in e.Items)
375          AddVariable(item);
376        AdjustListViewColumnSizes();
377      }
378    }
379
380    private void item_ToStringChanged(object sender, EventArgs e) {
381      foreach (ListViewItem item in variableListView.Items) {
382        var variable = item.Tag as KeyValuePair<string, object>?;
[11480]383        if (variable == null || variable.Value.Value != sender) continue;
384
385        string value = (variable.Value.Value ?? "null").ToString();
386        item.SubItems[1].Text = value;
387        item.SubItems[2].Text = variable.Value.Value.GetType().ToString();
388        SetToolTipText(item, item.ImageIndex != 0);
[10332]389      }
390    }
391    #endregion
392
393    #region Helpers
394    protected virtual void SortItemsListView(SortOrder sortOrder) {
395      variableListView.Sorting = SortOrder.None;
396      variableListView.Sorting = sortOrder;
397      variableListView.Sorting = SortOrder.None;
398    }
399    protected virtual void AdjustListViewColumnSizes() {
[10506]400      foreach (ColumnHeader ch in variableListView.Columns)
401        ch.Width = -2;
[10332]402    }
403
[11480]404    protected virtual void AssignVariableToListViewItem(ListViewItem listViewItem, KeyValuePair<string, object> variable) {
405      string value = (variable.Value ?? "null").ToString();
406      string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
407
408      listViewItem.Tag = variable;
409
410      var subItems = listViewItem.SubItems;
411      subItems[0].Text = variable.Key;
412      if (subItems.Count == 1) { // variable information is added; subitems do not exist yet
413        subItems.AddRange(new[] { value, type });
414      } else { // variable information is updated; subitems are changed
415        subItems[1].Text = value;
416        subItems[2].Text = type;
417      }
418    }
419
[11479]420    protected virtual void SetImageKey(ListViewItem listViewItem, bool serializable) {
421      var variable = (KeyValuePair<string, object>)listViewItem.Tag;
422      if (!serializable) listViewItem.ImageKey = ErrorImageName;
423      else if (!SafeVariableNameRegex.IsMatch(variable.Key)) listViewItem.ImageKey = WarningImageName;
424      else if (variable.Value is IItem) listViewItem.ImageKey = HeuristicLabObjectImageName;
425      else if (variable.Value != null) listViewItem.ImageKey = ObjectImageName;
426      else listViewItem.ImageKey = NothingImageName;
427    }
428
429    protected virtual void SetToolTipText(ListViewItem listViewItem, bool serializable) {
430      var variable = (KeyValuePair<string, object>)listViewItem.Tag;
[10332]431      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
[11480]432      string value = listViewItem.SubItems[1].Text;
433      string type = listViewItem.SubItems[2].Text;
434
[10332]435      string[] lines = {
436        "Name: " + variable.Key,
437        "Value: " + value,
[10358]438        "Type: " + type
[10332]439      };
[11480]440
[10358]441      string toolTipText = string.Join(Environment.NewLine, lines);
[11436]442      if (!SafeVariableNameRegex.IsMatch(variable.Key))
443        toolTipText = "Caution: Identifier is no valid C# identifier!" + Environment.NewLine + toolTipText;
[10358]444      if (!serializable)
[10727]445        toolTipText = "Caution: Type is not serializable!" + Environment.NewLine + toolTipText;
[11479]446      listViewItem.ToolTipText = toolTipText;
[10332]447    }
448
[11436]449    private string GenerateNewVariableName(string defaultName = DefaultVariableName, bool generateValidIdentifier = true) {
[11479]450      bool editLabel;
451      return GenerateNewVariableName(out editLabel, defaultName, generateValidIdentifier);
452    }
453
454    private string GenerateNewVariableName(out bool defaultNameExists, string defaultName = DefaultVariableName, bool generateValidIdentifier = true) {
455      if (string.IsNullOrEmpty(defaultName) || generateValidIdentifier && !SafeVariableNameRegex.IsMatch(defaultName))
[11436]456        defaultName = DefaultVariableName;
[10332]457      if (Content.ContainsKey(defaultName)) {
458        int i = 1;
[11436]459        string formatString = generateValidIdentifier ? "{0}{1}" : "{0} ({1})";
[10332]460        string newName;
461        do {
[11436]462          newName = string.Format(formatString, defaultName, i++);
[10332]463        } while (Content.ContainsKey(newName));
[11479]464        defaultNameExists = true;
[10332]465        return newName;
466      }
[11479]467      defaultNameExists = false;
[10332]468      return defaultName;
469    }
[10358]470
471    private bool IsSerializable(KeyValuePair<string, object> variable) {
[11472]472      Type type = null;
[11437]473      bool serializable;
[11472]474
475      if (variable.Value != null) {
476        type = variable.Value.GetType();
477        if (serializableLookup.TryGetValue(type, out serializable))
478          return serializable;
479      }
480
[10358]481      var ser = new Serializer(variable, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat()), "ROOT", true);
482      try {
[11472]483        serializable = ser.Count() > 0; // try to create all serialization tokens
[10358]484      } catch (PersistenceException) {
[11472]485        serializable = false;
[10358]486      }
[11472]487
488      if (type != null)
489        serializableLookup[type] = serializable;
490      return serializable;
[10358]491    }
[10332]492    #endregion
493  }
494}
Note: See TracBrowser for help on using the repository browser.