Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2520: Use ContentManager in Clipboard and StartPage. Show info when objects cannot be restored.

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