Free cookie consent management tool by TermsFeed Policy Generator

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

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

Fixed exception that was thrown when changing the name of a benchmark algorithm by pressing F2 in the ExperimentTreeView (#1740)

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          INamedItem namedItem = childNode.Tag as INamedItem;
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 = (INamedItem)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        INamedItem namedItem = childNode.Tag as INamedItem;
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.