Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs @ 17060

Last change on this file since 17060 was 17060, checked in by mkommend, 5 years ago

#2839: Merged r16427 into stable.

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