Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Scripting.Views/3.3/VariableStoreView.cs @ 12296

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

#2199: fixed VariableStoreView to correctly label serializable variables

File size: 17.8 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.Object,
61        HeuristicLab.Common.Resources.VSImageLibrary.Nothing
62      });
63    }
64
65    protected override void Dispose(bool disposing) {
66      if (disposing) {
67        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
68        if (components != null) components.Dispose();
69      }
70      base.Dispose(disposing);
71    }
72
73    protected override void DeregisterContentEvents() {
74      Content.ItemsAdded -= Content_ItemsAdded;
75      Content.ItemsReplaced -= Content_ItemsReplaced;
76      Content.ItemsRemoved -= Content_ItemsRemoved;
77      Content.CollectionReset -= Content_CollectionReset;
78      base.DeregisterContentEvents();
79    }
80    protected override void RegisterContentEvents() {
81      base.RegisterContentEvents();
82      Content.ItemsAdded += Content_ItemsAdded;
83      Content.ItemsReplaced += Content_ItemsReplaced;
84      Content.ItemsRemoved += Content_ItemsRemoved;
85      Content.CollectionReset += Content_CollectionReset;
86    }
87
88    protected override void OnContentChanged() {
89      base.OnContentChanged();
90      variableListView.Items.Clear();
91      itemListViewItemMapping.Clear();
92      RebuildImageList();
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      if (serializable) {
144        listViewItem.ImageIndex = variable.Value == null ? 2 : 1;
145      } else listViewItem.ImageIndex = 0;
146      variableListView.Items.Add(listViewItem);
147      itemListViewItemMapping[variable.Key] = listViewItem;
148      sortAscendingButton.Enabled = variableListView.Items.Count > 1;
149      sortDescendingButton.Enabled = variableListView.Items.Count > 1;
150      var item = variable.Value as IItem;
151      if (item != null) item.ToStringChanged += item_ToStringChanged;
152    }
153
154    protected virtual void RemoveVariable(KeyValuePair<string, object> variable) {
155      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
156      ListViewItem listViewItem;
157      if (itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem)) {
158        itemListViewItemMapping.Remove(variable.Key);
159        variableListView.Items.Remove(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
167    protected virtual void UpdateVariable(KeyValuePair<string, object> variable) {
168      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
169      ListViewItem listViewItem;
170      if (itemListViewItemMapping.TryGetValue(variable.Key, out listViewItem)) {
171        string value = (variable.Value ?? "null").ToString();
172        string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
173        bool serializable = IsSerializable(variable);
174        if (serializable) {
175          listViewItem.ImageIndex = variable.Value == null ? 2 : 1;
176        } else listViewItem.ImageIndex = 0;
177        listViewItem.SubItems[1].Text = value;
178        listViewItem.SubItems[2].Text = type;
179        listViewItem.ToolTipText = GetToolTipText(variable, serializable);
180        listViewItem.Tag = variable;
181      } else throw new ArgumentException("A variable with the specified name does not exist.", "variable");
182    }
183
184    #region ListView Events
185    protected virtual void variableListView_SelectedIndexChanged(object sender, EventArgs e) {
186      removeButton.Enabled = (Content != null) && !Locked && !ReadOnly && variableListView.SelectedItems.Count > 0;
187      AdjustListViewColumnSizes();
188    }
189    protected virtual void variableListView_KeyDown(object sender, KeyEventArgs e) {
190      if (e.KeyCode == Keys.Delete) {
191        if ((variableListView.SelectedItems.Count > 0) && !Locked && !ReadOnly) {
192          foreach (ListViewItem item in variableListView.SelectedItems)
193            Content.Remove(item.Text);
194        }
195      }
196    }
197    protected virtual void variableListView_DoubleClick(object sender, EventArgs e) {
198      if (variableListView.SelectedItems.Count == 1) {
199        var item = variableListView.SelectedItems[0].Tag as KeyValuePair<string, object>?;
200        if (item != null) {
201          var value = item.Value.Value as IContent;
202          if (value != null) {
203            IContentView view = MainFormManager.MainForm.ShowContent(value);
204            if (view != null) {
205              view.ReadOnly = ReadOnly;
206              view.Locked = Locked;
207            }
208          }
209        }
210      }
211    }
212    protected virtual void variableListView_ItemDrag(object sender, ItemDragEventArgs e) {
213      if (!Locked) {
214        var items = new List<object>();
215        foreach (ListViewItem listViewItem in variableListView.SelectedItems) {
216          var item = (KeyValuePair<string, object>)listViewItem.Tag as KeyValuePair<string, object>?;
217          if (item != null) items.Add(item.Value.Value);
218        }
219
220        if (items.Count > 0) {
221          var data = new DataObject();
222          if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
223          else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
224          if (ReadOnly) {
225            DoDragDrop(data, DragDropEffects.Copy);
226          } else {
227            var result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
228            if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
229              foreach (string item in items) Content.Remove(item);
230            }
231          }
232        }
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.KeyState & 32) == 32) e.Effect = DragDropEffects.Link;  // ALT key
242        else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
243        else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
244        else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
245        else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
246      }
247    }
248    protected virtual void variableListView_DragDrop(object sender, DragEventArgs e) {
249      if (e.Effect != DragDropEffects.None) {
250        object item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
251        if (e.Effect.HasFlag(DragDropEffects.Copy)) {
252          var cloner = new Cloner();
253          var dc = item as IDeepCloneable;
254          if (dc != null) item = cloner.Clone(dc);
255        }
256        string name = GenerateNewVariableName();
257        Content.Add(name, item);
258        var listViewItem = variableListView.FindItemWithText(name);
259        listViewItem.BeginEdit();
260      }
261    }
262
263    private readonly Regex SafeVariableNameRegex = new Regex("^[@]?[_a-zA-Z][_a-zA-Z0-9]*$");
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        RebuildImageList();
330        AdjustListViewColumnSizes();
331      }
332    }
333    protected virtual void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, object>> e) {
334      if (InvokeRequired)
335        Invoke(new CollectionItemsChangedEventHandler<KeyValuePair<string, object>>(Content_CollectionReset), sender, e);
336      else {
337        foreach (var item in e.OldItems)
338          RemoveVariable(item);
339        RebuildImageList();
340        foreach (var item in e.Items)
341          AddVariable(item);
342        AdjustListViewColumnSizes();
343      }
344    }
345
346    private void item_ToStringChanged(object sender, EventArgs e) {
347      foreach (ListViewItem item in variableListView.Items) {
348        var variable = item.Tag as KeyValuePair<string, object>?;
349        if (variable != null && variable.Value.Value == sender) {
350          string value = (variable.Value.Value ?? "null").ToString();
351          item.SubItems[1].Text = value;
352          item.SubItems[2].Text = variable.Value.Value.GetType().ToString();
353          item.ToolTipText = GetToolTipText(variable.Value, item.ImageIndex != 0);
354          return;
355        }
356      }
357    }
358    #endregion
359
360    #region Helpers
361    protected virtual void SortItemsListView(SortOrder sortOrder) {
362      variableListView.Sorting = SortOrder.None;
363      variableListView.Sorting = sortOrder;
364      variableListView.Sorting = SortOrder.None;
365    }
366    protected virtual void AdjustListViewColumnSizes() {
367      foreach (ColumnHeader ch in variableListView.Columns)
368        ch.Width = -2;
369    }
370    protected virtual void RebuildImageList() {
371      variableListView.SmallImageList.Images.Clear();
372      variableListView.SmallImageList.Images.AddRange(new Image[] {
373        HeuristicLab.Common.Resources.VSImageLibrary.Error,
374        HeuristicLab.Common.Resources.VSImageLibrary.Object,
375        HeuristicLab.Common.Resources.VSImageLibrary.Nothing
376      });
377      foreach (ListViewItem listViewItem in variableListView.Items) {
378        var variable = (KeyValuePair<string, object>)listViewItem.Tag;
379        bool serializable = IsSerializable(variable);
380        if (serializable) {
381          listViewItem.ImageIndex = variable.Value == null ? 2 : 1;
382        } else listViewItem.ImageIndex = 0;
383      }
384    }
385
386    private string GetToolTipText(KeyValuePair<string, object> variable, bool serializable) {
387      if (string.IsNullOrEmpty(variable.Key)) throw new ArgumentException("The variable must have a name.", "variable");
388      string value = (variable.Value ?? "null").ToString();
389      string type = variable.Value == null ? "null" : variable.Value.GetType().ToString();
390      string[] lines = {
391        "Name: " + variable.Key,
392        "Value: " + value,
393        "Type: " + type
394      };
395      string toolTipText = string.Join(Environment.NewLine, lines);
396      if (!serializable)
397        toolTipText = "Caution: Type is not serializable!" + Environment.NewLine + toolTipText;
398      return toolTipText;
399    }
400
401    private string GenerateNewVariableName(string defaultName = "enter_name") {
402      if (Content.ContainsKey(defaultName)) {
403        int i = 1;
404        string newName;
405        do {
406          newName = defaultName + i++;
407        } while (Content.ContainsKey(newName));
408        return newName;
409      }
410      return defaultName;
411    }
412
413    private bool IsSerializable(KeyValuePair<string, object> variable) {
414      var ser = new Serializer(variable, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat()), "ROOT", true);
415      try {
416        return ser.Count() > 0;
417      } catch (PersistenceException) {
418        return false;
419      }
420    }
421    #endregion
422  }
423}
Note: See TracBrowser for help on using the repository browser.