source: branches/2839_HiveProjectManagement/HeuristicLab.Core.Views/3.3/Clipboard.cs @ 16057

Last change on this file since 16057 was 16057, checked in by jkarder, 15 months ago

#2839:

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