Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.cs @ 7274

Last change on this file since 7274 was 7274, checked in by swagner, 12 years ago

Added context menu items to expand or collapse all tree nodes in the ExperimentTreeView (#1726)

File size: 40.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Core.Views;
32using HeuristicLab.MainForm;
33using HeuristicLab.PluginInfrastructure;
34
35namespace HeuristicLab.Optimization.Views {
36  public sealed partial class ExperimentTreeView : ItemView {
37    private TypeSelectorDialog typeSelectorDialog;
38    private Dictionary<INamedItem, List<TreeNode>> treeNodeTagMapping;
39
40    public ExperimentTreeView() {
41      InitializeComponent();
42      treeNodeTagMapping = new Dictionary<INamedItem, List<TreeNode>>();
43    }
44
45    protected override void Dispose(bool disposing) {
46      if (disposing) {
47        if (typeSelectorDialog != null) typeSelectorDialog.Dispose();
48        if (components != null) components.Dispose();
49      }
50      base.Dispose(disposing);
51    }
52
53    #region necessary code to handle dock correctly regarding the expanded nodes
54    bool[] expandendedState;
55    protected override void OnHandleCreated(EventArgs e) {
56      base.OnHandleCreated(e);
57      if (expandendedState == null) return;
58      var nodes = IterateTreeNodes().ToList();
59      for (int i = 0; i < nodes.Count; i++)
60        if (expandendedState[i]) nodes[i].Expand();
61    }
62    protected override void OnHandleDestroyed(EventArgs e) {
63      base.OnHandleDestroyed(e);
64      var nodes = IterateTreeNodes().ToList();
65      expandendedState = new bool[nodes.Count];
66      for (int i = 0; i < nodes.Count; i++)
67        expandendedState[i] = nodes[i].IsExpanded;
68    }
69    #endregion
70
71    public new Experiment Content {
72      get { return (Experiment)base.Content; }
73      set { base.Content = value; }
74    }
75
76    #region events registration
77    protected override void RegisterContentEvents() {
78      base.RegisterContentEvents();
79      Content.ExecutionStateChanged += new EventHandler(Content_ExecutionStateChanged);
80      Content.Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
81      Content.Optimizers.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsMoved);
82      Content.Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
83      Content.Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
84      Content.Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
85    }
86
87    protected override void DeregisterContentEvents() {
88      Content.ExecutionStateChanged -= new EventHandler(Content_ExecutionStateChanged);
89      Content.Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
90      Content.Optimizers.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsMoved);
91      Content.Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
92      Content.Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
93      Content.Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
94      foreach (var optimizer in treeNodeTagMapping.Keys)
95        DeregisterNamedItemEvents(optimizer);
96      base.DeregisterContentEvents();
97    }
98
99    private void RegisterNamedItemEvents(INamedItem namedItem) {
100      namedItem.ToStringChanged += new EventHandler(namedItem_ToStringChanged);
101      namedItem.ItemImageChanged += new EventHandler(namedItem_ItemImageChanged);
102
103      var algorithm = namedItem as IAlgorithm;
104      var batchRun = namedItem as BatchRun;
105      var experiment = namedItem as Experiment;
106
107      if (algorithm != null) {
108        algorithm.Prepared += new EventHandler(algorithm_Prepared);
109        algorithm.ProblemChanged += new EventHandler(algorithm_ProblemChanged);
110      } else if (batchRun != null) {
111        batchRun.OptimizerChanged += new EventHandler(batchRun_OptimizerChanged);
112      } else if (experiment != null) {
113        experiment.Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
114        experiment.Optimizers.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsMoved);
115        experiment.Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
116        experiment.Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
117        experiment.Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
118      }
119    }
120
121    private void DeregisterNamedItemEvents(INamedItem namedItem) {
122      namedItem.ToStringChanged -= new EventHandler(namedItem_ToStringChanged);
123      namedItem.ItemImageChanged -= new EventHandler(namedItem_ItemImageChanged);
124
125      var algorithm = namedItem as IAlgorithm;
126      var batchRun = namedItem as BatchRun;
127      var experiment = namedItem as Experiment;
128
129      if (algorithm != null) {
130        algorithm.Prepared -= new EventHandler(algorithm_Prepared);
131        algorithm.ProblemChanged -= new EventHandler(algorithm_ProblemChanged);
132      } else if (batchRun != null) {
133        batchRun.OptimizerChanged -= new EventHandler(batchRun_OptimizerChanged);
134      } else if (experiment != null) {
135        experiment.Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
136        experiment.Optimizers.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsMoved);
137        experiment.Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
138        experiment.Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
139        experiment.Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
140      }
141    }
142    #endregion
143
144    protected override void OnContentChanged() {
145      base.OnContentChanged();
146      if (Content == null) {
147        treeView.Nodes.Clear();
148      } else {
149        UpdateOptimizerTreeView();
150        treeView.ExpandAll();
151      }
152    }
153
154    #region content events
155    private void Content_ExecutionStateChanged(object sender, EventArgs e) {
156      if (InvokeRequired) {
157        Invoke((Action<object, EventArgs>)Content_ExecutionStateChanged, sender, e);
158        return;
159      }
160      SetEnabledStateOfControls();
161    }
162
163    private void algorithm_Prepared(object sender, EventArgs e) {
164      var algorithm = (IAlgorithm)sender;
165      foreach (TreeNode node in treeNodeTagMapping[algorithm]) {
166        TreeNode resultsNode = node.Nodes.OfType<TreeNode>().Where(x => x.Tag is ResultCollection).Single();
167        if (detailsViewHost.Content == resultsNode.Tag)
168          detailsViewHost.Content = algorithm.Results;
169        resultsNode.Tag = algorithm.Results;
170      }
171    }
172
173    private void algorithm_ProblemChanged(object sender, EventArgs e) {
174      if (InvokeRequired) {
175        Invoke((Action<object, EventArgs>)algorithm_ProblemChanged, sender, e);
176        return;
177      }
178
179      var algorithm = (IAlgorithm)sender;
180      foreach (TreeNode node in treeNodeTagMapping[algorithm]) {
181        foreach (TreeNode childNode in node.Nodes.OfType<TreeNode>().ToList()) {
182          DisposeTreeNode(childNode);
183          childNode.Remove();
184        }
185        List<TreeNode> nodes;
186        foreach (TreeNode childNode in CreateAlgorithmChildNodes(algorithm)) {
187          node.Nodes.Add(childNode);
188          NamedItem namedItem = childNode.Tag as NamedItem;
189          if (namedItem != null) {
190            if (!treeNodeTagMapping.TryGetValue(namedItem, out nodes)) {
191              nodes = new List<TreeNode>();
192              treeNodeTagMapping.Add(namedItem, nodes);
193              RegisterNamedItemEvents(namedItem);
194            }
195            nodes.Add(childNode);
196          }
197        }
198
199        node.Expand();
200      }
201
202      RebuildImageList();
203      UpdateDetailsViewHost();
204    }
205
206    private void batchRun_OptimizerChanged(object sender, EventArgs e) {
207      if (InvokeRequired) {
208        Invoke((Action<object, EventArgs>)batchRun_OptimizerChanged, sender, e);
209        return;
210      }
211      var batchRun = (BatchRun)sender;
212      foreach (TreeNode node in treeNodeTagMapping[batchRun]) {
213        foreach (TreeNode childNode in node.Nodes.OfType<TreeNode>().ToList()) {
214          DisposeTreeNode(childNode);
215          childNode.Remove();
216        }
217
218        if (batchRun.Optimizer != null) {
219          UpdateChildTreeNodes(node.Nodes, batchRun);
220          node.Expand();
221        }
222      }
223      RebuildImageList();
224      UpdateDetailsViewHost();
225    }
226
227    private void Optimizers_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
228      if (InvokeRequired) {
229        Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>>>)Optimizers_ItemsAdded, sender, e);
230        return;
231      }
232
233      var optimizerList = (OptimizerList)sender;
234      IEnumerable<TreeNodeCollection> parentNodes;
235      if (optimizerList == Content.Optimizers) parentNodes = new List<TreeNodeCollection>() { treeView.Nodes };
236      else {
237        Experiment experiment = treeNodeTagMapping.Keys.OfType<Experiment>().Where(exp => exp.Optimizers == optimizerList).First();
238        parentNodes = treeNodeTagMapping[experiment].Select(node => node.Nodes);
239      }
240
241      foreach (TreeNodeCollection parentNode in parentNodes) {
242        foreach (var childOptimizer in e.Items) {
243          TreeNode childNode = CreateTreeNode(childOptimizer.Value);
244          UpdateChildTreeNodes(childNode.Nodes, childOptimizer.Value);
245          parentNode.Insert(childOptimizer.Index, childNode);
246          childNode.ExpandAll();
247          if (childNode.Parent != null) childNode.Parent.ExpandAll();
248        }
249      }
250      RebuildImageList();
251    }
252    private void Optimizers_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
253      if (InvokeRequired) {
254        Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>>>)Optimizers_ItemsMoved, sender, e);
255        return;
256      }
257
258      var optimizerList = (OptimizerList)sender;
259      IEnumerable<TreeNodeCollection> parentNodes;
260      if (optimizerList == Content.Optimizers) parentNodes = new List<TreeNodeCollection>() { treeView.Nodes };
261      else {
262        Experiment experiment = treeNodeTagMapping.Keys.OfType<Experiment>().Where(exp => exp.Optimizers == optimizerList).First();
263        parentNodes = treeNodeTagMapping[experiment].Select(node => node.Nodes);
264      }
265
266      foreach (TreeNodeCollection parentNode in parentNodes) {
267        var backup = parentNode.OfType<TreeNode>().ToList();
268        foreach (var indexedItem in e.Items) {
269          var node = backup.Where(n => n.Tag == indexedItem.Value).First();
270          node.Remove();
271          parentNode.Insert(indexedItem.Index, node);
272        }
273      }
274    }
275    private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
276      if (InvokeRequired) {
277        Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>>>)Optimizers_ItemsRemoved, sender, e);
278        return;
279      }
280
281      var optimizerList = (OptimizerList)sender;
282      IEnumerable<TreeNodeCollection> parentNodes;
283      if (optimizerList == Content.Optimizers) parentNodes = new List<TreeNodeCollection>() { treeView.Nodes };
284      else {
285        Experiment experiment = treeNodeTagMapping.Keys.OfType<Experiment>().Where(exp => exp.Optimizers == optimizerList).First();
286        parentNodes = treeNodeTagMapping[experiment].Select(node => node.Nodes);
287      }
288
289      foreach (TreeNodeCollection parentNode in parentNodes) {
290        foreach (var childOptimizer in e.Items) {
291          TreeNode childNode = parentNode[childOptimizer.Index];
292          DisposeTreeNode(childNode);
293          childNode.Remove();
294        }
295      }
296      RebuildImageList();
297      UpdateDetailsViewHost();
298    }
299    private void Optimizers_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
300      if (InvokeRequired) {
301        Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>>>)Optimizers_ItemsReplaced, sender, e);
302        return;
303      }
304
305      var optimizerList = (OptimizerList)sender;
306      IEnumerable<TreeNodeCollection> parentNodes;
307      if (optimizerList == Content.Optimizers) parentNodes = new List<TreeNodeCollection>() { treeView.Nodes };
308      else {
309        Experiment experiment = treeNodeTagMapping.Keys.OfType<Experiment>().Where(exp => exp.Optimizers == optimizerList).First();
310        parentNodes = treeNodeTagMapping[experiment].Select(node => node.Nodes);
311      }
312
313      foreach (TreeNodeCollection parentNode in parentNodes) {
314        foreach (var childOptimizer in e.OldItems) {
315          TreeNode childNode = parentNode.Cast<TreeNode>().Where(n => n.Tag == childOptimizer.Value && n.Index == childOptimizer.Index).First();
316          DisposeTreeNode(childNode);
317          childNode.Remove();
318        }
319        foreach (var childOptimizer in e.Items) {
320          TreeNode childNode = CreateTreeNode(childOptimizer.Value);
321          UpdateChildTreeNodes(childNode.Nodes, childOptimizer.Value);
322          parentNode.Insert(childOptimizer.Index, childNode);
323        }
324      }
325      RebuildImageList();
326      UpdateDetailsViewHost();
327    }
328    private void Optimizers_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
329      if (InvokeRequired) {
330        Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>>>)Optimizers_CollectionReset, sender, e);
331        return;
332      }
333
334      var optimizerList = (OptimizerList)sender;
335      IEnumerable<TreeNodeCollection> parentNodes;
336      if (optimizerList == Content.Optimizers) parentNodes = new List<TreeNodeCollection>() { treeView.Nodes };
337      else {
338        Experiment experiment = treeNodeTagMapping.Keys.OfType<Experiment>().Where(exp => exp.Optimizers == optimizerList).First();
339        parentNodes = treeNodeTagMapping[experiment].Select(node => node.Nodes);
340      }
341
342      foreach (TreeNodeCollection parentNode in parentNodes) {
343        foreach (var childOptimizer in e.OldItems) {
344          TreeNode childNode = parentNode.Cast<TreeNode>().Where(n => n.Tag == childOptimizer.Value && n.Index == childOptimizer.Index).First();
345          DisposeTreeNode(childNode);
346          childNode.Remove();
347        }
348        foreach (var childOptimizer in e.Items) {
349          TreeNode childNode = CreateTreeNode(childOptimizer.Value);
350          UpdateChildTreeNodes(childNode.Nodes, childOptimizer.Value);
351          parentNode.Insert(childOptimizer.Index, childNode);
352        }
353      }
354      RebuildImageList();
355      UpdateDetailsViewHost();
356    }
357
358    private void namedItem_ToStringChanged(object sender, EventArgs e) {
359      if (InvokeRequired) {
360        Invoke((Action<object, EventArgs>)namedItem_ToStringChanged, sender, e);
361        return;
362      }
363      var namedItem = (INamedItem)sender;
364      foreach (TreeNode node in treeNodeTagMapping[namedItem])
365        node.Text = namedItem.ToString();
366    }
367
368    private void namedItem_ItemImageChanged(object sender, EventArgs e) {
369      if (InvokeRequired) {
370        Invoke((Action<object, EventArgs>)namedItem_ItemImageChanged, sender, e);
371        return;
372      }
373      INamedItem namedItem = (INamedItem)sender;
374      foreach (TreeNode node in treeNodeTagMapping[namedItem]) {
375        treeView.ImageList.Images[node.ImageIndex] = namedItem.ItemImage;
376        node.ImageIndex = node.ImageIndex;
377      }
378      SetEnabledStateOfControls();
379    }
380    #endregion
381
382    protected override void PropagateStateChanges(Control control, Type type, System.Reflection.PropertyInfo propertyInfo) {
383      return;
384    }
385
386    protected override void SetEnabledStateOfControls() {
387      base.SetEnabledStateOfControls();
388      IOptimizer optimizer = null;
389      IAlgorithm algorithm = null;
390      BatchRun batchRun = null;
391      Experiment experiment = null;
392
393      IOptimizer parentOptimizer = null;
394      Experiment parentExperiment = null;
395
396      if (treeView.SelectedNode != null) {
397        optimizer = treeView.SelectedNode.Tag as IOptimizer;
398        algorithm = optimizer as IAlgorithm;
399        batchRun = optimizer as BatchRun;
400        experiment = optimizer as Experiment;
401
402        if (treeView.SelectedNode.Parent != null) parentOptimizer = treeView.SelectedNode.Parent.Tag as IOptimizer;
403        else parentOptimizer = Content;
404
405        parentExperiment = parentOptimizer as Experiment;
406      }
407
408      treeView.Enabled = Content != null;
409      if (parentOptimizer != null) {
410        detailsViewHost.ReadOnly = parentOptimizer.ExecutionState == ExecutionState.Started;
411        detailsViewHost.Locked = parentOptimizer.ExecutionState == ExecutionState.Started;
412      }
413
414      addButton.Enabled = Content != null && !Locked && !ReadOnly &&
415        (treeView.SelectedNode == null || experiment != null || batchRun != null || algorithm != null);
416      moveUpButton.Enabled = Content != null && !Locked && !ReadOnly &&
417        treeView.SelectedNode != null && treeView.SelectedNode.PrevNode != null && parentExperiment != null;
418      moveDownButton.Enabled = Content != null && !Locked && !ReadOnly &&
419        treeView.SelectedNode != null && treeView.SelectedNode.NextNode != null && parentExperiment != null;
420      removeButton.Enabled = Content != null && !Locked && !ReadOnly && optimizer != null;
421    }
422
423    private void UpdateOptimizerTreeView() {
424      treeView.Nodes.Clear();
425      UpdateChildTreeNodes(treeView.Nodes, Content);
426      RebuildImageList();
427    }
428
429    private void UpdateChildTreeNodes(TreeNodeCollection collection, IOptimizer optimizer) {
430      var batchRun = optimizer as BatchRun;
431      var experiment = optimizer as Experiment;
432
433      if (batchRun != null && batchRun.Optimizer != null) UpdateChildTreeNodes(collection, new List<IOptimizer>() { batchRun.Optimizer });
434      else if (experiment != null) UpdateChildTreeNodes(collection, experiment.Optimizers);
435    }
436    private void UpdateChildTreeNodes(TreeNodeCollection collection, IEnumerable<IOptimizer> optimizers) {
437      foreach (IOptimizer optimizer in optimizers) {
438        var node = CreateTreeNode(optimizer);
439        collection.Add(node);
440        UpdateChildTreeNodes(node.Nodes, optimizer);
441      }
442    }
443
444
445    #region drag & drop
446    private void optimizerTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
447      if (Locked) return;
448
449      TreeNode selectedNode = (TreeNode)e.Item;
450      var item = (IItem)selectedNode.Tag;
451      if (item == null) return;
452
453      DataObject data = new DataObject();
454      data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, item);
455      validDragOperation = true;
456
457      if (ReadOnly || !(item is IOptimizer)) {
458        DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
459      } else {
460        DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
461        if ((result & DragDropEffects.Move) == DragDropEffects.Move) {
462          var optimizer = (IOptimizer)item;
463          if (selectedNode.Parent == null) Content.Optimizers.Remove(optimizer);
464          else {
465            var parentOptimizer = (IOptimizer)selectedNode.Parent.Tag;
466            var parentBatchRun = parentOptimizer as BatchRun;
467            var parentExperiment = parentOptimizer as Experiment;
468            if (parentBatchRun != null) parentBatchRun.Optimizer = null;
469            else if (parentExperiment != null) parentExperiment.Optimizers.Remove(optimizer);
470            else throw new NotSupportedException("Handling for specific type not implemented" + parentOptimizer.GetType());
471          }
472        }
473      }
474    }
475
476    private bool validDragOperation = false;
477    private void optimizerTreeView_DragEnter(object sender, DragEventArgs e) {
478      validDragOperation = false;
479      if (!ReadOnly) {
480        var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
481        if (data is IOptimizer) validDragOperation = true;
482        else if (data is IProblem) validDragOperation = true;
483        else if (data is IEnumerable) {
484          IEnumerable items = (IEnumerable)data;
485          validDragOperation = true;
486          foreach (object item in items)
487            validDragOperation = validDragOperation && (item is IOptimizer);
488        }
489      }
490    }
491    private void optimizerTreeView_DragOver(object sender, DragEventArgs e) {
492      e.Effect = DragDropEffects.None;
493      if (!validDragOperation) return;
494      Point coordinates = treeView.PointToClient(new Point(e.X, e.Y));
495      TreeNode node = treeView.GetNodeAt(coordinates);
496      Experiment experiment = null;
497      BatchRun batchRun = null;
498      Algorithm algorithm = null;
499
500      if (node == null) experiment = Content;
501      else {
502        experiment = node.Tag as Experiment;
503        batchRun = node.Tag as BatchRun;
504        algorithm = node.Tag as Algorithm;
505      }
506
507      if (batchRun == null && experiment == null && algorithm == null) return;
508
509      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
510
511      if (algorithm != null) {
512        var problem = data as IProblem;
513        if (problem == null) return;
514        if (!algorithm.ProblemType.IsAssignableFrom(problem.GetType())) return;
515      } else if (batchRun != null) {
516        var optimizer = data as IOptimizer;
517        if (optimizer == null) return;
518        if (batchRun == optimizer) return;
519        if (optimizer.NestedOptimizers.Contains(batchRun)) return;
520      } //do not allow recursive nesting of contents
521      else if (experiment != null) {
522        var optimizer = data as IOptimizer;
523        IEnumerable<IOptimizer> optimizers = null;
524        var enumerable = data as IEnumerable;
525        if (enumerable != null) optimizers = enumerable.Cast<IOptimizer>();
526        if (experiment == optimizer) return;
527        if (optimizer != null && optimizer.NestedOptimizers.Contains(experiment)) return;
528        if (optimizers != null && optimizers.Any(x => x.NestedOptimizers.Contains(experiment))) return;
529      }
530
531      if ((e.KeyState & 32) == 32 && e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;  // ALT key
532      else if ((e.KeyState & 4) == 4 && e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;  // SHIFT key
533      else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
534      else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
535      else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
536    }
537
538    private void optimizerTreeView_DragDrop(object sender, DragEventArgs e) {
539      Point coordinates = treeView.PointToClient(new Point(e.X, e.Y));
540      TreeNode node = treeView.GetNodeAt(coordinates);
541      Algorithm algorithm = null;
542      BatchRun batchRun = null;
543      Experiment experiment = null;
544
545      if (node == null) experiment = Content;
546      else {
547        algorithm = node.Tag as Algorithm;
548        batchRun = node.Tag as BatchRun;
549        experiment = node.Tag as Experiment;
550      }
551
552      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
553      if (data is IProblem) {
554        var problem = (IProblem)data;
555        if (e.Effect.HasFlag(DragDropEffects.Copy)) problem = (IProblem)problem.Clone();
556        algorithm.Problem = problem;
557      } else if (data is IOptimizer) {
558        IOptimizer optimizer = (IOptimizer)data;
559        if (e.Effect.HasFlag(DragDropEffects.Copy)) optimizer = (IOptimizer)optimizer.Clone();
560        if (batchRun != null) batchRun.Optimizer = optimizer;
561        else if (experiment != null) experiment.Optimizers.Add(optimizer);
562        else throw new NotSupportedException("Handling for specific type not implemented" + node.Tag.GetType());
563      } else if (data is IEnumerable) {
564        IEnumerable<IOptimizer> optimizers = ((IEnumerable)data).Cast<IOptimizer>();
565        if (e.Effect.HasFlag(DragDropEffects.Copy)) {
566          Cloner cloner = new Cloner();
567          optimizers = optimizers.Select(o => cloner.Clone(o));
568        }
569        if (experiment != null) experiment.Optimizers.AddRange(optimizers);
570        else throw new NotSupportedException("Handling for specific type not implemented" + node.Tag.GetType());
571      }
572    }
573    #endregion
574
575    #region control events
576    private void treeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
577      if (rightClickOccured) return;
578      if (e.X < e.Node.Bounds.Left - treeView.ImageList.Images[e.Node.ImageIndex].Width || e.X > e.Node.Bounds.Right) return;
579      e.Node.Toggle();
580      IContent optimizer = (IContent)e.Node.Tag;
581      MainFormManager.MainForm.ShowContent(optimizer);
582    }
583    private void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) {
584      if (e.X < e.Node.Bounds.Left - treeView.ImageList.Images[e.Node.ImageIndex].Width || e.X > e.Node.Bounds.Right) return;
585      treeView.SelectedNode = e.Node;
586      detailsViewHost.Content = (IContent)e.Node.Tag;
587      SetEnabledStateOfControls();
588    }
589    private void treeView_MouseDown(object sender, MouseEventArgs e) {
590      // enables deselection of treeNodes
591      if (e.Button != MouseButtons.Right) rightClickOccured = false;
592      if (treeView.SelectedNode == null) return;
593      Point coordinates = new Point(e.X, e.Y);
594      TreeNode node = treeView.GetNodeAt(coordinates);
595      if (node == null || coordinates.X < node.Bounds.Left - treeView.ImageList.Images[node.ImageIndex].Width || coordinates.X > node.Bounds.Right) {
596        treeView.SelectedNode = null;
597        detailsViewHost.Content = null;
598        SetEnabledStateOfControls();
599      }
600    }
601
602
603    private void treeView_KeyDown(object sender, KeyEventArgs e) {
604      if (Locked || ReadOnly) return;
605      if (treeView.SelectedNode == null) return;
606      if (!(treeView.SelectedNode.Tag is INamedItem)) return;
607
608      var treeNode = treeView.SelectedNode;
609      var namedItem = (NamedItem)treeNode.Tag;
610      var optimizer = namedItem as IOptimizer;
611
612      if (e.KeyCode == Keys.F2 && !treeNode.IsEditing) {
613        treeNode.BeginEdit();
614        return;
615      }
616
617      if (e.KeyCode == Keys.Delete && optimizer != null) {
618        if (treeNode.Parent == null)
619          Content.Optimizers.Remove(optimizer);
620        else {
621          var batchRun = treeNode.Parent.Tag as BatchRun;
622          var experiment = treeNode.Parent.Tag as Experiment;
623          if (batchRun != null) batchRun.Optimizer = null;
624          else if (experiment != null) experiment.Optimizers.Remove(optimizer);
625          else throw new NotSupportedException("Handling for specific type not implemented" + treeView.SelectedNode.Tag.GetType());
626        }
627        SetEnabledStateOfControls();
628        UpdateDetailsViewHost();
629        RebuildImageList();
630      }
631    }
632
633
634    private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
635      if (e.Action == TreeViewAction.ByKeyboard) {
636        UpdateDetailsViewHost();
637        //NOTE: necessary because algorithm view steals the focus
638        treeView.Focus();
639      }
640    }
641
642    private bool rightClickOccured = true;
643    private TreeNode toolStripMenuNode = null;
644    private void treeView_RightClick(object sender, EventArgs e) {
645      rightClickOccured = true;
646      Point coordinates = treeView.PointToClient(Cursor.Position);
647      toolStripMenuNode = treeView.GetNodeAt(coordinates);
648
649      if (toolStripMenuNode != null && coordinates.X >= toolStripMenuNode.Bounds.Left && coordinates.X <= toolStripMenuNode.Bounds.Right) {
650        treeView.SelectedNode = toolStripMenuNode;
651        detailsViewHost.Content = (IContent)toolStripMenuNode.Tag;
652        SetEnabledStateOfControls();
653
654        ExpandToolStripMenuItem.Enabled = ExpandToolStripMenuItem.Visible = !toolStripMenuNode.IsExpanded && toolStripMenuNode.Nodes.Count > 0;
655        CollapseToolStripMenuItem.Enabled = CollapseToolStripMenuItem.Visible = toolStripMenuNode.IsExpanded;
656        EditNodeLabelToolStripMenuItem.Enabled = EditNodeLabelToolStripMenuItem.Visible = !Locked && !ReadOnly && toolStripMenuNode.Tag != null && toolStripMenuNode.Tag is INamedItem && ((INamedItem)toolStripMenuNode.Tag).CanChangeName;
657      } else {
658        ExpandToolStripMenuItem.Enabled = ExpandToolStripMenuItem.Visible = false;
659        CollapseToolStripMenuItem.Enabled = CollapseToolStripMenuItem.Visible = false;
660        EditNodeLabelToolStripMenuItem.Enabled = EditNodeLabelToolStripMenuItem.Visible = false;
661      }
662      ExpandAllToolStripMenuItem.Enabled = ExpandAllToolStripMenuItem.Visible = !treeView.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x));
663      CollapseAllToolStripMenuItem.Enabled = CollapseAllToolStripMenuItem.Visible = treeView.Nodes.OfType<TreeNode>().Any(x => x.IsExpanded);
664      if (contextMenuStrip.Items.Cast<ToolStripMenuItem>().Any(item => item.Enabled))
665        contextMenuStrip.Show(Cursor.Position);
666    }
667
668    private void treeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e) {
669      if (Locked) e.CancelEdit = true;
670      if (ReadOnly) e.CancelEdit = true;
671      if (e.Node.Tag == null) e.CancelEdit = true;
672      var namedItem = e.Node.Tag as INamedItem;
673      if (namedItem == null) e.CancelEdit = true;
674      else if (!namedItem.CanChangeName) e.CancelEdit = true;
675    }
676    private void treeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) {
677      if (e.Label == null) return;
678      e.Node.EndEdit(false);
679      var namedItem = (INamedItem)e.Node.Tag;
680      namedItem.Name = e.Label;
681    }
682
683    private void ExpandToolStripMenuItem_Click(object sender, EventArgs e) {
684      if (toolStripMenuNode != null) toolStripMenuNode.ExpandAll();
685    }
686    private void ExpandAllToolStripMenuItem_Click(object sender, EventArgs e) {
687      treeView.ExpandAll();
688    }
689    private void CollapseToolStripMenuItem_Click(object sender, EventArgs e) {
690      if (toolStripMenuNode != null) toolStripMenuNode.Collapse();
691    }
692    private void CollapseAllToolStripMenuItem_Click(object sender, EventArgs e) {
693      treeView.CollapseAll();
694    }
695    private void EditNodeLabelToolStripMenuItem_Click(object sender, EventArgs e) {
696      if (toolStripMenuNode != null) {
697        if (!toolStripMenuNode.IsEditing) toolStripMenuNode.BeginEdit();
698      }
699    }
700
701    private void addButton_Click(object sender, System.EventArgs e) {
702      if (typeSelectorDialog == null) typeSelectorDialog = new TypeSelectorDialog();
703
704      IAlgorithm algorithm = null;
705      if (treeView.SelectedNode != null && (treeView.SelectedNode.Tag is IAlgorithm))
706        algorithm = (IAlgorithm)treeView.SelectedNode.Tag;
707
708      if (algorithm == null) {
709        typeSelectorDialog.Caption = "Select Optimizer";
710        typeSelectorDialog.TypeSelector.Caption = "Available Optimizers";
711        typeSelectorDialog.TypeSelector.Configure(typeof(IOptimizer), false, true);
712      } else {
713        typeSelectorDialog.Caption = "Select Problem";
714        typeSelectorDialog.TypeSelector.Caption = "Available Problems";
715        typeSelectorDialog.TypeSelector.Configure(algorithm.ProblemType, false, true);
716      }
717
718      if (typeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
719        try {
720          if (algorithm == null) {
721            IOptimizer optimizer = (IOptimizer)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
722            if (treeView.SelectedNode == null) Content.Optimizers.Add(optimizer);
723            else {
724              var batchRun = treeView.SelectedNode.Tag as BatchRun;
725              var experiment = treeView.SelectedNode.Tag as Experiment;
726              if (batchRun != null) batchRun.Optimizer = optimizer;
727              else if (experiment != null) experiment.Optimizers.Add(optimizer);
728              else throw new NotSupportedException("Handling for specific type not implemented" + treeView.SelectedNode.Tag.GetType());
729            }
730          } else {
731            IProblem problem = (IProblem)typeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
732            algorithm.Problem = problem;
733          }
734        }
735        catch (Exception ex) {
736          ErrorHandling.ShowErrorDialog(this, ex);
737        }
738      }
739    }
740
741    private void moveUpButton_Click(object sender, EventArgs e) {
742      var optimizer = (IOptimizer)treeView.SelectedNode.Tag;
743      Experiment experiment = null;
744      if (treeView.SelectedNode.Parent == null) experiment = Content;
745      else experiment = (Experiment)treeView.SelectedNode.Parent.Tag;
746
747      var selectedNode = treeView.SelectedNode;
748      int index = treeView.SelectedNode.Index;
749      experiment.Optimizers.Reverse(index - 1, 2);
750      treeView.SelectedNode = selectedNode;
751      SetEnabledStateOfControls();
752    }
753    private void moveDownButton_Click(object sender, EventArgs e) {
754      var optimizer = (IOptimizer)treeView.SelectedNode.Tag;
755      Experiment experiment = null;
756      if (treeView.SelectedNode.Parent == null) experiment = Content;
757      else experiment = (Experiment)treeView.SelectedNode.Parent.Tag;
758
759      var selectedNode = treeView.SelectedNode;
760      int index = treeView.SelectedNode.Index;
761      experiment.Optimizers.Reverse(index, 2);
762      treeView.SelectedNode = selectedNode;
763      SetEnabledStateOfControls();
764    }
765
766    private void removeButton_Click(object sender, EventArgs e) {
767      var treeNode = treeView.SelectedNode;
768      var optimizer = treeNode.Tag as IOptimizer;
769
770      if (treeNode.Parent == null)
771        Content.Optimizers.Remove(optimizer);
772      else {
773        var batchRun = treeNode.Parent.Tag as BatchRun;
774        var experiment = treeNode.Parent.Tag as Experiment;
775        if (batchRun != null) batchRun.Optimizer = null;
776        else if (experiment != null) experiment.Optimizers.Remove(optimizer);
777        else throw new NotSupportedException("Handling for specific type not implemented" + treeView.SelectedNode.Tag.GetType());
778      }
779      SetEnabledStateOfControls();
780      UpdateDetailsViewHost();
781      RebuildImageList();
782    }
783
784    private void showDetailsCheckBox_CheckedChanged(object sender, System.EventArgs e) {
785      if (showDetailsCheckBox.Checked) {
786        splitContainer.Panel2Collapsed = false;
787        detailsGroupBox.Enabled = treeView.SelectedNode != null;
788        detailsViewHost.Content = treeView.SelectedNode != null ? (IContent)treeView.SelectedNode.Tag : null;
789      } else {
790        splitContainer.Panel2Collapsed = true;
791        detailsViewHost.Content = null;
792      }
793    }
794    #endregion
795
796    #region helpers
797    private void UpdateDetailsViewHost() {
798      if (treeView.SelectedNode != null)
799        detailsViewHost.Content = (IContent)treeView.SelectedNode.Tag;
800      else
801        detailsViewHost.Content = null;
802    }
803
804    private TreeNode CreateTreeNode(IOptimizer optimizer) {
805      TreeNode node = new TreeNode(optimizer.ToString());
806      node.Tag = optimizer;
807
808      var algorithm = optimizer as IAlgorithm;
809      if (algorithm != null) {
810        foreach (TreeNode childNode in CreateAlgorithmChildNodes(algorithm))
811          node.Nodes.Add(childNode);
812      }
813
814      List<TreeNode> nodes;
815      if (!treeNodeTagMapping.TryGetValue(optimizer, out nodes)) {
816        nodes = new List<TreeNode>();
817        treeNodeTagMapping.Add(optimizer, nodes);
818        RegisterNamedItemEvents(optimizer);
819      }
820      nodes.Add(node);
821
822      foreach (TreeNode childNode in node.Nodes) {
823        NamedItem namedItem = childNode.Tag as NamedItem;
824        if (namedItem != null) {
825          if (!treeNodeTagMapping.TryGetValue(namedItem, out nodes)) {
826            nodes = new List<TreeNode>();
827            treeNodeTagMapping.Add(namedItem, nodes);
828            RegisterNamedItemEvents(namedItem);
829          }
830          nodes.Add(childNode);
831        }
832      }
833      return node;
834    }
835
836    private IEnumerable<TreeNode> CreateAlgorithmChildNodes(IAlgorithm algorithm) {
837      TreeNode problemNode;
838      if (algorithm.Problem != null) {
839        problemNode = new TreeNode(algorithm.Problem.Name);
840        problemNode.Tag = algorithm.Problem;
841      } else {
842        problemNode = new TreeNode("No Problem");
843        problemNode.Tag = null;
844      }
845      TreeNode parametersNode = new TreeNode("Parameters");
846      parametersNode.Tag = algorithm.Parameters;
847      TreeNode resultsNode = new TreeNode("Results");
848      resultsNode.Tag = algorithm.Results;
849
850      yield return problemNode;
851      yield return parametersNode;
852      yield return resultsNode;
853    }
854
855    private void DisposeTreeNode(TreeNode node) {
856      var namedItem = node.Tag as INamedItem;
857      if (namedItem == null) return;
858
859      List<TreeNode> nodes;
860      if (!treeNodeTagMapping.TryGetValue(namedItem, out nodes))
861        throw new ArgumentException();
862      nodes.Remove(node);
863      if (nodes.Count == 0) {
864        treeNodeTagMapping.Remove(namedItem);
865        DeregisterNamedItemEvents(namedItem);
866      }
867    }
868
869    private IEnumerable<TreeNode> IterateTreeNodes(TreeNode node = null) {
870      TreeNodeCollection nodes;
871      if (node == null)
872        nodes = treeView.Nodes;
873      else {
874        nodes = node.Nodes;
875        yield return node;
876      }
877
878      foreach (var childNode in nodes.OfType<TreeNode>())
879        foreach (var n in IterateTreeNodes(childNode))
880          yield return n;
881    }
882
883    private bool TreeNodeIsFullyExpanded(TreeNode node) {
884      return (node.Nodes.Count == 0) || (node.IsExpanded && node.Nodes.OfType<TreeNode>().All(x => TreeNodeIsFullyExpanded(x)));
885    }
886
887    private void RebuildImageList() {
888      if (InvokeRequired) {
889        Invoke((Action)RebuildImageList);
890        return;
891      }
892
893      treeView.BeginUpdate();
894
895      treeView.ImageList.Images.Clear();
896      var topLevelNodes = treeView.Nodes.OfType<TreeNode>().ToArray();
897      var nodes = IterateTreeNodes().ToList();
898      var selectedNode = treeView.SelectedNode;
899      treeView.Nodes.Clear();
900
901      foreach (TreeNode treeNode in nodes) {
902        var item = (IItem)treeNode.Tag;
903        treeView.ImageList.Images.Add(item == null ? HeuristicLab.Common.Resources.VSImageLibrary.Nothing : item.ItemImage);
904        treeNode.ImageIndex = treeView.ImageList.Images.Count - 1;
905        treeNode.SelectedImageIndex = treeNode.ImageIndex;
906      }
907      treeView.Nodes.AddRange(topLevelNodes);
908      treeView.SelectedNode = selectedNode;
909      treeView.EndUpdate();
910    }
911    #endregion
912
913
914    public sealed class CustomTreeView : System.Windows.Forms.TreeView {
915      protected override void WndProc(ref System.Windows.Forms.Message m) {
916        const int WM_RBUTTONDOWN = 0x204;
917        if (m.Msg == WM_RBUTTONDOWN) {
918          //Raise your custom event right click event to prevent node highlighting
919          OnRightClick();
920          return;
921        }
922        base.WndProc(ref m);
923      }
924
925      public event EventHandler RightClick;
926      private void OnRightClick() {
927        var handler = RightClick;
928        if (handler != null) RightClick(this, EventArgs.Empty);
929      }
930    }
931  }
932}
Note: See TracBrowser for help on using the repository browser.