Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Core.Views/3.3/Clipboard.cs @ 17105

Last change on this file since 17105 was 17105, checked in by mkommend, 5 years ago

#2520: Merged 16584, 16585,16594,16595, 16625, 16658, 16659, 16672, 16707, 16729, 16792, 16796, 16797, 16799, 16819, 16906, 16907, 16908, 16933, 16945, 16992, 16994, 16995, 16996, 16997, 17014, 17015, 17017, 17020, 17021, 17022, 17023, 17024, 17029, 17086, 17087, 17088, 17089 into stable.

File size: 17.2 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 = null;
158          if (HeuristicLab.Persistence.Default.Xml.XmlParser.CanOpen(filename)) {
159            item = HeuristicLab.Persistence.Default.Xml.XmlParser.Deserialize<T>(filename);
160          } else {
161            item = (T)new ProtoBufSerializer().Deserialize(filename);
162          }
163          OnItemLoaded(item, progressBar.Maximum / items.Length);
164        } catch (Exception) {
165          // ignore if loading a clipboad item fails.
166        }
167      }
168      OnAllItemsLoaded();
169    }
170    private void OnItemLoaded(T item, int progress) {
171      if (InvokeRequired)
172        Invoke(new Action<T, int>(OnItemLoaded), item, progress);
173      else {
174        AddItem(item);
175        progressBar.Value += progress;
176      }
177    }
178    private void OnAllItemsLoaded() {
179      if (InvokeRequired)
180        Invoke(new Action(OnAllItemsLoaded));
181      else {
182        Enabled = true;
183        if (listView.Items.Count > 0) {
184          for (int i = 0; i < listView.Columns.Count; i++)
185            listView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
186        }
187        infoPanel.Visible = false;
188      }
189    }
190    private void SaveItems(object param) {
191      Directory.Delete(ItemsPath, true);
192      Directory.CreateDirectory(ItemsPath);
193      // directory creation might take some time -> wait until it is definitively created
194      while (!Directory.Exists(ItemsPath)) {
195        Thread.Sleep(100);
196        Directory.CreateDirectory(ItemsPath);
197      }
198
199      int i = 0;
200      T[] items = GetStorableItems(itemListViewItemMapping.Keys);
201
202      foreach (T item in items) {
203        try {
204          i++;
205          SetEnabledStateOfContentViews(item, false);
206          var ser = new ProtoBufSerializer();
207          ser.Serialize(item, ItemsPath + Path.DirectorySeparatorChar + i.ToString("00000000") + ".hl");
208          OnItemSaved(item, progressBar.Maximum / listView.Items.Count);
209        }
210        catch (Exception) { }
211        finally {
212          SetEnabledStateOfContentViews(item, true);
213        }
214      }
215      OnAllItemsSaved();
216    }
217
218    private void OnItemSaved(T item, int progress) {
219      if (item != null) {
220        if (InvokeRequired)
221          Invoke(new Action<T, int>(OnItemSaved), item, progress);
222        else {
223          progressBar.Value += progress;
224        }
225      }
226    }
227    private void OnAllItemsSaved() {
228      if (InvokeRequired)
229        Invoke(new Action(OnAllItemsLoaded));
230      else {
231        Enabled = true;
232        infoPanel.Visible = false;
233      }
234    }
235
236    private void SetEnabledStateOfContentViews(IItem item, bool enabled) {
237      if (InvokeRequired)
238        Invoke((Action<IItem, bool>)SetEnabledStateOfContentViews, item, enabled);
239      else {
240        var views = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v.Content == item).ToList();
241        views.ForEach(v => v.Enabled = enabled);
242      }
243    }
244
245    private static T[] GetStorableItems(IEnumerable<T> items) {
246      var query = from item in items
247                  let executeable = item as IExecutable
248                  let views = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v.Content == item)
249                  where executeable == null || executeable.ExecutionState != ExecutionState.Started
250                  where !views.Any(v => v.Locked)
251                  select item;
252      T[] itemArray = query.ToArray();
253      return itemArray;
254    }
255    #endregion
256
257    #region ListView Events
258    private void listView_SelectedIndexChanged(object sender, EventArgs e) {
259      removeButton.Enabled = !ReadOnly && listView.SelectedItems.Count > 0;
260    }
261    private void listView_KeyDown(object sender, KeyEventArgs e) {
262      if (e.KeyCode == Keys.Delete) {
263        if (!ReadOnly && (listView.SelectedItems.Count > 0)) {
264          foreach (ListViewItem item in listView.SelectedItems)
265            RemoveItem((T)item.Tag);
266          RebuildImageList();
267        }
268      }
269    }
270    private void listView_DoubleClick(object sender, EventArgs e) {
271      if (listView.SelectedItems.Count == 1) {
272        T item = (T)listView.SelectedItems[0].Tag;
273        IContentView view = MainFormManager.MainForm.ShowContent(item, true);
274      }
275    }
276    private void listView_ItemDrag(object sender, ItemDragEventArgs e) {
277      List<T> items = new List<T>();
278      foreach (ListViewItem listViewItem in listView.SelectedItems) {
279        T item = listViewItem.Tag as T;
280        if (item != null) items.Add(item);
281      }
282
283      if (items.Count > 0) {
284        DataObject data = new DataObject();
285        if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
286        else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
287        if (ReadOnly) {
288          DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
289        } else {
290          DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
291          if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
292            foreach (T item in items) RemoveItem(item);
293            RebuildImageList();
294          }
295        }
296      }
297    }
298    private void listView_DragEnter(object sender, DragEventArgs e) {
299      validDragOperation = false;
300      draggedItemsAlreadyContained = false;
301      if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T)) {
302        validDragOperation = true;
303        draggedItemsAlreadyContained = itemListViewItemMapping.ContainsKey((T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat));
304      } else if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable)) {
305        validDragOperation = true;
306        IEnumerable items = (IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
307        foreach (object item in items) {
308          validDragOperation = validDragOperation && (item is T);
309          draggedItemsAlreadyContained = draggedItemsAlreadyContained || itemListViewItemMapping.ContainsKey((T)item);
310        }
311      }
312    }
313    private void listView_DragOver(object sender, DragEventArgs e) {
314      e.Effect = DragDropEffects.None;
315      if (validDragOperation) {
316        if (((e.KeyState & 32) == 32) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Link;  // ALT key
317        else if (((e.KeyState & 4) == 4) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Move;  // SHIFT key
318        else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
319        else if (e.AllowedEffect.HasFlag(DragDropEffects.Move) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Move;
320        else if (e.AllowedEffect.HasFlag(DragDropEffects.Link) && !draggedItemsAlreadyContained) e.Effect = DragDropEffects.Link;
321      }
322    }
323    private void listView_DragDrop(object sender, DragEventArgs e) {
324      if (e.Effect != DragDropEffects.None) {
325        try {
326          if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T) {
327            T item = (T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
328            AddItem(e.Effect.HasFlag(DragDropEffects.Copy) ? (T)item.Clone() : item);
329          } else if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is IEnumerable) {
330            IEnumerable<T> items = ((IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat)).Cast<T>();
331            if (e.Effect.HasFlag(DragDropEffects.Copy)) {
332              Cloner cloner = new Cloner();
333              items = items.Select(x => cloner.Clone(x));
334            }
335            foreach (T item in items)
336              AddItem(item);
337          }
338        }
339        catch (Exception ex) {
340          ErrorHandling.ShowErrorDialog(this, ex);
341        }
342      }
343    }
344    #endregion
345
346    #region Button Events
347    private void addButton_Click(object sender, EventArgs e) {
348      if (typeSelectorDialog == null) {
349        typeSelectorDialog = new TypeSelectorDialog();
350        typeSelectorDialog.Caption = "Select Item";
351        typeSelectorDialog.TypeSelector.Caption = "Available Items";
352        typeSelectorDialog.TypeSelector.Configure(typeof(T), false, true);
353      }
354
355      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
356        try {
357          AddItem((T)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType());
358        }
359        catch (Exception ex) {
360          ErrorHandling.ShowErrorDialog(this, ex);
361        }
362      }
363    }
364    private void sortAscendingButton_Click(object sender, EventArgs e) {
365      listView.Sorting = SortOrder.None;
366      listView.Sorting = SortOrder.Ascending;
367    }
368    private void sortDescendingButton_Click(object sender, EventArgs e) {
369      listView.Sorting = SortOrder.None;
370      listView.Sorting = SortOrder.Descending;
371    }
372    private void removeButton_Click(object sender, EventArgs e) {
373      if (listView.SelectedItems.Count > 0) {
374        foreach (ListViewItem item in listView.SelectedItems)
375          RemoveItem((T)item.Tag);
376        RebuildImageList();
377      }
378    }
379    private void saveButton_Click(object sender, EventArgs e) {
380      IEnumerable<T> items = itemListViewItemMapping.Keys.Except(GetStorableItems(itemListViewItemMapping.Keys));
381      if (items.Any()) {
382        string itemNames = string.Join(Environment.NewLine, items.Select(item => item.ToString()).ToArray());
383        MessageBox.Show("The following items are not saved, because they are locked (e.g. used in a running algorithm):" + Environment.NewLine + Environment.NewLine +
384          itemNames + Environment.NewLine + Environment.NewLine + "All other items will be saved.", "Cannot save all items", MessageBoxButtons.OK, MessageBoxIcon.Warning);
385      }
386      Save();
387    }
388    #endregion
389
390    #region Item Events
391    private void Item_ItemImageChanged(object sender, EventArgs e) {
392      if (InvokeRequired)
393        Invoke(new EventHandler(Item_ItemImageChanged), sender, e);
394      else {
395        T item = (T)sender;
396        ListViewItem listViewItem = itemListViewItemMapping[item];
397        int i = listViewItem.ImageIndex;
398        listView.SmallImageList.Images[i] = item.ItemImage;
399        listViewItem.ImageIndex = -1;
400        listViewItem.ImageIndex = i;
401      }
402    }
403    private void Item_ToStringChanged(object sender, EventArgs e) {
404      if (InvokeRequired)
405        Invoke(new EventHandler(Item_ToStringChanged), sender, e);
406      else {
407        T item = (T)sender;
408        itemListViewItemMapping[item].Text = item.ToString();
409        listView.Sort();
410        AdjustListViewColumnSizes();
411      }
412    }
413    #endregion
414
415    #region Helpers
416    private void AdjustListViewColumnSizes() {
417      if (listView.Items.Count > 0) {
418        for (int i = 0; i < listView.Columns.Count; i++)
419          listView.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
420      }
421    }
422    private void RebuildImageList() {
423      listView.SmallImageList.Images.Clear();
424      foreach (ListViewItem item in listView.Items) {
425        listView.SmallImageList.Images.Add(((T)item.Tag).ItemImage);
426        item.ImageIndex = listView.SmallImageList.Images.Count - 1;
427      }
428    }
429    #endregion
430  }
431}
Note: See TracBrowser for help on using the repository browser.