Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 15978 was 15978, checked in by jzenisek, 6 years ago

#2839: applied several fixes:

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