Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2262: worked on variable management of VariableStoreView

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