Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 12015 was 12012, checked in by ascheibe, 9 years ago

#2212 merged r12008, r12009, r12010 back into trunk

File size: 20.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Linq;
25using System.Text.RegularExpressions;
26using System.Windows.Forms;
27using HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Core.Views;
31using HeuristicLab.MainForm;
32using HeuristicLab.MainForm.WindowsForms;
33using HeuristicLab.Persistence.Core;
34using HeuristicLab.Persistence.Default.Xml;
35using HeuristicLab.PluginInfrastructure;
36
37namespace HeuristicLab.Scripting.Views {
38  [View("ItemCollection View")]
39  [Content(typeof(VariableStore), true)]
40  public partial class VariableStoreView : AsynchronousContentView {
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
49    private readonly Regex SafeVariableNameRegex = new Regex("^[@]?[_a-zA-Z][_a-zA-Z0-9]*$");
50    private const string DefaultVariableName = "enter_name";
51    protected readonly Dictionary<string, ListViewItem> itemListViewItemMapping;
52    protected readonly Dictionary<Type, bool> serializableLookup;
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>();
68      serializableLookup = new Dictionary<Type, bool>();
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);
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;
121        variableListView.LabelEdit = false;
122      } else {
123        bool enabled = !Locked && !ReadOnly;
124        addButton.Enabled = enabled;
125        sortAscendingButton.Enabled = variableListView.Items.Count > 1;
126        sortDescendingButton.Enabled = variableListView.Items.Count > 1;
127        removeButton.Enabled = enabled && variableListView.SelectedItems.Count > 0;
128        variableListView.LabelEdit = enabled;
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");
151      bool serializable = IsSerializable(variable);
152
153      var listViewItem = new ListViewItem();
154      AssignVariableToListViewItem(listViewItem, variable);
155      SetImageKey(listViewItem, serializable);
156      SetToolTipText(listViewItem, serializable);
157      variableListView.Items.Add(listViewItem);
158
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");
168
169      ListViewItem listViewItem;
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;
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");
182
183      ListViewItem listViewItem;
184      if (!itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem))
185        throw new ArgumentException("A variable with the specified name does not exist.", "variable");
186
187      bool serializable = IsSerializable(variable);
188      AssignVariableToListViewItem(listViewItem, variable);
189      SetImageKey(listViewItem, serializable);
190      SetToolTipText(listViewItem, serializable);
191
192    }
193
194    #region ListView Events
195    protected virtual void variableListView_SelectedIndexChanged(object sender, EventArgs e) {
196      removeButton.Enabled = (Content != null) && !Locked && !ReadOnly && variableListView.SelectedItems.Count > 0;
197      AdjustListViewColumnSizes();
198    }
199    protected virtual void variableListView_KeyDown(object sender, KeyEventArgs e) {
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:
208          if (variableListView.SelectedItems.Count != 1) return;
209          var selectedItem = variableListView.SelectedItems[0];
210          if (variableListView.LabelEdit)
211            selectedItem.BeginEdit();
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;
219      }
220    }
221    protected virtual void variableListView_DoubleClick(object sender, EventArgs e) {
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;
234    }
235    protected virtual void variableListView_ItemDrag(object sender, ItemDragEventArgs e) {
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);
243    }
244    protected virtual void variableListView_DragEnter(object sender, DragEventArgs e) {
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      }
254    }
255    protected virtual void variableListView_DragOver(object sender, DragEventArgs e) {
256      e.Effect = DragDropEffects.None;
257      if (validDragOperation) {
258        if (e.AllowedEffect.HasFlag(DragDropEffects.Copy))
259          e.Effect = DragDropEffects.Copy;
260      }
261    }
262    protected virtual void variableListView_DragDrop(object sender, DragEventArgs e) {
263      if (e.Effect != DragDropEffects.Copy) return;
264      object item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
265
266      string variableName;
267      bool editLabel;
268
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      }
280
281      var cloneable = item as IDeepCloneable;
282      if (cloneable == null) return;
283
284      var clonedItem = cloneable.Clone();
285      Content.Add(variableName, clonedItem);
286
287      var listViewItem = variableListView.FindItemWithText(variableName);
288      variableListView.SelectedItems.Clear();
289      if (editLabel) listViewItem.BeginEdit();
290    }
291
292    private void variableListView_AfterLabelEdit(object sender, LabelEditEventArgs e) {
293      string name = e.Label;
294      if (!string.IsNullOrEmpty(name)) {
295        var variable = (KeyValuePair<string, object>)variableListView.Items[e.Item].Tag;
296        if (!Content.ContainsKey(name)) {
297          Content.Remove(variable.Key);
298          Content.Add(name, variable.Value);
299        }
300      }
301      e.CancelEdit = true;
302    }
303    #endregion
304
305    #region Button Events
306    protected virtual void addButton_Click(object sender, EventArgs e) {
307      object variableValue = CreateItem();
308      if (variableValue == null) return;
309
310      string variableName;
311      var namedItem = variableValue as INamedItem;
312      if (namedItem != null)
313        variableName = GenerateNewVariableName(namedItem.Name, false);
314      else
315        variableName = GenerateNewVariableName();
316
317      Content.Add(variableName, variableValue);
318
319      var item = variableListView.FindItemWithText(variableName);
320      variableListView.SelectedItems.Clear();
321      item.BeginEdit();
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>?;
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);
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() {
400      foreach (ColumnHeader ch in variableListView.Columns)
401        ch.Width = -2;
402    }
403
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
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;
431      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
432      string value = listViewItem.SubItems[1].Text;
433      string type = listViewItem.SubItems[2].Text;
434
435      string[] lines = {
436        "Name: " + variable.Key,
437        "Value: " + value,
438        "Type: " + type
439      };
440
441      string toolTipText = string.Join(Environment.NewLine, lines);
442      if (!SafeVariableNameRegex.IsMatch(variable.Key))
443        toolTipText = "Caution: Identifier is no valid C# identifier!" + Environment.NewLine + toolTipText;
444      if (!serializable)
445        toolTipText = "Caution: Type is not serializable!" + Environment.NewLine + toolTipText;
446      listViewItem.ToolTipText = toolTipText;
447    }
448
449    private string GenerateNewVariableName(string defaultName = DefaultVariableName, bool generateValidIdentifier = true) {
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))
456        defaultName = DefaultVariableName;
457      if (Content.ContainsKey(defaultName)) {
458        int i = 1;
459        string formatString = generateValidIdentifier ? "{0}{1}" : "{0} ({1})";
460        string newName;
461        do {
462          newName = string.Format(formatString, defaultName, i++);
463        } while (Content.ContainsKey(newName));
464        defaultNameExists = true;
465        return newName;
466      }
467      defaultNameExists = false;
468      return defaultName;
469    }
470
471    private bool IsSerializable(KeyValuePair<string, object> variable) {
472      Type type = null;
473      bool serializable;
474
475      if (variable.Value != null) {
476        type = variable.Value.GetType();
477        if (serializableLookup.TryGetValue(type, out serializable))
478          return serializable;
479      }
480
481      var ser = new Serializer(variable, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat()), "ROOT", true);
482      try {
483        serializable = ser.Count() > 0; // try to create all serialization tokens
484      } catch (PersistenceException) {
485        serializable = false;
486      }
487
488      if (type != null)
489        serializableLookup[type] = serializable;
490      return serializable;
491    }
492    #endregion
493  }
494}
Note: See TracBrowser for help on using the repository browser.