source: trunk/HeuristicLab.Core.Views/3.3/ItemArrayView.cs @ 17008

Last change on this file since 17008 was 17008, checked in by abeham, 15 months ago

#2949: Disable autosizing when there is only one column and use width of list view as size of column. In addition no update occurs on ToStringChanged when there is only one column (most common case)

File size: 21.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 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;
27using System.Windows.Forms;
28using HeuristicLab.Collections;
29using HeuristicLab.MainForm;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Core.Views {
33  [View("ItemArray View")]
34  [Content(typeof(ItemArray<>), true)]
35  [Content(typeof(IItemArray<>), false)]
36  [Content(typeof(ReadOnlyItemArray<>), true)]
37  public partial class ItemArrayView<T> : ItemView where T : class, IItem {
38    protected Dictionary<T, List<ListViewItem>> itemListViewItemMapping;
39    protected TypeSelectorDialog typeSelectorDialog;
40    protected bool validDragOperation;
41
42    public new IItemArray<T> Content {
43      get { return (IItemArray<T>)base.Content; }
44      set { base.Content = value; }
45    }
46
47    public ListView ItemsListView {
48      get { return itemsListView; }
49    }
50
51    public ItemArrayView() {
52      InitializeComponent();
53      itemListViewItemMapping = new Dictionary<T, List<ListViewItem>>();
54    }
55
56    protected override void Dispose(bool disposing) {
57      if (disposing) {
58        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
59        if (components != null) components.Dispose();
60      }
61      base.Dispose(disposing);
62    }
63
64    protected override void DeregisterContentEvents() {
65      Content.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsReplaced);
66      Content.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsMoved);
67      Content.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_CollectionReset);
68      foreach (T item in itemListViewItemMapping.Keys) {
69        DeregisterItemEvents(item);
70      }
71      base.DeregisterContentEvents();
72    }
73    protected override void RegisterContentEvents() {
74      base.RegisterContentEvents();
75      Content.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsReplaced);
76      Content.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsMoved);
77      Content.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_CollectionReset);
78    }
79    protected virtual void DeregisterItemEvents(T item) {
80      item.ItemImageChanged -= new EventHandler(Item_ItemImageChanged);
81      item.ToStringChanged -= new EventHandler(Item_ToStringChanged);
82    }
83    protected virtual void RegisterItemEvents(T item) {
84      item.ItemImageChanged += new EventHandler(Item_ItemImageChanged);
85      item.ToStringChanged += new EventHandler(Item_ToStringChanged);
86    }
87
88    protected override void OnContentChanged() {
89      base.OnContentChanged();
90
91      int selectedIndex = -1;
92      if (itemsListView.SelectedItems.Count == 1) selectedIndex = itemsListView.SelectedIndices[0];
93
94      itemsListView.Items.Clear();
95      itemListViewItemMapping.Clear();
96      RebuildImageList();
97      viewHost.Content = null;
98      if (Content != null) {
99        Caption += " (" + Content.GetType().Name + ")";
100        foreach (T item in Content)
101          AddListViewItem(CreateListViewItem(item));
102        AdjustListViewColumnSizes();
103        if ((selectedIndex != -1) && (selectedIndex < itemsListView.Items.Count))
104          itemsListView.Items[selectedIndex].Selected = true;
105      }
106    }
107
108    protected override void SetEnabledStateOfControls() {
109      base.SetEnabledStateOfControls();
110      if (Content == null) {
111        addButton.Enabled = false;
112        moveUpButton.Enabled = false;
113        moveDownButton.Enabled = false;
114        removeButton.Enabled = false;
115        itemsListView.Enabled = false;
116        detailsGroupBox.Enabled = false;
117      } else {
118        addButton.Enabled = itemsListView.SelectedItems.Count > 0 &&
119                            !Content.IsReadOnly && !ReadOnly;
120        moveUpButton.Enabled = itemsListView.SelectedItems.Count == 1 &&
121                               itemsListView.SelectedIndices[0] != 0 &&
122                               !Content.IsReadOnly && !ReadOnly;
123        moveDownButton.Enabled = itemsListView.SelectedItems.Count == 1 &&
124                                 itemsListView.SelectedIndices[0] != itemsListView.Items.Count - 1 &&
125                                 !Content.IsReadOnly && !ReadOnly;
126        removeButton.Enabled = itemsListView.SelectedItems.Count > 0 &&
127                               !Content.IsReadOnly && !ReadOnly;
128        itemsListView.Enabled = true;
129        detailsGroupBox.Enabled = itemsListView.SelectedItems.Count == 1;
130      }
131    }
132
133    protected virtual T CreateItem() {
134      if (typeSelectorDialog == null) {
135        typeSelectorDialog = new TypeSelectorDialog();
136        typeSelectorDialog.Caption = "Select Item";
137        typeSelectorDialog.TypeSelector.Caption = "Available Items";
138        typeSelectorDialog.TypeSelector.Configure(typeof(T), false, true);
139      }
140
141      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
142        try {
143          return (T)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
144        } catch (Exception ex) {
145          ErrorHandling.ShowErrorDialog(this, ex);
146        }
147      }
148      return null;
149    }
150    protected virtual ListViewItem CreateListViewItem(T item) {
151      ListViewItem listViewItem = new ListViewItem();
152      if (item == null) {
153        listViewItem.Text = "null";
154        itemsListView.SmallImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Nothing);
155        listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
156      } else {
157        listViewItem.Text = item.ToString();
158        listViewItem.ToolTipText = item.ItemName + ": " + item.ItemDescription;
159        itemsListView.SmallImageList.Images.Add(item.ItemImage);
160        listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
161        listViewItem.Tag = item;
162      }
163      return listViewItem;
164    }
165    protected virtual void AddListViewItem(ListViewItem listViewItem) {
166      if (listViewItem == null) throw new ArgumentNullException();
167      T item = (listViewItem.Tag as T);
168      itemsListView.Items.Add(listViewItem);
169      if (item != null) {
170        if (!itemListViewItemMapping.ContainsKey(item)) {
171          RegisterItemEvents(item);
172          itemListViewItemMapping.Add(item, new List<ListViewItem>());
173        }
174        itemListViewItemMapping[item].Add(listViewItem);
175      }
176    }
177    protected virtual void InsertListViewItem(int index, ListViewItem listViewItem) {
178      if (listViewItem == null) throw new ArgumentNullException();
179      T item = (listViewItem.Tag as T);
180      itemsListView.Items.Insert(index, listViewItem);
181      if (item != null) {
182        if (!itemListViewItemMapping.ContainsKey(item)) {
183          RegisterItemEvents(item);
184          itemListViewItemMapping.Add(item, new List<ListViewItem>());
185        }
186        itemListViewItemMapping[item].Add(listViewItem);
187      }
188    }
189    protected virtual void RemoveListViewItem(ListViewItem listViewItem) {
190      if (listViewItem == null) throw new ArgumentNullException();
191      T item = (listViewItem.Tag as T);
192      if (item != null) {
193        itemListViewItemMapping[item].Remove(listViewItem);
194        if (itemListViewItemMapping[item].Count == 0) {
195          itemListViewItemMapping.Remove(item);
196          DeregisterItemEvents(item);
197        }
198      }
199      listViewItem.Remove();
200    }
201    protected virtual void UpdateListViewItemImage(ListViewItem listViewItem) {
202      if (listViewItem == null) throw new ArgumentNullException();
203      T item = listViewItem.Tag as T;
204      int i = listViewItem.ImageIndex;
205      itemsListView.SmallImageList.Images[i] = item == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : item.ItemImage;
206      listViewItem.ImageIndex = -1;
207      listViewItem.ImageIndex = i;
208    }
209    protected virtual void UpdateListViewItemText(ListViewItem listViewItem) {
210      if (listViewItem == null) throw new ArgumentNullException();
211      T item = listViewItem.Tag as T;
212      listViewItem.Text = item == null ? "null" : item.ToString();
213      listViewItem.ToolTipText = item == null ? string.Empty : item.ItemName + ": " + item.ItemDescription;
214    }
215    protected virtual IEnumerable<ListViewItem> GetListViewItemsForItem(T item) {
216      if (item == null) {
217        List<ListViewItem> listViewItems = new List<ListViewItem>();
218        foreach (ListViewItem listViewItem in itemsListView.Items) {
219          if (listViewItem.Tag == null) listViewItems.Add(listViewItem);
220        }
221        return listViewItems;
222      } else {
223        List<ListViewItem> listViewItems = null;
224        itemListViewItemMapping.TryGetValue(item, out listViewItems);
225        return listViewItems == null ? Enumerable.Empty<ListViewItem>() : listViewItems;
226      }
227    }
228
229    #region ListView Events
230    protected virtual void itemsListView_SelectedIndexChanged(object sender, EventArgs e) {
231      addButton.Enabled = itemsListView.SelectedItems.Count > 0 && (Content != null) && !Content.IsReadOnly && !ReadOnly;
232      moveUpButton.Enabled = itemsListView.SelectedItems.Count == 1 &&
233                             itemsListView.SelectedIndices[0] != 0 &&
234                             (Content != null) && !Content.IsReadOnly && !ReadOnly;
235      moveDownButton.Enabled = itemsListView.SelectedItems.Count == 1 &&
236                               itemsListView.SelectedIndices[0] != itemsListView.Items.Count - 1 &&
237                               (Content != null) && !Content.IsReadOnly && !ReadOnly;
238      removeButton.Enabled = itemsListView.SelectedItems.Count > 0 && (Content != null) && !Content.IsReadOnly && !ReadOnly;
239
240      if (showDetailsCheckBox.Checked) {
241        if (itemsListView.SelectedItems.Count == 1) {
242          T item = itemsListView.SelectedItems[0].Tag as T;
243          detailsGroupBox.Enabled = true;
244          viewHost.Content = item;
245        } else {
246          viewHost.Content = null;
247          detailsGroupBox.Enabled = false;
248        }
249      }
250    }
251
252    protected virtual void itemsListView_KeyDown(object sender, KeyEventArgs e) {
253      if (e.KeyCode == Keys.Delete) {
254        if ((itemsListView.SelectedItems.Count > 0) && !Content.IsReadOnly && !ReadOnly) {
255          foreach (ListViewItem item in itemsListView.SelectedItems)
256            Content[item.Index] = null;
257        }
258      } else if (e.KeyData == (Keys.Control | Keys.C)) {
259        if (itemsListView.SelectedItems.Count > 0) {
260          var builder = new StringBuilder();
261          foreach (ListViewItem selected in itemsListView.SelectedItems) {
262            builder.AppendLine(selected.Text);
263          }
264          Clipboard.SetText(builder.ToString());
265        }
266      }
267    }
268
269    protected virtual void itemsListView_DoubleClick(object sender, EventArgs e) {
270      if (itemsListView.SelectedItems.Count == 1) {
271        T item = itemsListView.SelectedItems[0].Tag as T;
272        if (item != null) {
273          IContentView view = MainFormManager.MainForm.ShowContent(item);
274          if (view != null) {
275            view.ReadOnly = ReadOnly;
276            view.Locked = Locked;
277          }
278        }
279      }
280    }
281
282    protected virtual void itemsListView_ItemDrag(object sender, ItemDragEventArgs e) {
283      if (!Locked) {
284        List<T> items = new List<T>();
285        foreach (ListViewItem listViewItem in itemsListView.SelectedItems) {
286          T item = listViewItem.Tag as T;
287          if (item != null) items.Add(item);
288        }
289
290        if (items.Count > 0) {
291          DataObject data = new DataObject();
292          if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
293          else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
294          if (Content.IsReadOnly || ReadOnly) {
295            DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
296          } else {
297            DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
298            if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
299              foreach (ListViewItem listViewItem in itemsListView.SelectedItems.Cast<ListViewItem>().ToArray())
300                Content[listViewItem.Index] = null;
301            }
302          }
303        }
304      }
305    }
306    protected virtual void itemsListView_DragEnter(object sender, DragEventArgs e) {
307      validDragOperation = !Content.IsReadOnly && !ReadOnly && e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T;
308    }
309    protected virtual void itemsListView_DragOver(object sender, DragEventArgs e) {
310      e.Effect = DragDropEffects.None;
311      if (validDragOperation) {
312        Point p = itemsListView.PointToClient(new Point(e.X, e.Y));
313        ListViewItem listViewItem = itemsListView.GetItemAt(p.X, p.Y);
314        if (listViewItem != null) {
315          if ((e.KeyState & 32) == 32) e.Effect = DragDropEffects.Link;  // ALT key
316          else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
317          else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
318          else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
319          else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
320        }
321      }
322    }
323    protected virtual void itemsListView_DragDrop(object sender, DragEventArgs e) {
324      if (e.Effect != DragDropEffects.None) {
325        Point p = itemsListView.PointToClient(new Point(e.X, e.Y));
326        ListViewItem listViewItem = itemsListView.GetItemAt(p.X, p.Y);
327        T item = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as T;
328        Content[listViewItem.Index] = e.Effect.HasFlag(DragDropEffects.Copy) ? (T)item.Clone() : item;
329      }
330    }
331    protected virtual void itemsListView_Layout(object sender, LayoutEventArgs e) {
332      if (itemsListView.Columns.Count == 1)
333        AdjustListViewColumnSizes();
334    }
335    #endregion
336
337    #region Button Events
338    protected virtual void addButton_Click(object sender, EventArgs e) {
339      if (itemsListView.SelectedItems.Count > 0) {
340        T item = CreateItem();
341        if (item != null) {
342          foreach (ListViewItem listViewItem in itemsListView.SelectedItems)
343            Content[listViewItem.Index] = item;
344        }
345      }
346    }
347    protected virtual void moveUpButton_Click(object sender, EventArgs e) {
348      if (itemsListView.SelectedItems.Count == 1) {
349        int index = itemsListView.SelectedIndices[0];
350        Content.Reverse(index - 1, 2);
351        itemsListView.Items[index].Selected = false;
352        itemsListView.Items[index - 1].Selected = true;
353      }
354    }
355    protected virtual void moveDownButton_Click(object sender, EventArgs e) {
356      if (itemsListView.SelectedItems.Count == 1) {
357        int index = itemsListView.SelectedIndices[0];
358        Content.Reverse(index, 2);
359        itemsListView.Items[index].Selected = false;
360        itemsListView.Items[index + 1].Selected = true;
361      }
362    }
363    protected virtual void removeButton_Click(object sender, EventArgs e) {
364      if (itemsListView.SelectedItems.Count > 0) {
365        foreach (ListViewItem item in itemsListView.SelectedItems)
366          Content[item.Index] = null;
367      }
368    }
369    #endregion
370
371    #region CheckBox Events
372    protected virtual void showDetailsCheckBox_CheckedChanged(object sender, EventArgs e) {
373      if (showDetailsCheckBox.Checked) {
374        splitContainer.Panel2Collapsed = false;
375        detailsGroupBox.Enabled = itemsListView.SelectedItems.Count == 1;
376        viewHost.Content = itemsListView.SelectedItems.Count == 1 ? (T)itemsListView.SelectedItems[0].Tag : null;
377      } else {
378        splitContainer.Panel2Collapsed = true;
379        viewHost.Content = null;
380      }
381    }
382    #endregion
383
384    #region Content Events
385    protected virtual void Content_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
386      if (InvokeRequired)
387        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsReplaced), sender, e);
388      else {
389        int[] selected = new int[itemsListView.SelectedIndices.Count];
390        itemsListView.SelectedIndices.CopyTo(selected, 0);
391
392        List<ListViewItem> listViewItems = new List<ListViewItem>();
393        foreach (IndexedItem<T> item in e.OldItems)
394          listViewItems.Add(itemsListView.Items[item.Index]);
395        foreach (ListViewItem listViewItem in listViewItems)
396          RemoveListViewItem(listViewItem);
397        RebuildImageList();
398
399        foreach (IndexedItem<T> item in e.Items)
400          InsertListViewItem(item.Index, CreateListViewItem(item.Value));
401        AdjustListViewColumnSizes();
402
403        for (int i = 0; i < selected.Length; i++)
404          itemsListView.Items[selected[i]].Selected = true;
405      }
406    }
407    protected virtual void Content_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
408      if (InvokeRequired)
409        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_ItemsMoved), sender, e);
410      else {
411        foreach (IndexedItem<T> item in e.Items) {
412          ListViewItem listViewItem = itemsListView.Items[item.Index];
413          if (listViewItem.Tag != null)
414            itemListViewItemMapping[(T)listViewItem.Tag].Remove(listViewItem);
415          listViewItem.Tag = item.Value;
416          if (listViewItem.Tag != null)
417            itemListViewItemMapping[item.Value].Add(listViewItem);
418          UpdateListViewItemImage(listViewItem);
419          UpdateListViewItemText(listViewItem);
420        }
421      }
422    }
423    protected virtual void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
424      if (InvokeRequired)
425        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<T>>(Content_CollectionReset), sender, e);
426      else {
427        List<ListViewItem> listViewItems = new List<ListViewItem>();
428        foreach (IndexedItem<T> item in e.OldItems)
429          listViewItems.Add(itemsListView.Items[item.Index]);
430        foreach (ListViewItem listViewItem in listViewItems)
431          RemoveListViewItem(listViewItem);
432        RebuildImageList();
433
434        foreach (IndexedItem<T> item in e.Items)
435          InsertListViewItem(item.Index, CreateListViewItem(item.Value));
436        AdjustListViewColumnSizes();
437      }
438    }
439    #endregion
440
441    #region Item Events
442    protected virtual void Item_ItemImageChanged(object sender, EventArgs e) {
443      if (InvokeRequired)
444        Invoke(new EventHandler(Item_ItemImageChanged), sender, e);
445      else {
446        T item = (T)sender;
447        foreach (ListViewItem listViewItem in GetListViewItemsForItem(item))
448          UpdateListViewItemImage(listViewItem);
449      }
450    }
451    protected virtual void Item_ToStringChanged(object sender, EventArgs e) {
452      if (InvokeRequired)
453        Invoke(new EventHandler(Item_ToStringChanged), sender, e);
454      else {
455        T item = (T)sender;
456        foreach (ListViewItem listViewItem in GetListViewItemsForItem(item))
457          UpdateListViewItemText(listViewItem);
458        if (itemsListView.Columns.Count > 1)
459          AdjustListViewColumnSizes();
460      }
461    }
462    #endregion
463
464    #region Helpers
465    protected virtual void AdjustListViewColumnSizes() {
466      if (itemsListView.Columns.Count == 1) {
467        if (itemsListView.Columns[0].Width != itemsListView.ClientSize.Width)
468          itemsListView.Columns[0].Width = itemsListView.ClientSize.Width;
469      } else {
470        if (itemsListView.Items.Count > 0) {
471          for (int i = 0; i < itemsListView.Columns.Count; i++)
472            itemsListView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
473        }
474      }
475    }
476    protected virtual void RebuildImageList() {
477      itemsListView.SmallImageList.Images.Clear();
478      foreach (ListViewItem listViewItem in itemsListView.Items) {
479        T item = listViewItem.Tag as T;
480        itemsListView.SmallImageList.Images.Add(item == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : item.ItemImage);
481        listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
482      }
483    }
484    #endregion
485  }
486}
Note: See TracBrowser for help on using the repository browser.