Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2239: applied a slightly modified version of bburlacu's patch

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