Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Core.Views/3.3/Clipboard.cs @ 16997

Last change on this file since 16997 was 16997, checked in by gkronber, 5 years ago

#2520 Update plugin dependencies and references for Core.Views and Optimizer for new persistence

File size: 16.9 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;
24using System.Collections.Generic;
25using System.IO;
26using System.Linq;
27using System.Threading;
28using System.Windows.Forms;
29using HEAL.Attic;
30using HeuristicLab.Common;
31using HeuristicLab.MainForm;
32using HeuristicLab.PluginInfrastructure;
33
34namespace HeuristicLab.Core.Views {
35  [View("Clipboard")]
36  public sealed partial class Clipboard<T> : HeuristicLab.MainForm.WindowsForms.Sidebar where T : class, IItem {
37    private TypeSelectorDialog typeSelectorDialog;
38    private Dictionary<T, ListViewItem> itemListViewItemMapping;
39    private bool validDragOperation;
40    private bool draggedItemsAlreadyContained;
41
42    private string itemsPath;
43    public string ItemsPath {
44      get { return itemsPath; }
45      private set {
46        if (string.IsNullOrEmpty(value)) throw new ArgumentException(string.Format("Invalid items path \"{0}\".", value));
47        itemsPath = value;
48        try {
49          if (!Directory.Exists(itemsPath)) {
50            Directory.CreateDirectory(itemsPath);
51            // directory creation might take some time -> wait until it is definitively created
52            while (!Directory.Exists(itemsPath)) {
53              Thread.Sleep(100);
54              Directory.CreateDirectory(itemsPath);
55            }
56          }
57        }
58        catch (Exception ex) {
59          throw new ArgumentException(string.Format("Invalid items path \"{0}\".", itemsPath), ex);
60        }
61      }
62    }
63
64    public Clipboard() {
65      InitializeComponent();
66      ItemsPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
67                  Path.DirectorySeparatorChar + "HeuristicLab" + Path.DirectorySeparatorChar + "Clipboard";
68      itemListViewItemMapping = new Dictionary<T, ListViewItem>();
69    }
70    public Clipboard(string itemsPath) {
71      InitializeComponent();
72      ItemsPath = itemsPath;
73      itemListViewItemMapping = new Dictionary<T, ListViewItem>();
74    }
75
76    protected override void Dispose(bool disposing) {
77      if (disposing) {
78        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
79        foreach (T item in itemListViewItemMapping.Keys) {
80          item.ItemImageChanged -= new EventHandler(Item_ItemImageChanged);
81          item.ToStringChanged -= new EventHandler(Item_ToStringChanged);
82        }
83        if (components != null) components.Dispose();
84      }
85      base.Dispose(disposing);
86    }
87
88    protected override void OnInitialized(EventArgs e) {
89      base.OnInitialized(e);
90      SetEnabledStateOfControls();
91      Enabled = false;
92      infoLabel.Text = "Loading ...";
93      progressBar.Value = 0;
94      infoPanel.Visible = true;
95      ThreadPool.QueueUserWorkItem(new WaitCallback(LoadItems));
96    }
97
98    protected override void SetEnabledStateOfControls() {
99      base.SetEnabledStateOfControls();
100      addButton.Enabled = !ReadOnly;
101      removeButton.Enabled = !ReadOnly && listView.SelectedItems.Count > 0;
102      saveButton.Enabled = !ReadOnly;
103    }
104
105    public void AddItem(T item) {
106      if (InvokeRequired)
107        Invoke(new Action<T>(AddItem), item);
108      else {
109        if (item == null) throw new ArgumentNullException("item", "Cannot add null item to clipboard.");
110        if (!itemListViewItemMapping.ContainsKey(item)) {
111          ListViewItem listViewItem = new ListViewItem(item.ToString());
112          listViewItem.ToolTipText = item.ItemName + ": " + item.ItemDescription;
113          listView.SmallImageList.Images.Add(item.ItemImage);
114          listViewItem.ImageIndex = listView.SmallImageList.Images.Count - 1;
115          listViewItem.Tag = item;
116          listView.Items.Add(listViewItem);
117          itemListViewItemMapping.Add(item, listViewItem);
118          item.ItemImageChanged += new EventHandler(Item_ItemImageChanged);
119          item.ToStringChanged += new EventHandler(Item_ToStringChanged);
120          sortAscendingButton.Enabled = sortDescendingButton.Enabled = listView.Items.Count > 1;
121          AdjustListViewColumnSizes();
122        }
123      }
124    }
125
126    private void RemoveItem(T item) {
127      if (InvokeRequired)
128        Invoke(new Action<T>(RemoveItem), item);
129      else {
130        if (itemListViewItemMapping.ContainsKey(item)) {
131          item.ItemImageChanged -= new EventHandler(Item_ItemImageChanged);
132          item.ToStringChanged -= new EventHandler(Item_ToStringChanged);
133          ListViewItem listViewItem = itemListViewItemMapping[item];
134          listViewItem.Remove();
135          itemListViewItemMapping.Remove(item);
136          sortAscendingButton.Enabled = sortDescendingButton.Enabled = listView.Items.Count > 1;
137        }
138      }
139    }
140    private void Save() {
141      if (InvokeRequired)
142        Invoke(new Action(Save));
143      else {
144        Enabled = false;
145        infoLabel.Text = "Saving ...";
146        progressBar.Value = 0;
147        infoPanel.Visible = true;
148        ThreadPool.QueueUserWorkItem(new WaitCallback(SaveItems));
149      }
150    }
151
152    #region Loading/Saving Items
153    private void LoadItems(object state) {
154      string[] items = Directory.GetFiles(ItemsPath);
155      foreach (string filename in items) {
156        try {
157          T item = (T)ContentManager.Load(filename);
158          OnItemLoaded(item, progressBar.Maximum / items.Length);
159        } catch(Exception) {
160          // ignore if loading a clipboad item fails.
161        }
162      }
163      OnAllItemsLoaded();
164    }
165    private void OnItemLoaded(T item, int progress) {
166      if (InvokeRequired)
167        Invoke(new Action<T, int>(OnItemLoaded), item, progress);
168      else {
169        AddItem(item);
170        progressBar.Value += progress;
171      }
172    }
173    private void OnAllItemsLoaded() {
174      if (InvokeRequired)
175        Invoke(new Action(OnAllItemsLoaded));
176      else {
177        Enabled = true;
178        if (listView.Items.Count > 0) {
179          for (int i = 0; i < listView.Columns.Count; i++)
180            listView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
181        }
182        infoPanel.Visible = false;
183      }
184    }
185    private void SaveItems(object param) {
186      Directory.Delete(ItemsPath, true);
187      Directory.CreateDirectory(ItemsPath);
188      // directory creation might take some time -> wait until it is definitively created
189      while (!Directory.Exists(ItemsPath)) {
190        Thread.Sleep(100);
191        Directory.CreateDirectory(ItemsPath);
192      }
193
194      int i = 0;
195      T[] items = GetStorableItems(itemListViewItemMapping.Keys);
196
197      foreach (T item in items) {
198        try {
199          i++;
200          SetEnabledStateOfContentViews(item, false);
201          var ser = new ProtoBufSerializer();
202          ser.Serialize(item, ItemsPath + Path.DirectorySeparatorChar + i.ToString("00000000") + ".hl");
203          OnItemSaved(item, progressBar.Maximum / listView.Items.Count);
204        }
205        catch (Exception) { }
206        finally {
207          SetEnabledStateOfContentViews(item, true);
208        }
209      }
210      OnAllItemsSaved();
211    }
212
213    private void OnItemSaved(T item, int progress) {
214      if (item != null) {
215        if (InvokeRequired)
216          Invoke(new Action<T, int>(OnItemSaved), item, progress);
217        else {
218          progressBar.Value += progress;
219        }
220      }
221    }
222    private void OnAllItemsSaved() {
223      if (InvokeRequired)
224        Invoke(new Action(OnAllItemsLoaded));
225      else {
226        Enabled = true;
227        infoPanel.Visible = false;
228      }
229    }
230
231    private void SetEnabledStateOfContentViews(IItem item, bool enabled) {
232      if (InvokeRequired)
233        Invoke((Action<IItem, bool>)SetEnabledStateOfContentViews, item, enabled);
234      else {
235        var views = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v.Content == item).ToList();
236        views.ForEach(v => v.Enabled = enabled);
237      }
238    }
239
240    private static T[] GetStorableItems(IEnumerable<T> items) {
241      var query = from item in items
242                  let executeable = item as IExecutable
243                  let views = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v.Content == item)
244                  where executeable == null || executeable.ExecutionState != ExecutionState.Started
245                  where !views.Any(v => v.Locked)
246                  select item;
247      T[] itemArray = query.ToArray();
248      return itemArray;
249    }
250    #endregion
251
252    #region ListView Events
253    private void listView_SelectedIndexChanged(object sender, EventArgs e) {
254      removeButton.Enabled = !ReadOnly && listView.SelectedItems.Count > 0;
255    }
256    private void listView_KeyDown(object sender, KeyEventArgs e) {
257      if (e.KeyCode == Keys.Delete) {
258        if (!ReadOnly && (listView.SelectedItems.Count > 0)) {
259          foreach (ListViewItem item in listView.SelectedItems)
260            RemoveItem((T)item.Tag);
261          RebuildImageList();
262        }
263      }
264    }
265    private void listView_DoubleClick(object sender, EventArgs e) {
266      if (listView.SelectedItems.Count == 1) {
267        T item = (T)listView.SelectedItems[0].Tag;
268        IContentView view = MainFormManager.MainForm.ShowContent(item, true);
269      }
270    }
271    private void listView_ItemDrag(object sender, ItemDragEventArgs e) {
272      List<T> items = new List<T>();
273      foreach (ListViewItem listViewItem in listView.SelectedItems) {
274        T item = listViewItem.Tag as T;
275        if (item != null) items.Add(item);
276      }
277
278      if (items.Count > 0) {
279        DataObject data = new DataObject();
280        if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
281        else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
282        if (ReadOnly) {
283          DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
284        } else {
285          DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
286          if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
287            foreach (T item in items) RemoveItem(item);
288            RebuildImageList();
289          }
290        }
291      }
292    }
293    private void listView_DragEnter(object sender, DragEventArgs e) {
294      validDragOperation = false;
295      draggedItemsAlreadyContained = false;
296      if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T)) {
297        validDragOperation = true;
298        draggedItemsAlreadyContained = itemListViewItemMapping.ContainsKey((T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat));
299      } else if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable)) {
300        validDragOperation = true;
301        IEnumerable items = (IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
302        foreach (object item in items) {
303          validDragOperation = validDragOperation && (item is T);
304          draggedItemsAlreadyContained = draggedItemsAlreadyContained || itemListViewItemMapping.ContainsKey((T)item);
305        }
306      }
307    }
308    private void listView_DragOver(object sender, DragEventArgs e) {
309      e.Effect = DragDropEffects.None;
310      if (validDragOperation) {
311        if (((e.KeyState & 32) == 32) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Link;  // ALT key
312        else if (((e.KeyState & 4) == 4) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Move;  // SHIFT key
313        else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
314        else if (e.AllowedEffect.HasFlag(DragDropEffects.Move) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Move;
315        else if (e.AllowedEffect.HasFlag(DragDropEffects.Link) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Link;
316      }
317    }
318    private void listView_DragDrop(object sender, DragEventArgs e) {
319      if (e.Effect != DragDropEffects.None) {
320        try {
321          if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T) {
322            T item = (T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
323            AddItem(e.Effect.HasFlag(DragDropEffects.Copy) ? (T)item.Clone() : item);
324          } else if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable) {
325            IEnumerable<T> items = ((IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat)).Cast<T>();
326            if (e.Effect.HasFlag(DragDropEffects.Copy)) {
327              Cloner cloner = new Cloner();
328              items = items.Select(x => cloner.Clone(x));
329            }
330            foreach (T item in items)
331              AddItem(item);
332          }
333        }
334        catch (Exception ex) {
335          ErrorHandling.ShowErrorDialog(this, ex);
336        }
337      }
338    }
339    #endregion
340
341    #region Button Events
342    private void addButton_Click(object sender, EventArgs e) {
343      if (typeSelectorDialog == null) {
344        typeSelectorDialog = new TypeSelectorDialog();
345        typeSelectorDialog.Caption = "Select Item";
346        typeSelectorDialog.TypeSelector.Caption = "Available Items";
347        typeSelectorDialog.TypeSelector.Configure(typeof(T), false, true);
348      }
349
350      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
351        try {
352          AddItem((T)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType());
353        }
354        catch (Exception ex) {
355          ErrorHandling.ShowErrorDialog(this, ex);
356        }
357      }
358    }
359    private void sortAscendingButton_Click(object sender, EventArgs e) {
360      listView.Sorting = SortOrder.None;
361      listView.Sorting = SortOrder.Ascending;
362    }
363    private void sortDescendingButton_Click(object sender, EventArgs e) {
364      listView.Sorting = SortOrder.None;
365      listView.Sorting = SortOrder.Descending;
366    }
367    private void removeButton_Click(object sender, EventArgs e) {
368      if (listView.SelectedItems.Count > 0) {
369        foreach (ListViewItem item in listView.SelectedItems)
370          RemoveItem((T)item.Tag);
371        RebuildImageList();
372      }
373    }
374    private void saveButton_Click(object sender, EventArgs e) {
375      IEnumerable<T> items = itemListViewItemMapping.Keys.Except(GetStorableItems(itemListViewItemMapping.Keys));
376      if (items.Any()) {
377        string itemNames = string.Join(Environment.NewLine, items.Select(item => item.ToString()).ToArray());
378        MessageBox.Show("The following items are not saved, because they are locked (e.g. used in a running algorithm):" + Environment.NewLine + Environment.NewLine +
379          itemNames + Environment.NewLine + Environment.NewLine + "All other items will be saved.", "Cannot save all items", MessageBoxButtons.OK, MessageBoxIcon.Warning);
380      }
381      Save();
382    }
383    #endregion
384
385    #region Item Events
386    private void Item_ItemImageChanged(object sender, EventArgs e) {
387      if (InvokeRequired)
388        Invoke(new EventHandler(Item_ItemImageChanged), sender, e);
389      else {
390        T item = (T)sender;
391        ListViewItem listViewItem = itemListViewItemMapping[item];
392        int i = listViewItem.ImageIndex;
393        listView.SmallImageList.Images[i] = item.ItemImage;
394        listViewItem.ImageIndex = -1;
395        listViewItem.ImageIndex = i;
396      }
397    }
398    private void Item_ToStringChanged(object sender, EventArgs e) {
399      if (InvokeRequired)
400        Invoke(new EventHandler(Item_ToStringChanged), sender, e);
401      else {
402        T item = (T)sender;
403        itemListViewItemMapping[item].Text = item.ToString();
404        listView.Sort();
405        AdjustListViewColumnSizes();
406      }
407    }
408    #endregion
409
410    #region Helpers
411    private void AdjustListViewColumnSizes() {
412      if (listView.Items.Count > 0) {
413        for (int i = 0; i < listView.Columns.Count; i++)
414          listView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
415      }
416    }
417    private void RebuildImageList() {
418      listView.SmallImageList.Images.Clear();
419      foreach (ListViewItem item in listView.Items) {
420        listView.SmallImageList.Images.Add(((T)item.Tag).ItemImage);
421        item.ImageIndex = listView.SmallImageList.Images.Count - 1;
422      }
423    }
424    #endregion
425  }
426}
Note: See TracBrowser for help on using the repository browser.