#1587: Updated `ViewHost` after node selection with arrow keys and handled item move...
[hl.git] / sources / HeuristicLab.Core.Views / 3.3 / ItemCollectionView.cs
bloba8fc2a86d3ccad120d58d475f0686b6e01a64109
1 #region License Information
2 /* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
5 * This file is part of HeuristicLab.
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.
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.
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/>.
20 #endregion
22 using System;
23 using System.Collections;
24 using System.Collections.Generic;
25 using System.Linq;
26 using System.Windows.Forms;
27 using HeuristicLab.Collections;
28 using HeuristicLab.Common;
29 using HeuristicLab.MainForm;
30 using HeuristicLab.MainForm.WindowsForms;
31 using HeuristicLab.PluginInfrastructure;
33 namespace HeuristicLab.Core.Views {
34 [View("ItemCollection View")]
35 [Content(typeof(ItemCollection<>), true)]
36 [Content(typeof(IItemCollection<>), false)]
37 public partial class ItemCollectionView<T> : ItemView where T : class, IItem {
38 protected Dictionary<T, List<ListViewItem>> itemListViewItemMapping;
39 protected TypeSelectorDialog typeSelectorDialog;
40 protected bool validDragOperation;
42 public new IItemCollection<T> Content {
43 get { return (IItemCollection<T>)base.Content; }
44 set { base.Content = value; }
47 public ListView ItemsListView {
48 get { return itemsListView; }
51 public ItemCollectionView() {
52 InitializeComponent();
53 itemListViewItemMapping = new Dictionary<T, List<ListViewItem>>();
56 protected override void Dispose(bool disposing) {
57 if (disposing) {
58 if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
59 if (components != null) components.Dispose();
61 base.Dispose(disposing);
64 protected override void DeregisterContentEvents() {
65 Content.ItemsAdded -= new CollectionItemsChangedEventHandler<T>(Content_ItemsAdded);
66 Content.ItemsRemoved -= new CollectionItemsChangedEventHandler<T>(Content_ItemsRemoved);
67 Content.CollectionReset -= new CollectionItemsChangedEventHandler<T>(Content_CollectionReset);
68 foreach (T item in itemListViewItemMapping.Keys) {
69 DeregisterItemEvents(item);
71 base.DeregisterContentEvents();
73 protected override void RegisterContentEvents() {
74 base.RegisterContentEvents();
75 Content.ItemsAdded += new CollectionItemsChangedEventHandler<T>(Content_ItemsAdded);
76 Content.ItemsRemoved += new CollectionItemsChangedEventHandler<T>(Content_ItemsRemoved);
77 Content.CollectionReset += new CollectionItemsChangedEventHandler<T>(Content_CollectionReset);
79 protected virtual void DeregisterItemEvents(T item) {
80 item.ItemImageChanged -= new EventHandler(Item_ItemImageChanged);
81 item.ToStringChanged -= new EventHandler(Item_ToStringChanged);
83 protected virtual void RegisterItemEvents(T item) {
84 item.ItemImageChanged += new EventHandler(Item_ItemImageChanged);
85 item.ToStringChanged += new EventHandler(Item_ToStringChanged);
88 protected override void OnContentChanged() {
89 base.OnContentChanged();
90 itemsListView.Items.Clear();
91 itemListViewItemMapping.Clear();
92 RebuildImageList();
93 viewHost.Content = null;
94 if (Content != null) {
95 Caption += " (" + Content.GetType().Name + ")";
96 foreach (T item in Content)
97 AddListViewItem(CreateListViewItem(item));
98 AdjustListViewColumnSizes();
99 SortItemsListView(SortOrder.Ascending);
103 protected override void SetEnabledStateOfControls() {
104 base.SetEnabledStateOfControls();
105 if (Content == null) {
106 addButton.Enabled = false;
107 sortAscendingButton.Enabled = false;
108 sortDescendingButton.Enabled = false;
109 removeButton.Enabled = false;
110 itemsListView.Enabled = false;
111 detailsGroupBox.Enabled = false;
112 } else {
113 addButton.Enabled = !Content.IsReadOnly && !ReadOnly;
114 sortAscendingButton.Enabled = itemsListView.Items.Count > 1;
115 sortDescendingButton.Enabled = itemsListView.Items.Count > 1;
116 removeButton.Enabled = !Content.IsReadOnly && !ReadOnly && itemsListView.SelectedItems.Count > 0;
117 itemsListView.Enabled = true;
118 detailsGroupBox.Enabled = itemsListView.SelectedItems.Count == 1;
122 protected virtual T CreateItem() {
123 if (typeSelectorDialog == null) {
124 typeSelectorDialog = new TypeSelectorDialog();
125 typeSelectorDialog.Caption = "Select Item";
126 typeSelectorDialog.TypeSelector.Caption = "Available Items";
127 typeSelectorDialog.TypeSelector.Configure(typeof(T), false, true);
130 if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
131 try {
132 return (T)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
134 catch (Exception ex) {
135 ErrorHandling.ShowErrorDialog(this, ex);
138 return null;
140 protected virtual ListViewItem CreateListViewItem(T item) {
141 ListViewItem listViewItem = new ListViewItem();
142 if (item == null) {
143 listViewItem.Text = "null";
144 itemsListView.SmallImageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.Nothing);
145 listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
146 } else {
147 listViewItem.Text = item.ToString();
148 listViewItem.ToolTipText = item.ItemName + ": " + item.ItemDescription;
149 itemsListView.SmallImageList.Images.Add(item.ItemImage);
150 listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
151 listViewItem.Tag = item;
153 return listViewItem;
155 protected virtual void AddListViewItem(ListViewItem listViewItem) {
156 if (listViewItem == null) throw new ArgumentNullException();
157 T item = (listViewItem.Tag as T);
158 itemsListView.Items.Add(listViewItem);
159 if (item != null) {
160 if (!itemListViewItemMapping.ContainsKey(item)) {
161 RegisterItemEvents(item);
162 itemListViewItemMapping.Add(item, new List<ListViewItem>());
164 itemListViewItemMapping[item].Add(listViewItem);
166 sortAscendingButton.Enabled = itemsListView.Items.Count > 1;
167 sortDescendingButton.Enabled = itemsListView.Items.Count > 1;
169 protected virtual void RemoveListViewItem(ListViewItem listViewItem) {
170 if (listViewItem == null) throw new ArgumentNullException();
171 T item = (listViewItem.Tag as T);
172 if (item != null) {
173 itemListViewItemMapping[item].Remove(listViewItem);
174 if (itemListViewItemMapping[item].Count == 0) {
175 itemListViewItemMapping.Remove(item);
176 DeregisterItemEvents(item);
179 listViewItem.Remove();
180 sortAscendingButton.Enabled = itemsListView.Items.Count > 1;
181 sortDescendingButton.Enabled = itemsListView.Items.Count > 1;
183 protected virtual void UpdateListViewItemImage(ListViewItem listViewItem) {
184 if (listViewItem == null) throw new ArgumentNullException();
185 T item = listViewItem.Tag as T;
186 int i = listViewItem.ImageIndex;
187 itemsListView.SmallImageList.Images[i] = item == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : item.ItemImage;
188 listViewItem.ImageIndex = -1;
189 listViewItem.ImageIndex = i;
191 protected virtual void UpdateListViewItemText(ListViewItem listViewItem) {
192 if (listViewItem == null) throw new ArgumentNullException();
193 T item = listViewItem.Tag as T;
194 listViewItem.Text = item == null ? "null" : item.ToString();
195 listViewItem.ToolTipText = item == null ? string.Empty : item.ItemName + ": " + item.ItemDescription;
197 protected virtual IEnumerable<ListViewItem> GetListViewItemsForItem(T item) {
198 if (item == null) {
199 List<ListViewItem> listViewItems = new List<ListViewItem>();
200 foreach (ListViewItem listViewItem in itemsListView.Items) {
201 if (listViewItem.Tag == null) listViewItems.Add(listViewItem);
203 return listViewItems;
204 } else {
205 List<ListViewItem> listViewItems = null;
206 itemListViewItemMapping.TryGetValue(item, out listViewItems);
207 return listViewItems == null ? Enumerable.Empty<ListViewItem>() : listViewItems;
211 #region ListView Events
212 protected virtual void itemsListView_SelectedIndexChanged(object sender, EventArgs e) {
213 removeButton.Enabled = (Content != null) && !Content.IsReadOnly && !ReadOnly && itemsListView.SelectedItems.Count > 0;
214 AdjustListViewColumnSizes();
215 if (showDetailsCheckBox.Checked) {
216 if (itemsListView.SelectedItems.Count == 1) {
217 T item = (T)itemsListView.SelectedItems[0].Tag;
218 detailsGroupBox.Enabled = true;
219 viewHost.Content = item;
220 } else {
221 viewHost.Content = null;
222 detailsGroupBox.Enabled = false;
226 protected virtual void itemsListView_KeyDown(object sender, KeyEventArgs e) {
227 if (e.KeyCode == Keys.Delete) {
228 if ((itemsListView.SelectedItems.Count > 0) && !Content.IsReadOnly && !ReadOnly) {
229 foreach (ListViewItem item in itemsListView.SelectedItems)
230 Content.Remove((T)item.Tag);
234 protected virtual void itemsListView_DoubleClick(object sender, EventArgs e) {
235 if (itemsListView.SelectedItems.Count == 1) {
236 T item = itemsListView.SelectedItems[0].Tag as T;
237 if (item != null) {
238 IContentView view = MainFormManager.MainForm.ShowContent(item);
239 if (view != null) {
240 view.ReadOnly = ReadOnly;
241 view.Locked = Locked;
246 protected virtual void itemsListView_ItemDrag(object sender, ItemDragEventArgs e) {
247 if (!Locked) {
248 List<T> items = new List<T>();
249 foreach (ListViewItem listViewItem in itemsListView.SelectedItems) {
250 T item = listViewItem.Tag as T;
251 if (item != null) items.Add(item);
254 if (items.Count > 0) {
255 DataObject data = new DataObject();
256 if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
257 else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
258 if (Content.IsReadOnly || ReadOnly) {
259 DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
260 } else {
261 DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
262 if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
263 foreach (T item in items) Content.Remove(item);
269 protected virtual void itemsListView_DragEnter(object sender, DragEventArgs e) {
270 validDragOperation = false;
271 if (!Content.IsReadOnly && !ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T)) {
272 validDragOperation = true;
273 } else if (!Content.IsReadOnly && !ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable)) {
274 validDragOperation = true;
275 IEnumerable items = (IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
276 foreach (object item in items)
277 validDragOperation = validDragOperation && (item is T);
280 protected virtual void itemsListView_DragOver(object sender, DragEventArgs e) {
281 e.Effect = DragDropEffects.None;
282 if (validDragOperation) {
283 if ((e.KeyState & 32) == 32) e.Effect = DragDropEffects.Link; // ALT key
284 else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move; // SHIFT key
285 else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
286 else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
287 else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
290 protected virtual void itemsListView_DragDrop(object sender, DragEventArgs e) {
291 if (e.Effect != DragDropEffects.None) {
292 if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T) {
293 T item = (T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
294 Content.Add(e.Effect.HasFlag(DragDropEffects.Copy) ? (T)item.Clone() : item);
295 } else if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable) {
296 IEnumerable<T> items = ((IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat)).Cast<T>();
297 if (e.Effect.HasFlag(DragDropEffects.Copy)) {
298 Cloner cloner = new Cloner();
299 items = items.Select(x => cloner.Clone(x));
301 foreach (T item in items)
302 Content.Add(item);
306 #endregion
308 #region Button Events
309 protected virtual void addButton_Click(object sender, EventArgs e) {
310 T item = CreateItem();
311 if (item != null)
312 Content.Add(item);
314 protected virtual void sortAscendingButton_Click(object sender, EventArgs e) {
315 SortItemsListView(SortOrder.Ascending);
317 protected virtual void sortDescendingButton_Click(object sender, EventArgs e) {
318 SortItemsListView(SortOrder.Descending);
320 protected virtual void removeButton_Click(object sender, EventArgs e) {
321 if (itemsListView.SelectedItems.Count > 0) {
322 foreach (ListViewItem item in itemsListView.SelectedItems)
323 Content.Remove((T)item.Tag);
324 itemsListView.SelectedItems.Clear();
327 #endregion
329 #region CheckBox Events
330 protected virtual void showDetailsCheckBox_CheckedChanged(object sender, EventArgs e) {
331 if (showDetailsCheckBox.Checked) {
332 splitContainer.Panel2Collapsed = false;
333 detailsGroupBox.Enabled = itemsListView.SelectedItems.Count == 1;
334 viewHost.Content = itemsListView.SelectedItems.Count == 1 ? (T)itemsListView.SelectedItems[0].Tag : null;
335 } else {
336 splitContainer.Panel2Collapsed = true;
337 viewHost.Content = null;
340 #endregion
342 #region Content Events
343 protected virtual void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<T> e) {
344 if (InvokeRequired)
345 Invoke(new CollectionItemsChangedEventHandler<T>(Content_ItemsAdded), sender, e);
346 else {
347 foreach (T item in e.Items)
348 AddListViewItem(CreateListViewItem(item));
349 AdjustListViewColumnSizes();
353 protected virtual void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<T> e) {
354 if (InvokeRequired)
355 Invoke(new CollectionItemsChangedEventHandler<T>(Content_ItemsRemoved), sender, e);
356 else {
357 foreach (T item in e.Items) {
358 //remove only the first matching ListViewItem, because the IItem could be contained multiple times in the ItemCollection
359 ListViewItem listviewItem = GetListViewItemsForItem(item).FirstOrDefault();
360 if (listviewItem != null) RemoveListViewItem(listviewItem);
362 RebuildImageList();
365 protected virtual void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<T> e) {
366 if (InvokeRequired)
367 Invoke(new CollectionItemsChangedEventHandler<T>(Content_CollectionReset), sender, e);
368 else {
369 foreach (T item in e.OldItems) {
370 //remove only the first matching ListViewItem, because the IItem could be contained multiple times in the ItemCollection
371 ListViewItem listviewItem = GetListViewItemsForItem(item).FirstOrDefault();
372 if (listviewItem != null) RemoveListViewItem(listviewItem);
374 RebuildImageList();
375 foreach (T item in e.Items)
376 AddListViewItem(CreateListViewItem(item));
379 #endregion
381 #region Item Events
382 protected virtual void Item_ItemImageChanged(object sender, EventArgs e) {
383 if (InvokeRequired)
384 Invoke(new EventHandler(Item_ItemImageChanged), sender, e);
385 else {
386 T item = (T)sender;
387 foreach (ListViewItem listViewItem in GetListViewItemsForItem(item))
388 UpdateListViewItemImage(listViewItem);
391 protected virtual void Item_ToStringChanged(object sender, EventArgs e) {
392 if (InvokeRequired)
393 Invoke(new EventHandler(Item_ToStringChanged), sender, e);
394 else {
395 T item = (T)sender;
396 foreach (ListViewItem listViewItem in GetListViewItemsForItem(item))
397 UpdateListViewItemText(listViewItem);
400 #endregion
402 #region Helpers
403 protected virtual void SortItemsListView(SortOrder sortOrder) {
404 itemsListView.Sorting = SortOrder.None;
405 itemsListView.Sorting = sortOrder;
406 itemsListView.Sorting = SortOrder.None;
408 protected virtual void AdjustListViewColumnSizes() {
409 if (itemsListView.Items.Count > 0) {
410 for (int i = 0; i < itemsListView.Columns.Count; i++)
411 itemsListView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
414 protected virtual void RebuildImageList() {
415 itemsListView.SmallImageList.Images.Clear();
416 foreach (ListViewItem listViewItem in itemsListView.Items) {
417 T item = listViewItem.Tag as T;
418 itemsListView.SmallImageList.Images.Add(item == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : item.ItemImage);
419 listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
422 #endregion