source: branches/HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs @ 15658

Last change on this file since 15658 was 15658, checked in by jzenisek, 3 years ago

#2839

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