Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 16805 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

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