Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

File size: 17.2 KB
RevLine 
[3292]1#region License Information
2/* HeuristicLab
[17181]3 * Copyright (C) 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;
26using System.Linq;
27using System.Threading;
[3292]28using System.Windows.Forms;
[17097]29using HEAL.Attic;
[6527]30using HeuristicLab.Common;
[3292]31using HeuristicLab.MainForm;
[3758]32using HeuristicLab.PluginInfrastructure;
[3292]33
34namespace HeuristicLab.Core.Views {
35  [View("Clipboard")]
[3571]36  public sealed partial class Clipboard<T> : HeuristicLab.MainForm.WindowsForms.Sidebar where T : class, IItem {
[3298]37    private TypeSelectorDialog typeSelectorDialog;
[5237]38    private Dictionary<T, ListViewItem> itemListViewItemMapping;
[5744]39    private bool validDragOperation;
40    private bool draggedItemsAlreadyContained;
[3298]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
[3292]64    public Clipboard() {
65      InitializeComponent();
[3298]66      ItemsPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
67                  Path.DirectorySeparatorChar + "HeuristicLab" + Path.DirectorySeparatorChar + "Clipboard";
[5237]68      itemListViewItemMapping = new Dictionary<T, ListViewItem>();
[3292]69    }
[3298]70    public Clipboard(string itemsPath) {
71      InitializeComponent();
72      ItemsPath = itemsPath;
[5237]73      itemListViewItemMapping = new Dictionary<T, ListViewItem>();
[3298]74    }
[3292]75
[5237]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
[3292]88    protected override void OnInitialized(EventArgs e) {
89      base.OnInitialized(e);
[3362]90      SetEnabledStateOfControls();
[3298]91      Enabled = false;
92      infoLabel.Text = "Loading ...";
93      progressBar.Value = 0;
94      infoPanel.Visible = true;
95      ThreadPool.QueueUserWorkItem(new WaitCallback(LoadItems));
[3292]96    }
[3298]97
[3904]98    protected override void SetEnabledStateOfControls() {
99      base.SetEnabledStateOfControls();
[3362]100      addButton.Enabled = !ReadOnly;
101      removeButton.Enabled = !ReadOnly && listView.SelectedItems.Count > 0;
102      saveButton.Enabled = !ReadOnly;
103    }
104
[3298]105    public void AddItem(T item) {
106      if (InvokeRequired)
107        Invoke(new Action<T>(AddItem), item);
108      else {
[5237]109        if (item == null) throw new ArgumentNullException("item", "Cannot add null item to clipboard.");
110        if (!itemListViewItemMapping.ContainsKey(item)) {
[3298]111          ListViewItem listViewItem = new ListViewItem(item.ToString());
112          listViewItem.ToolTipText = item.ItemName + ": " + item.ItemDescription;
[3341]113          listView.SmallImageList.Images.Add(item.ItemImage);
114          listViewItem.ImageIndex = listView.SmallImageList.Images.Count - 1;
[3298]115          listViewItem.Tag = item;
116          listView.Items.Add(listViewItem);
[5237]117          itemListViewItemMapping.Add(item, listViewItem);
[3341]118          item.ItemImageChanged += new EventHandler(Item_ItemImageChanged);
[3298]119          item.ToStringChanged += new EventHandler(Item_ToStringChanged);
120          sortAscendingButton.Enabled = sortDescendingButton.Enabled = listView.Items.Count > 1;
[3299]121          AdjustListViewColumnSizes();
[3298]122        }
123      }
124    }
[3341]125
[3298]126    private void RemoveItem(T item) {
127      if (InvokeRequired)
128        Invoke(new Action<T>(RemoveItem), item);
129      else {
[5237]130        if (itemListViewItemMapping.ContainsKey(item)) {
[3341]131          item.ItemImageChanged -= new EventHandler(Item_ItemImageChanged);
[3298]132          item.ToStringChanged -= new EventHandler(Item_ToStringChanged);
[5237]133          ListViewItem listViewItem = itemListViewItemMapping[item];
[3341]134          listViewItem.Remove();
[5237]135          itemListViewItemMapping.Remove(item);
[3298]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 {
[17105]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          }
[3298]163          OnItemLoaded(item, progressBar.Maximum / items.Length);
[17097]164        } catch (Exception) {
[17105]165          // ignore if loading a clipboad item fails.
[3298]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;
[5237]200      T[] items = GetStorableItems(itemListViewItemMapping.Keys);
[4447]201
[3298]202      foreach (T item in items) {
203        try {
204          i++;
[4435]205          SetEnabledStateOfContentViews(item, false);
[17097]206          var ser = new ProtoBufSerializer();
207          ser.Serialize(item, ItemsPath + Path.DirectorySeparatorChar + i.ToString("00000000") + ".hl");
[3298]208          OnItemSaved(item, progressBar.Maximum / listView.Items.Count);
209        }
210        catch (Exception) { }
[4447]211        finally {
212          SetEnabledStateOfContentViews(item, true);
213        }
[3298]214      }
215      OnAllItemsSaved();
216    }
[4453]217
[3298]218    private void OnItemSaved(T item, int progress) {
219      if (item != null) {
220        if (InvokeRequired)
[4435]221          Invoke(new Action<T, int>(OnItemSaved), item, progress);
222        else {
[3298]223          progressBar.Value += progress;
[4435]224        }
[3298]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    }
[4435]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    }
[4453]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    }
[3298]255    #endregion
256
257    #region ListView Events
258    private void listView_SelectedIndexChanged(object sender, EventArgs e) {
[3362]259      removeButton.Enabled = !ReadOnly && listView.SelectedItems.Count > 0;
[3298]260    }
261    private void listView_KeyDown(object sender, KeyEventArgs e) {
262      if (e.KeyCode == Keys.Delete) {
[3362]263        if (!ReadOnly && (listView.SelectedItems.Count > 0)) {
[3298]264          foreach (ListViewItem item in listView.SelectedItems)
265            RemoveItem((T)item.Tag);
[5237]266          RebuildImageList();
[3298]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;
[5270]273        IContentView view = MainFormManager.MainForm.ShowContent(item, true);
[3298]274      }
275    }
276    private void listView_ItemDrag(object sender, ItemDragEventArgs e) {
[5744]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();
[5837]285        if (items.Count == 1) data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items[0]);
286        else data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, items);
[5744]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          }
[5237]295        }
[3362]296      }
[3298]297    }
[5744]298    private void listView_DragEnter(object sender, DragEventArgs e) {
299      validDragOperation = false;
300      draggedItemsAlreadyContained = false;
[5837]301      if (!ReadOnly && (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T)) {
[5744]302        validDragOperation = true;
[5837]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)) {
[5744]305        validDragOperation = true;
[5837]306        IEnumerable items = (IEnumerable)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
[5744]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) {
[3298]314      e.Effect = DragDropEffects.None;
[5744]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;
[3298]321      }
322    }
323    private void listView_DragDrop(object sender, DragEventArgs e) {
324      if (e.Effect != DragDropEffects.None) {
[5237]325        try {
[5837]326          if (e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) is T) {
327            T item = (T)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
[5744]328            AddItem(e.Effect.HasFlag(DragDropEffects.Copy) ? (T)item.Clone() : item);
[5837]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>();
[6527]331            if (e.Effect.HasFlag(DragDropEffects.Copy)) {
332              Cloner cloner = new Cloner();
333              items = items.Select(x => cloner.Clone(x));
334            }
[5744]335            foreach (T item in items)
[6527]336              AddItem(item);
[5744]337          }
[5237]338        }
339        catch (Exception ex) {
340          ErrorHandling.ShowErrorDialog(this, ex);
341        }
[3298]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";
[3588]352        typeSelectorDialog.TypeSelector.Configure(typeof(T), false, true);
[3298]353      }
354
[3407]355      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
356        try {
357          AddItem((T)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType());
358        }
359        catch (Exception ex) {
[3758]360          ErrorHandling.ShowErrorDialog(this, ex);
[3407]361        }
362      }
[3298]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);
[5237]376        RebuildImageList();
[3298]377      }
378    }
379    private void saveButton_Click(object sender, EventArgs e) {
[5237]380      IEnumerable<T> items = itemListViewItemMapping.Keys.Except(GetStorableItems(itemListViewItemMapping.Keys));
[4453]381      if (items.Any()) {
382        string itemNames = string.Join(Environment.NewLine, items.Select(item => item.ToString()).ToArray());
[4500]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);
[4447]385      }
[3298]386      Save();
387    }
388    #endregion
389
390    #region Item Events
[3341]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;
[5237]396        ListViewItem listViewItem = itemListViewItemMapping[item];
[3341]397        int i = listViewItem.ImageIndex;
[5839]398        listView.SmallImageList.Images[i] = item.ItemImage;
[3341]399        listViewItem.ImageIndex = -1;
400        listViewItem.ImageIndex = i;
401      }
402    }
[3298]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;
[5237]408        itemListViewItemMapping[item].Text = item.ToString();
[3298]409        listView.Sort();
[3299]410        AdjustListViewColumnSizes();
[3298]411      }
412    }
413    #endregion
[3299]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    }
[5237]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    }
[3299]429    #endregion
[3292]430  }
431}
Note: See TracBrowser for help on using the repository browser.