Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Core.Views/3.3/ItemListView.cs @ 5304

Last change on this file since 5304 was 5302, checked in by swagner, 14 years ago

Fixed exception which was thrown when item updates are still pending after the content of an ItemCollectionView has already been changed (#1324)

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