source: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs @ 15922

Last change on this file since 15922 was 15922, checked in by jzenisek, 16 months ago

#2839:

  • replaced use of TreeView with NoDoubleClickTreeView everywhere allegedly reasonable for Hive
  • updated genealogy computation for HiveAdminClient and corresponding views (ResourcesView & ProjectResourcesView)
File size: 28.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 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.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Collections;
28using HeuristicLab.Common.Resources;
29using HeuristicLab.Core;
30using HeuristicLab.Core.Views;
31using HeuristicLab.MainForm;
32using HeuristicLab.MainForm.WindowsForms;
33
34namespace HeuristicLab.Clients.Hive.JobManager.Views {
35  [View("Hive Project Selector View")]
36  [Content(typeof(IItemList<Project>), true)]
37  public partial class HiveProjectSelector : ItemView, IDisposable {
38    private const int greenFlagImageIndex = 0;
39    private const int redFlagImageIndex = 1;
40    private const int slaveImageIndex = 0;
41    private const int slaveGroupImageIndex = 1;
42    public const string additionalSlavesGroupName = "Additional Slaves";
43    public const string additionalSlavesGroupDescription = "Contains additional slaves which are either ungrouped or the parenting slave group is not assigned to the selected project.";
44
45    private const string CURRENT_SELECTION_TAG = " [current selection]";
46    private const string NEW_SELECTION_TAG = " [new selection]";
47    private const string CHANGED_SELECTION_TAG = " [changed selection]";
48    private const string ADDED_SELECTION_TAG = " [added selection]";
49    private const string REMOVED_SELECTION_TAG = " [removed selection]";
50    private const string INCLUDED_TAG = " [included]";
51    private const string ADDED_INCLUDE_TAG = " [added include]";
52    private const string REMOVED_INCLUDE_TAG = " [removed include]";
53
54    private readonly HashSet<TreeNode> mainTreeNodes = new HashSet<TreeNode>();
55    private readonly HashSet<TreeNode> filteredTreeNodes = new HashSet<TreeNode>();
56    private readonly HashSet<TreeNode> nodeStore = new HashSet<TreeNode>();
57
58    private readonly HashSet<Resource> availableResources = new HashSet<Resource>();
59    private readonly HashSet<Resource> assignedResources = new HashSet<Resource>();
60    private readonly HashSet<Resource> includedResources = new HashSet<Resource>();
61    private readonly HashSet<Resource> newAssignedResources = new HashSet<Resource>();
62    private readonly HashSet<Resource> newIncludedResources = new HashSet<Resource>();
63
64    private readonly Color addedAssignmentColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
65    private readonly Color removedAssignmentColor = Color.FromArgb(255, 236, 159, 72); // #ec9f48
66    private readonly Color addedIncludeColor = Color.FromArgb(25, 169, 221, 221); // #a9dddd
67    private readonly Color removedIncludeColor = Color.FromArgb(25, 249, 210, 145); // #f9d291
68    private readonly Color selectedBackColor = Color.DodgerBlue;
69    private readonly Color selectedForeColor = Color.White;
70    private readonly Color controlTextColor = SystemColors.ControlText;
71    private readonly Color grayTextColor = SystemColors.GrayText;
72
73    private string currentSearchString;
74
75    private void resetHiveResourceSelector() {
76      lastSelectedProject = null;
77      selectedProject = null;
78      projectId = null;
79    }
80
81    private Guid jobId;
82    public Guid JobId {
83      get { return jobId; }
84      set {
85        if (jobId == value) return;
86        jobId = value;
87        resetHiveResourceSelector();
88      }
89    }
90
91    private Guid? projectId;
92    public Guid? ProjectId {
93      get { return projectId; }
94      set {
95        if (projectId == value) return;
96        projectId = value;
97      }
98    }
99
100    private Guid? selectedProjectId;
101    public Guid? SelectedProjectId {
102      get { return selectedProjectId; }
103      set {
104        if (selectedProjectId == value) return;
105        selectedProjectId = value;
106      }
107    }
108
109    private IEnumerable<Guid> selectedResourceIds;
110    public IEnumerable<Guid> SelectedResourceIds {
111      get { return selectedResourceIds; }
112      set {
113        if (selectedResourceIds == value) return;
114        selectedResourceIds = value;
115      }
116    }
117
118    public bool ChangedProjectSelection {
119      get {
120        if ((lastSelectedProject == null && selectedProject != null) 
121          || (lastSelectedProject != null && selectedProject == null)
122          || (lastSelectedProject != null && selectedProject != null && lastSelectedProject.Id != selectedProject.Id))
123          return true;
124        else return false;
125      }
126    }
127
128    public bool ChangedResources {
129      get { return !assignedResources.SetEquals(newAssignedResources); }
130    }
131
132    private Project lastSelectedProject;
133    private Project selectedProject;
134    public Project SelectedProject {
135      get { return selectedProject; }
136      set {
137        if (selectedProject == value) return;
138
139        if ((JobId == Guid.Empty || JobId == null) 
140          && (value == null || SelectedProject == null || value.Id != SelectedProject.Id)) selectedResourceIds = null;
141        lastSelectedProject = selectedProject;
142        selectedProject = value;
143
144        UpdateResourceTree();
145        ExtractStatistics();
146        OnSelectedProjectChanged();
147      }
148    }
149
150    public IEnumerable<Resource> AssignedResources {
151      get { return newAssignedResources; }
152      set {
153        if (newAssignedResources == value) return;
154        newAssignedResources.Clear();
155        foreach(var resource in value) {
156          newAssignedResources.Add(resource);
157        }
158      }
159    }
160
161
162    public new IItemList<Project> Content {
163      get { return (IItemList<Project>)base.Content; }
164      set { base.Content = value; }
165    }
166
167    public HiveProjectSelector() {
168      InitializeComponent();
169
170      projectsImageList.Images.Add(VSImageLibrary.FlagGreen);
171      projectsImageList.Images.Add(VSImageLibrary.FlagRed);
172      resourcesImageList.Images.Add(VSImageLibrary.MonitorLarge);
173      resourcesImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
174    }
175
176    #region Overrides
177    protected override void OnContentChanged() {
178      base.OnContentChanged();
179
180      if (Content != null) {               
181        if (SelectedProjectId.HasValue && SelectedProjectId.Value != Guid.Empty) {
182          SelectedProject = GetSelectedProjectById(SelectedProjectId.Value);
183        } else {
184          SelectedProject = null;
185        }
186        //ExtractStatistics();
187        UpdateProjectTree();
188
189      } else {
190        lastSelectedProject = null;
191        selectedProject = null;
192        selectedProjectId = null;
193        projectsTreeView.Nodes.Clear();
194        resourcesTreeView.Nodes.Clear();
195      }
196    }
197
198    #endregion
199
200    #region Event Handlers
201    private void HiveProjectSelector_Load(object sender, EventArgs e) {
202      projectsTreeView.Nodes.Clear();
203      resourcesTreeView.Nodes.Clear();
204    }
205
206    private void searchTextBox_TextChanged(object sender, EventArgs e) {
207      currentSearchString = searchTextBox.Text.ToLower();
208      //UpdateFilteredTree();
209      UpdateProjectTree();
210    }
211
212    private void projectsTreeView_MouseDoubleClick(object sender, MouseEventArgs e) {
213      OnProjectsTreeViewDoubleClicked();
214    }
215
216    private void projectsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
217      var node = (Project)e.Node.Tag;
218     
219      if (node == null) {
220        projectsTreeView.SelectedNode = null;
221      } else {
222        ResetTreeNodes(projectsTreeView.Nodes);
223        e.Node.BackColor = selectedBackColor;
224        e.Node.ForeColor = selectedForeColor;
225       
226        if(node.Id == projectId) {
227          e.Node.Text += CURRENT_SELECTION_TAG;
228        } else if(projectId == null || projectId == Guid.Empty) {
229          e.Node.Text += NEW_SELECTION_TAG;
230        } else {
231          e.Node.Text += CHANGED_SELECTION_TAG;
232        }
233
234       
235      }
236      SelectedProject = node;
237    }
238
239    private void resourcesTreeView_MouseDown(object sender, MouseEventArgs e) {
240      var node = resourcesTreeView.GetNodeAt(new Point(e.X, e.Y));
241
242      if (node == null) {
243        resourcesTreeView.SelectedNode = null;
244        ExtractStatistics();
245      } else {
246        ExtractStatistics((Resource)node.Tag);
247      }
248    }
249
250    private void resourcesTreeView_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
251      var checkedResource = (Resource)e.Node.Tag;
252      if (newIncludedResources.Contains(checkedResource) || checkedResource.Id == Guid.Empty) {
253        e.Cancel = true;
254        ExtractStatistics((Resource)resourcesTreeView.SelectedNode?.Tag);
255      }
256    }
257
258    private void resourcesTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
259      var checkedResource = (Resource)e.Node.Tag;
260      if (e.Node.Checked) {
261        newAssignedResources.Add(checkedResource);
262      } else {
263        newAssignedResources.Remove(checkedResource);
264      }
265
266      UpdateResourceTreeAfterCheck();
267      ExtractStatistics();
268      OnAssignedResourcesChanged();
269    }
270
271    private void resourcesTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
272      return;
273    }
274    #endregion
275
276    #region Helpers
277
278    private Project GetSelectedProjectById(Guid projectId) {
279      return Content.Where(x => x.Id == projectId).SingleOrDefault();
280    }
281
282    private void UpdateProjectTree() {
283
284      if (string.IsNullOrEmpty(currentSearchString)) {
285        BuildProjectTree(Content);
286      } else {
287        HashSet<Project> filteredProjects = new HashSet<Project>();
288        foreach(var project in Content) {
289          if(project.Name.ToLower().Contains(currentSearchString.ToLower())) {
290            filteredProjects.Add(project);
291            filteredProjects.UnionWith(Content.Where(p => HiveClient.Instance.GetAvailableProjectAncestors(project.Id).Select(x => x.Id).Contains(p.Id)));
292          }
293        }
294        BuildProjectTree(filteredProjects);
295      }
296    }
297
298    private void BuildProjectTree(IEnumerable<Project> projects) {
299      projectsTreeView.Nodes.Clear();
300      if (!projects.Any()) return;
301
302      // select all top level projects (withouth parent, or without any ancestor within current project collection)
303      var mainProjects = new HashSet<Project>(projects.Where(x => x.ParentProjectId == null));
304      var parentedMainProjects = new HashSet<Project>(projects
305        .Where(x => x.ParentProjectId.HasValue
306        && !projects.Select(y => y.Id).Contains(x.ParentProjectId.Value)
307        && !projects.SelectMany(y => HiveClient.Instance.ProjectAncestors[y.Id]).Contains(x.ParentProjectId.Value)));
308      mainProjects.UnionWith(parentedMainProjects);
309      var subProbjects = new HashSet<Project>(projects.Except(mainProjects));
310      foreach(var p in subProbjects) {
311        p.ParentProjectId = HiveClient.Instance.ProjectAncestors[p.Id].Where(x => projects.Select(y => y.Id).Contains(x)).FirstOrDefault();
312      }
313
314      var stack = new Stack<Project>(mainProjects.OrderByDescending(x => x.Name));
315
316      TreeNode currentNode = null;
317      Project currentProject = null;
318
319      while(stack.Any()) {
320        var newProject = stack.Pop();
321        var newNode = new TreeNode(newProject.Name) { Tag = newProject };
322
323        while (currentNode != null && newProject.ParentProjectId != currentProject.Id) {
324          currentNode = currentNode.Parent;
325          currentProject = currentNode == null ? null : (Project)currentNode.Tag;
326        }
327
328        if (currentNode == null) {
329          projectsTreeView.Nodes.Add(newNode);
330          newNode.ImageIndex = greenFlagImageIndex;
331        } else {
332          currentNode.Nodes.Add(newNode);
333          newNode.ImageIndex = redFlagImageIndex;
334        }
335
336        newNode.SelectedImageIndex = newNode.ImageIndex;
337
338        if (SelectedProject != null && SelectedProject.Id.Equals(newProject.Id)) {
339          newNode.BackColor = selectedBackColor;
340          newNode.ForeColor = selectedForeColor;
341          if(SelectedProject.Id == projectId) {
342            newNode.Text += CURRENT_SELECTION_TAG;
343          } else if (projectId == null || projectId == Guid.Empty) {
344            newNode.Text += NEW_SELECTION_TAG;
345          } else {
346            newNode.Text += CHANGED_SELECTION_TAG;
347          }
348        }
349
350        if (!string.IsNullOrEmpty(currentSearchString) && newProject.Name.ToLower().Contains(currentSearchString.ToLower())) {
351          newNode.BackColor = Color.LightBlue;
352        }
353
354        var childProjects = subProbjects.Where(x => x.ParentProjectId == newProject.Id);
355        if (childProjects.Any()) {
356          foreach (var project in childProjects.OrderByDescending(x => x.Name)) {
357            subProbjects.Remove(project);
358            stack.Push(project);
359          }
360          currentNode = newNode;
361          currentProject = newProject;
362        }
363      }
364
365      projectsTreeView.ExpandAll();
366    }
367
368    private static IEnumerable<Resource> GetAssignedResourcesForProject(Guid projectId) {
369      var assignedProjectResources = HiveServiceLocator.Instance.CallHiveService(s => s.GetAssignedResourcesForProject(projectId));
370      return HiveClient.Instance.Resources.Where(x => assignedProjectResources.Select(y => y.ResourceId).Contains(x.Id));
371    }
372
373    private static IEnumerable<Resource> GetAssignedResourcesForJob(Guid jobId) {
374      var assignedJobResources = HiveServiceLocator.Instance.CallHiveService(s => s.GetAssignedResourcesForJob(jobId));
375      return HiveClient.Instance.Resources.Where(x => assignedJobResources.Select(y => y.ResourceId).Contains(x.Id));
376    }
377
378    private void UpdateResourceTree() {
379      UpdateAvailableResources();
380      UpdateAssignedResources();
381      UpdateIncludedResources();
382      BuildResourceTree(availableResources);
383    }
384
385    private void UpdateResourceTreeAfterCheck() {
386      resourcesTreeView.BeforeCheck -= resourcesTreeView_BeforeCheck;
387      resourcesTreeView.AfterCheck -= resourcesTreeView_AfterCheck;
388      UpdateNewAssignedResources();
389      UpdateNewIncludedResources();
390      SetTreeNodes(resourcesTreeView.Nodes);
391      resourcesTreeView.BeforeCheck += resourcesTreeView_BeforeCheck;
392      resourcesTreeView.AfterCheck += resourcesTreeView_AfterCheck;
393    }
394
395    private void UpdateAvailableResources() {
396      availableResources.Clear();
397      if (selectedProject != null) {
398        var assignedProjectResources = GetAssignedResourcesForProject(selectedProject.Id);
399        foreach (var resource in assignedProjectResources) {
400          availableResources.Add(resource);
401          foreach(var descendant in HiveClient.Instance.Resources.Where(x => HiveClient.Instance.ResourceDescendants[resource.Id].Contains(x.Id))) {
402            availableResources.Add(descendant);
403          }
404        }
405      }
406      //ExtractStatistics();
407      //OnAssignedResourcesChanged();
408    }
409
410    private void UpdateAssignedResources() {
411      assignedResources.Clear();
412      newAssignedResources.Clear();
413
414      if (JobId == Guid.Empty || JobId == null) { // new, unchanged jobs get all avaialable resources
415        // update new assigned resources
416        if(selectedResourceIds == null) {
417          foreach (var resource in availableResources
418            .Where(x => !x.ParentResourceId.HasValue
419            || !availableResources.Select(y => y.Id).Contains(x.ParentResourceId.Value))) {
420            newAssignedResources.Add(resource);
421          }
422        } else {
423          foreach(var resource in availableResources.Where(x => selectedResourceIds.Contains(x.Id))) {
424            newAssignedResources.Add(resource);
425          }
426        }
427      } else { // existent, unchanged jobs get all assigned resources
428        // update assigned resources
429        var assignedJobResources = GetAssignedResourcesForJob(JobId);
430        foreach (var resource in assignedJobResources) {
431          assignedResources.Add(resource);
432          if (selectedResourceIds == null) {
433            newAssignedResources.Add(resource);
434          }
435        }
436
437        if(selectedResourceIds != null) {
438          foreach (var resource in availableResources.Where(x => selectedResourceIds.Contains(x.Id))) {
439            newAssignedResources.Add(resource);
440          }
441        }
442      }
443
444      //ExtractStatistics();
445      OnAssignedResourcesChanged();
446    }
447
448    private void UpdateNewAssignedResources() {
449      for(int i = newAssignedResources.Count-1; i>=0; i--) {
450        if(newAssignedResources.Intersect(HiveClient.Instance.GetAvailableResourceAncestors(newAssignedResources.ElementAt(i).Id)).Any()) {
451          newAssignedResources.Remove(newAssignedResources.ElementAt(i));
452        }
453      }
454    }
455
456    private void UpdateIncludedResources() {
457      includedResources.Clear();
458      newIncludedResources.Clear();
459
460      if (JobId != Guid.Empty) {
461        foreach (var item in assignedResources) {
462          foreach (var descendant in HiveClient.Instance.GetAvailableResourceDescendants(item.Id)) {
463            includedResources.Add(descendant);
464          }
465        }
466      }
467
468      foreach (var item in newAssignedResources) {
469        foreach (var descendant in HiveClient.Instance.GetAvailableResourceDescendants(item.Id)) {
470          newIncludedResources.Add(descendant);
471        }
472      }
473    }
474
475    private void UpdateNewIncludedResources() {
476      newIncludedResources.Clear();
477      foreach (var item in newAssignedResources) {
478        foreach (var descendant in HiveClient.Instance.GetAvailableResourceDescendants(item.Id)) {
479          newIncludedResources.Add(descendant);
480        }
481      }
482    }
483
484    private void BuildResourceTree(IEnumerable<Resource> resources) {
485      resourcesTreeView.Nodes.Clear();
486      if (!resources.Any()) return;
487
488      resourcesTreeView.BeforeCheck -= resourcesTreeView_BeforeCheck;
489      resourcesTreeView.AfterCheck -= resourcesTreeView_AfterCheck;
490
491      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>().Where(x => x.ParentResourceId == null));
492      var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
493        .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
494      mainResources.UnionWith(parentedMainResources);
495      var subResources = new HashSet<Resource>(resources.Except(mainResources));
496
497      var addedAssignments = newAssignedResources.Except(assignedResources);
498      var removedAssignments = assignedResources.Except(newAssignedResources);
499      var addedIncludes = newIncludedResources.Except(includedResources);
500      var removedIncludes = includedResources.Except(newIncludedResources);
501
502      TreeNode currentNode = null;
503      Resource currentResource = null;
504
505      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
506
507      while (stack.Any()) {
508        var newResource = stack.Pop();
509        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
510
511        // search for parent node of newNode and save in currentNode
512        // necessary since newNodes (stack top items) might be siblings
513        // or grand..grandparents of previous node (currentNode)
514        while (currentNode != null && newResource.ParentResourceId != currentResource.Id) {
515          currentNode = currentNode.Parent;
516          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
517        }
518
519        if (currentNode == null) {
520          resourcesTreeView.Nodes.Add(newNode);
521        } else {
522          currentNode.Nodes.Add(newNode);
523        }
524
525        if (newAssignedResources.Select(x => x.Id).Contains(newResource.Id)) {
526          newNode.Checked = true;
527        } else if (newIncludedResources.Select(x => x.Id).Contains(newResource.Id)) {
528          newNode.Checked = true;
529          newNode.ForeColor = grayTextColor;
530        }
531
532        if (includedResources.Select(x => x.Id).Contains(newResource.Id) && newIncludedResources.Select(x => x.Id).Contains(newResource.Id)) {
533          newNode.Text += INCLUDED_TAG;
534        } else if (addedIncludes.Select(x => x.Id).Contains(newResource.Id)) {
535          newNode.BackColor = addedIncludeColor;
536          newNode.ForeColor = grayTextColor;
537          newNode.Text += ADDED_INCLUDE_TAG;
538        } else if (removedIncludes.Select(x => x.Id).Contains(newResource.Id)) {
539          newNode.BackColor = removedIncludeColor;
540          newNode.Text += REMOVED_INCLUDE_TAG;
541        }
542
543        if (addedAssignments.Select(x => x.Id).Contains(newResource.Id)) {
544          newNode.BackColor = addedAssignmentColor;
545          newNode.ForeColor = controlTextColor;
546          newNode.Text += ADDED_SELECTION_TAG;
547        } else if (removedAssignments.Select(x => x.Id).Contains(newResource.Id)) {
548          newNode.BackColor = removedAssignmentColor;
549          newNode.ForeColor = controlTextColor;
550          newNode.Text += REMOVED_SELECTION_TAG;
551        }
552
553        if (newResource is Slave) {
554          newNode.ImageIndex = slaveImageIndex;
555        } else {
556          newNode.ImageIndex = slaveGroupImageIndex;
557
558          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
559          if (childResources.Any()) {
560            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
561              subResources.Remove(resource);
562              stack.Push(resource);
563            }
564            currentNode = newNode;
565            currentResource = newResource;
566          }
567        }
568        newNode.SelectedImageIndex = newNode.ImageIndex;
569      }
570
571      var singleSlaves = subResources.OfType<Slave>();
572      if (singleSlaves.Any()) {
573
574        var additionalNode = new TreeNode(additionalSlavesGroupName) {
575          ForeColor = SystemColors.GrayText,
576          Tag = new SlaveGroup() {
577            Name = additionalSlavesGroupName,
578            Description = additionalSlavesGroupDescription
579          }
580        };
581
582        foreach (var slave in singleSlaves.OrderBy(x => x.Name)) {
583          var slaveNode = new TreeNode(slave.Name) { Tag = slave };
584          additionalNode.Nodes.Add(slaveNode);
585        }
586
587        resourcesTreeView.Nodes.Add(additionalNode);
588      }
589
590      ExpandResourceNodesOfInterest(resourcesTreeView.Nodes);
591
592      resourcesTreeView.BeforeCheck += resourcesTreeView_BeforeCheck;
593      resourcesTreeView.AfterCheck += resourcesTreeView_AfterCheck;
594    }
595
596    private void ExpandResourceNodesOfInterest(TreeNodeCollection nodes) {
597      foreach(TreeNode n in nodes) {
598        Resource r = (Resource)n.Tag;
599        if(n.Nodes.Count > 0) {
600          if(HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()
601            || HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<Slave>().Intersect(assignedResources.Union(newAssignedResources)).Any()) {
602            n.Expand();
603            ExpandResourceNodesOfInterest(n.Nodes);
604          } else {
605            n.Collapse();
606          }   
607        } else {
608          n.Collapse();
609        }
610      }
611    }
612
613    private void CollapseSlaveOnlyNodes(TreeNode tn) {
614      if (!(tn.Tag is Resource)) return;
615
616      Resource r = (Resource)tn.Tag;
617      if (HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()) {
618        tn.Expand();
619        foreach (TreeNode n in tn.Nodes) CollapseSlaveOnlyNodes(n);
620      } else {
621        tn.Collapse();
622      }
623    }
624
625    private void ExtractStatistics(Resource resource = null) { 
626      HashSet<Slave> newAssignedSlaves = new HashSet<Slave>(newAssignedResources.OfType<Slave>());
627      foreach (var slaveGroup in newAssignedResources.OfType<SlaveGroup>()) {
628        foreach (var slave in HiveClient.Instance.GetAvailableResourceDescendants(slaveGroup.Id).OfType<Slave>()) {
629          newAssignedSlaves.Add(slave);
630        }
631      }
632
633      HashSet<Slave> selectedSlaves = null;
634
635      if (resource != null) {
636        var slaveGroup = resource as SlaveGroup;
637        if (slaveGroup != null) {
638          selectedSlaves = new HashSet<Slave>(HiveClient.Instance.GetAvailableResourceDescendants(slaveGroup.Id).OfType<Slave>());
639        } else {
640          selectedSlaves = new HashSet<Slave>(new[] { resource as Slave });
641        }
642      } else {
643        selectedSlaves = newAssignedSlaves;
644      }
645
646      int sumCores = selectedSlaves.Sum(x => x.Cores.GetValueOrDefault());
647      int sumFreeCores = selectedSlaves.Sum(x => x.FreeCores.GetValueOrDefault());
648      double sumMemory = selectedSlaves.Sum(x => x.Memory.GetValueOrDefault()) / 1024.0;
649      double sumFreeMemory = selectedSlaves.Sum(x => x.FreeMemory.GetValueOrDefault()) / 1024.0;
650
651      coresSummaryLabel.Text = $"{sumCores} Total ({sumFreeCores} Free / {sumCores - sumFreeCores} Used)";
652      memorySummaryLabel.Text = $"{sumMemory:0.00} GB Total ({sumFreeMemory:0.00} GB Free / {(sumMemory - sumFreeMemory):0.00} GB Used)";
653    }
654
655    private void StyleTreeNode(TreeNode n, string name) {
656      n.Text = name;
657      n.BackColor = Color.Transparent;
658      n.ForeColor = Color.Black;
659    }
660
661    private void ResetTreeNodes(TreeNodeCollection nodes) {
662      foreach (TreeNode n in nodes) {
663        string name = "";
664        if (n.Tag is Project) name = ((Project)n.Tag).Name;
665        else if (n.Tag is Resource) name = ((Resource)n.Tag).Name;
666        StyleTreeNode(n, name);
667        if (n.Nodes.Count > 0) {
668          ResetTreeNodes(n.Nodes);
669        }
670      }
671    }
672
673    private void SetTreeNodes(TreeNodeCollection nodes) {
674      var addedAssignments = newAssignedResources.Except(assignedResources);
675      var removedAssignments = assignedResources.Except(newAssignedResources);
676      var addedIncludes = newIncludedResources.Except(includedResources);
677      var removedIncludes = includedResources.Except(newIncludedResources);
678
679      foreach (TreeNode n in nodes) {
680
681        if(n.Tag is Resource) {
682          // reset
683          var resource = (Resource)n.Tag;
684          n.Text = resource.Name;
685          n.BackColor = Color.Transparent;
686          n.ForeColor = Color.Black;
687          n.Checked = false;
688
689          // add additional info
690          if (newAssignedResources.Select(x => x.Id).Contains(resource.Id)) {
691            n.Checked = true;
692          } else if (newIncludedResources.Select(x => x.Id).Contains(resource.Id)) {
693            n.Checked = true;
694            n.ForeColor = grayTextColor;
695          }
696
697          if (includedResources.Select(x => x.Id).Contains(resource.Id) && newIncludedResources.Select(x => x.Id).Contains(resource.Id)) {
698            n.Text += INCLUDED_TAG;
699          } else if (addedIncludes.Select(x => x.Id).Contains(resource.Id)) {
700            n.BackColor = addedIncludeColor;
701            n.ForeColor = grayTextColor;
702            n.Text += ADDED_INCLUDE_TAG;
703          } else if (removedIncludes.Select(x => x.Id).Contains(resource.Id)) {
704            n.BackColor = removedIncludeColor;
705            n.Text += REMOVED_INCLUDE_TAG;
706          }
707
708          if (addedAssignments.Select(x => x.Id).Contains(resource.Id)) {
709            n.BackColor = addedAssignmentColor;
710            n.ForeColor = controlTextColor;
711            n.Text += ADDED_SELECTION_TAG;
712          } else if (removedAssignments.Select(x => x.Id).Contains(resource.Id)) {
713            n.BackColor = removedAssignmentColor;
714            n.ForeColor = controlTextColor;
715            n.Text += REMOVED_SELECTION_TAG;
716          }
717        }
718
719        if(n.Nodes.Count > 0) {
720          SetTreeNodes(n.Nodes);
721        }
722      }
723    }
724
725    #endregion
726
727    #region Events
728    public event EventHandler SelectedProjectChanged;
729    private void OnSelectedProjectChanged() {
730      SelectedProjectChanged?.Invoke(this, EventArgs.Empty);
731    }
732
733    public event EventHandler AssignedResourcesChanged;
734    private void OnAssignedResourcesChanged() {
735      AssignedResourcesChanged?.Invoke(this, EventArgs.Empty);
736    }
737
738    public event EventHandler ProjectsTreeViewDoubleClicked;
739    private void OnProjectsTreeViewDoubleClicked() {
740      ProjectsTreeViewDoubleClicked?.Invoke(this, EventArgs.Empty);
741    }
742    #endregion
743  }
744}
Note: See TracBrowser for help on using the repository browser.