source: trunk/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs

Last change on this file was 17180, checked in by swagner, 12 months ago

#2875: Removed years in copyrights

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