source: trunk/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs @ 16117

Last change on this file since 16117 was 16117, checked in by jkarder, 2 years ago

#2839: merged [15377-16116/branches/2839_HiveProjectManagement] into trunk

File size: 27.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Clients.Access;
29using HeuristicLab.Clients.Hive.Views;
30using HeuristicLab.Collections;
31using HeuristicLab.Common.Resources;
32using HeuristicLab.Core;
33using HeuristicLab.Core.Views;
34using HeuristicLab.MainForm;
35
36namespace HeuristicLab.Clients.Hive.Administrator.Views {
37  [View("Resources View")]
38  [Content(typeof(IItemList<Resource>), false)]
39  public partial class ResourcesView : ItemView, IDisposable {
40    private const int slaveImageIndex = 0;
41    private const int slaveGroupImageIndex = 1;
42    public const string UNGROUPED_GROUP_NAME = "UNGROUPED";
43    public const string UNGROUPED_GROUP_DESCRIPTION = "Contains slaves that are not assigned to any group.";
44    private const string SELECTED_TAG = ""; // " [selected]";
45    private const string NOT_STORED_TAG = "*"; // " [not stored]";
46    private const string CHANGES_NOT_STORED_TAG = "*"; // " [changes not stored]";
47
48    private readonly Color changedColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
49    private readonly Color selectedBackColor = Color.DodgerBlue;
50    private readonly Color selectedForeColor = Color.White;
51    private readonly Color calculatingColor = Color.FromArgb(255, 58, 114, 35); // #3a7223
52    private readonly Color offlineColor = Color.FromArgb(255, 187, 36, 36); // #bb2424
53    private readonly Color grayTextColor = SystemColors.GrayText;
54
55
56
57    private TreeNode ungroupedGroupNode;
58
59    private Resource selectedResource = null;
60    public Resource SelectedResource {
61      get { return selectedResource; }
62      set { if (selectedResource != value) ChangeSelectedResource(value); }
63    }
64
65    private readonly object locker = new object();
66
67    public new IItemList<Resource> Content {
68      get { return (IItemList<Resource>)base.Content; }
69      set { base.Content = value; }
70    }
71
72    public ResourcesView() {
73      InitializeComponent();
74
75      treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge);
76      treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
77
78      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
79      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
80      AccessClient.Instance.Refreshing += AccessClient_Instance_Refreshing;
81      AccessClient.Instance.Refreshed += AccessClient_Instance_Refreshed;
82    }
83
84    #region Overrides
85    protected override void OnClosing(FormClosingEventArgs e) {
86      AccessClient.Instance.Refreshed -= AccessClient_Instance_Refreshed;
87      AccessClient.Instance.Refreshing -= AccessClient_Instance_Refreshing;
88      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
89      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
90      base.OnClosing(e);
91    }
92
93    protected override void RegisterContentEvents() {
94      base.RegisterContentEvents();
95      Content.ItemsAdded += Content_ItemsAdded;
96      Content.ItemsRemoved += Content_ItemsRemoved;
97    }
98
99    protected override void DeregisterContentEvents() {
100      Content.ItemsRemoved -= Content_ItemsRemoved;
101      Content.ItemsAdded -= Content_ItemsAdded;
102      base.DeregisterContentEvents();
103    }
104
105    protected override void OnContentChanged() {
106      base.OnContentChanged();
107      if (Content == null) {
108        treeView.Nodes.Clear();
109        viewHost.Content = null;
110        scheduleView.Content = null;
111      } else {
112        BuildResourceTree(Content);
113      }
114    }
115
116    protected override void SetEnabledStateOfControls() {
117      base.SetEnabledStateOfControls();
118
119      bool locked = Content == null || selectedResource == null || Locked || ReadOnly;
120      bool adminLocked = locked || !IsAdmin();
121      bool addLocked = adminLocked || selectedResource.Id == Guid.Empty || selectedResource is Slave;
122      bool deleteLocked = adminLocked || HiveAdminClient.Instance.ResourceDescendants[selectedResource.Id].Any();
123
124      btnAddGroup.Enabled = !addLocked;
125      btnRemoveGroup.Enabled = !deleteLocked;
126      btnSave.Enabled = !locked;
127      scheduleView.Locked = adminLocked;
128    }
129    #endregion
130
131    #region Event Handlers
132    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
133      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsAdded, sender, e);
134      else {
135        OnContentChanged();
136      }
137    }
138
139    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
140      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsRemoved, sender, e);
141      else {
142        OnContentChanged();
143      }
144    }
145
146    private void SlaveViewContent_PropertyChanged(object sender, PropertyChangedEventArgs e) {
147      if (InvokeRequired) Invoke((Action<object, PropertyChangedEventArgs>)SlaveViewContent_PropertyChanged, sender, e);
148      else {
149        OnContentChanged();
150        if (e.PropertyName == "HbInterval") {
151          UpdateChildHbIntervall((Resource)viewHost.Content);
152        }
153      }
154    }
155
156    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
157      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
158      else {
159        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
160        mainForm.AddOperationProgressToView(this, "Refreshing ...");
161        SetEnabledStateOfControls();
162      }
163    }
164
165    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
166      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
167      else {
168        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
169        mainForm.RemoveOperationProgressFromView(this);
170        SetEnabledStateOfControls();
171      }
172    }
173
174    private void AccessClient_Instance_Refreshing(object sender, EventArgs e) {
175      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshing, sender, e);
176      else {
177        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
178        mainForm.AddOperationProgressToView(this, "Refreshing ...");
179        SetEnabledStateOfControls();
180      }
181    }
182
183    private void AccessClient_Instance_Refreshed(object sender, EventArgs e) {
184      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshed, sender, e);
185      else {
186        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
187        mainForm.RemoveOperationProgressFromView(this);
188        SetEnabledStateOfControls();
189      }
190    }
191
192    private async void ResourcesView_Load(object sender, EventArgs e) {
193      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
194        action: () => UpdateResources());
195    }
196
197    private async void btnRefresh_Click(object sender, EventArgs e) {
198      lock (locker) {
199        if (!btnRefresh.Enabled) return;
200        btnRefresh.Enabled = false;
201      }
202
203      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
204        action: () => UpdateResources(),
205        finallyCallback: () => btnRefresh.Enabled = true);
206    }
207
208    private void btnAddGroup_Click(object sender, EventArgs e) {
209      Guid? parentResourceId = null;
210      if (!IsAdmin()) {
211        MessageBox.Show(
212          "You have no permission to add a resource group.",
213          "HeuristicLab Hive Administrator",
214          MessageBoxButtons.OK,
215          MessageBoxIcon.Information);
216        return;
217      } else if (selectedResource != null && selectedResource.Id == Guid.Empty) {
218        MessageBox.Show(
219          "You cannot add a resource group to a not yet stored group.",
220          "HeuristicLab Hive Administrator",
221          MessageBoxButtons.OK,
222          MessageBoxIcon.Information);
223        return;
224      }
225
226      if (selectedResource != null && selectedResource is SlaveGroup) {
227        parentResourceId = selectedResource.Id;
228      } else {
229        MessageBox.Show(
230          "You cannot add a resource group to a slave.",
231          "HeuristicLab Hive Administrator",
232          MessageBoxButtons.OK,
233          MessageBoxIcon.Information);
234        return;
235      }
236
237      var group = new SlaveGroup {
238        Name = "New Group",
239        OwnerUserId = UserInformation.Instance.User.Id,
240        ParentResourceId = parentResourceId
241      };
242
243      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
244      SelectedResource = group;
245      Content.Add(group);
246    }
247
248    private async void btnRemoveGroup_Click(object sender, EventArgs e) {
249      if (selectedResource == null) return;
250
251      lock (locker) {
252        if (!btnRemoveGroup.Enabled) return;
253        btnRemoveGroup.Enabled = false;
254      }
255
256      if (!IsAdmin()) {
257        MessageBox.Show(
258          "You have no permission to delete resource groups.",
259          "HeuristicLab Hive Administrator",
260          MessageBoxButtons.OK,
261          MessageBoxIcon.Information);
262        return;
263      }
264
265      if (Content.Any(x => x.ParentResourceId == selectedResource.Id)) {
266        MessageBox.Show(
267          "Only empty resource groups can be deleted.",
268          "HeuristicLab Hive Administrator",
269          MessageBoxButtons.OK,
270          MessageBoxIcon.Error);
271        return;
272      }
273
274      var result = MessageBox.Show(
275        "Do you really want to delete " + selectedResource.Name + "?",
276        "HeuristicLab Hive Administrator",
277        MessageBoxButtons.YesNo,
278        MessageBoxIcon.Question);
279      if (result == DialogResult.Yes) {
280        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
281          action: () => {
282            RemoveResource(selectedResource);
283          },
284          finallyCallback: () => {
285            btnRemoveGroup.Enabled = true;
286          });
287      } else {
288        btnRemoveGroup.Enabled = true;
289      }
290    }
291
292    private async void btnSave_Click(object sender, EventArgs e) {
293      lock (locker) {
294        if (!btnSave.Enabled) return;
295        btnSave.Enabled = false;
296      }
297
298      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
299        action: () => {
300          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
301          foreach (var resource in resourcesToSave)
302            resource.Store();
303          UpdateResources();
304        },
305        finallyCallback: () => btnSave.Enabled = true);
306
307      OnContentChanged();
308    }
309
310    private void treeSlaveGroup_MouseDown(object sender, MouseEventArgs e) {
311      var node = treeView.GetNodeAt(e.Location);
312      if (node == null || node == ungroupedGroupNode) return;
313      var r = (Resource)node.Tag;
314      if (!HiveAdminClient.Instance.DisabledParentResources.Contains(r)) ChangeSelectedResourceNode(node);
315    }
316
317    private void treeSlaveGroup_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
318      e.Cancel = true;
319    }
320
321    private void treeSlaveGroup_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
322      if (e.Node == ungroupedGroupNode) {
323        e.Cancel = true;
324      } else {
325        var r = (Resource)e.Node.Tag;
326        if (HiveAdminClient.Instance.DisabledParentResources.Contains(r)) {
327          e.Cancel = true;
328        }
329      }
330    }
331
332    private void treeSlaveGroup_DragDrop(object sender, DragEventArgs e) {
333      if (e.Effect == DragDropEffects.None) return;
334
335      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
336      var targetResource = (targetNode != null) ? (Resource)targetNode.Tag : null;
337      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
338
339      foreach (var r in resources) {
340        r.ParentResourceId = targetResource != null ? targetResource.Id : (Guid?)null;
341      }
342
343      // TODO
344      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
345      OnContentChanged();
346    }
347
348    private void treeSlaveGroup_ItemDrag(object sender, ItemDragEventArgs e) {
349      if (!IsAdmin()) return;
350
351      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
352      TreeNode sourceNode = (TreeNode)e.Item;
353      if (!sourceNode.Checked) nodes.Add(sourceNode);
354      nodes.Remove(ungroupedGroupNode);
355      ungroupedGroupNode.Checked = false;
356      var resources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
357
358      if (resources.Count > 0) {
359        DataObject data = new DataObject();
360        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, resources);
361        var action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
362        if (action.HasFlag(DragDropEffects.Move)) {
363          foreach (var node in nodes) node.Remove();
364          StyleTreeNode(ungroupedGroupNode, (Resource)ungroupedGroupNode.Tag, resources);
365        }
366      }
367    }
368
369    private IEnumerable<TreeNode> GetCheckedNodes(TreeNodeCollection nodes) {
370      if (nodes != null) {
371        foreach (var node in nodes.OfType<TreeNode>()) {
372          if (node.Checked && node != ungroupedGroupNode) yield return node;
373          foreach (var child in GetCheckedNodes(node.Nodes))
374            yield return child;
375        }
376      }
377    }
378
379    private void treeSlaveGroup_DragEnterOver(object sender, DragEventArgs e) {
380      e.Effect = DragDropEffects.Move;
381      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
382      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
383      var targetResource = (targetNode != null ? targetNode.Tag : null) as Resource;
384
385      if (!IsAdmin()
386        || resources == null
387        || !resources.Any()
388        || resources.Any(x => !HiveAdminClient.Instance.CheckParentChange(x, targetResource))
389        || (targetNode != null && (targetNode == ungroupedGroupNode || targetNode.Parent == ungroupedGroupNode))) {
390        e.Effect = DragDropEffects.None;
391      }
392    }
393
394    private void TabSlaveGroup_TabIndexChanged(object sender, EventArgs e) {
395      throw new NotImplementedException();
396    }
397
398    private async void TabSlaveGroup_Selected(object sender, System.Windows.Forms.TabControlEventArgs e) {
399      if (e.TabPage == tabSchedule) {
400        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
401          action: () => UpdateSchedule(),
402          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
403      }
404      SetEnabledStateOfControls();
405    }
406    #endregion
407
408    #region Helpers
409    private void BuildResourceTree(IEnumerable<Resource> resources) {
410      treeView.Nodes.Clear();
411      if (!resources.Any()) return;
412
413      var disabledParentResources = HiveAdminClient.Instance.DisabledParentResources;
414      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
415        .Where(x => x.ParentResourceId == null));
416      //var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
417      //  .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
418      //mainResources.UnionWith(parentedMainResources);
419      var mainDisabledParentResources = new HashSet<Resource>(disabledParentResources.Where(x => x.ParentResourceId == null || x.ParentResourceId == Guid.Empty));
420      mainResources.UnionWith(mainDisabledParentResources);
421      var subResources = new HashSet<Resource>(resources.Union(disabledParentResources).Except(mainResources).OrderByDescending(x => x.Name));
422
423      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
424      if (selectedResource != null) SelectedResource = resources.Where(x => x.Id == selectedResource.Id).FirstOrDefault();
425      bool nodeSelected = false;
426
427      TreeNode currentNode = null;
428      Resource currentResource = null;
429
430      while (stack.Any()) {
431        var newResource = stack.Pop();
432        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
433        StyleTreeNode(newNode, newResource, resources);
434
435        if (selectedResource == null && !disabledParentResources.Contains(newResource)) {
436          SelectedResource = newResource;
437        }
438        if (!nodeSelected && selectedResource != null && newResource.Id == selectedResource.Id) {
439          newNode.BackColor = selectedBackColor;
440          newNode.ForeColor = selectedForeColor;
441          newNode.Text += SELECTED_TAG;
442          nodeSelected = true;
443        }
444
445        if (disabledParentResources.Contains(newResource)) {
446          newNode.Checked = false;
447          newNode.ForeColor = grayTextColor;
448        }
449
450        // search for parent node of newNode and save in currentNode
451        // necessary since newNodes (stack top items) might be siblings
452        // or grand..grandparents of previous node (currentNode)
453        while (currentNode != null && newResource.ParentResourceId != currentResource.Id) {
454          currentNode = currentNode.Parent;
455          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
456        }
457
458        if (currentNode == null) {
459          treeView.Nodes.Add(newNode);
460        } else {
461          currentNode.Nodes.Add(newNode);
462        }
463
464        if (newResource is SlaveGroup) {
465          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
466          if (childResources.Any()) {
467            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
468              subResources.Remove(resource);
469              stack.Push(resource);
470            }
471            currentNode = newNode;
472            currentResource = newResource;
473          }
474        }
475        newNode.SelectedImageIndex = newNode.ImageIndex;
476      }
477
478      // collapse slave-only nodes
479      foreach (TreeNode n in treeView.Nodes) {
480        CollapseSlaveOnlyNodes(n);
481      }
482
483      ungroupedGroupNode = new TreeNode(UNGROUPED_GROUP_NAME) {
484        ForeColor = SystemColors.GrayText,
485        Tag = new SlaveGroup() {
486          Name = UNGROUPED_GROUP_NAME,
487          Description = UNGROUPED_GROUP_DESCRIPTION
488        }
489      };
490
491      foreach (var slave in subResources.OfType<Slave>().OrderBy(x => x.Name)) {
492        var slaveNode = new TreeNode(slave.Name) { Tag = slave };
493        StyleTreeNode(slaveNode, slave, resources);
494        ungroupedGroupNode.Nodes.Add(slaveNode);
495        if (selectedResource == null) {
496          SelectedResource = slave;
497        }
498
499        if (slave.Id == selectedResource.Id && !nodeSelected) {
500          slaveNode.BackColor = selectedBackColor;
501          slaveNode.ForeColor = selectedForeColor;
502          slaveNode.Text += SELECTED_TAG;
503          nodeSelected = true;
504        }
505      }
506
507      if (ungroupedGroupNode.Nodes.Count > 0) {
508        ungroupedGroupNode.Text += " [" + ungroupedGroupNode.Nodes.Count.ToString() + "]";
509        ungroupedGroupNode.Expand();
510      }
511      treeView.Nodes.Add(ungroupedGroupNode);
512    }
513
514    private void CollapseSlaveOnlyNodes(TreeNode tn) {
515      Resource r = (Resource)tn.Tag;
516      var descendants = GetResourceDescendants();
517      if (descendants.ContainsKey(r.Id)) {
518        if (descendants[r.Id].OfType<SlaveGroup>().Any()) {
519          tn.Expand();
520          foreach (TreeNode n in tn.Nodes) CollapseSlaveOnlyNodes(n);
521        } else {
522          tn.Collapse();
523        }
524      }
525    }
526
527    private void ExpandResourceNodesOfInterest(TreeNodeCollection nodes) {
528      foreach (TreeNode n in nodes) {
529        Resource r = (Resource)n.Tag;
530        if (n.Nodes.Count > 0) {
531          if (HiveAdminClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()) {
532            n.Expand();
533            ExpandResourceNodesOfInterest(n.Nodes);
534          } else {
535            n.Collapse();
536          }
537        } else {
538          n.Collapse();
539        }
540      }
541    }
542
543    private void UpdateChildHbIntervall(Resource resource) {
544      foreach (Resource r in Content.Where(x => x.ParentResourceId == resource.Id)) {
545        r.HbInterval = resource.HbInterval;
546        if (r is SlaveGroup) {
547          UpdateChildHbIntervall(r);
548        }
549      }
550    }
551
552    private void UpdateResources() {
553      try {
554        HiveAdminClient.Instance.Refresh();
555        Content = HiveAdminClient.Instance.Resources;
556      } catch (AnonymousUserException) {
557        ShowHiveInformationDialog();
558      }
559    }
560
561    private void RemoveResource(Resource resource) {
562      if (resource == null) return;
563
564      try {
565        if (resource.Id != Guid.Empty) {
566          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
567          foreach (var r in resourcesToSave)
568            r.Store();
569
570          SelectedResource = HiveAdminClient.Instance.GetAvailableResourceAncestors(resource.Id).LastOrDefault();
571          HiveAdminClient.Delete(resource);
572          UpdateResources();
573        } else {
574          Content.Remove(selectedResource);
575        }
576      } catch (AnonymousUserException) {
577        ShowHiveInformationDialog();
578      }
579    }
580
581    private void UpdateSchedule() {
582      try {
583        HiveAdminClient.Instance.RefreshCalendar();
584      } catch (AnonymousUserException) {
585        ShowHiveInformationDialog();
586      }
587    }
588
589    private bool IsAdmin() {
590      return HiveRoles.CheckAdminUserPermissions();
591    }
592
593    private void StyleTreeNode(TreeNode n, Resource r, IEnumerable<Resource> resources) {
594      n.Text = r.Name;
595      n.BackColor = Color.Transparent;
596      n.ForeColor = Color.Black;
597
598      if (HiveAdminClient.Instance.DisabledParentResources.Select(x => x.Id).Contains(r.Id)) {
599        n.ForeColor = grayTextColor;
600      } else if (r.Id == Guid.Empty && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
601        // not stored (i.e. new)
602        n.Text += NOT_STORED_TAG;
603      } else if (r.Modified && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
604        // changed
605        n.Text += CHANGES_NOT_STORED_TAG;
606      }
607
608      // slave count
609      int childSlavesCount = 0;
610      if (r.Id != Guid.Empty && r is SlaveGroup) {
611        var descendants = GetResourceDescendants();
612        if (descendants.ContainsKey(r.Id)) {
613          childSlavesCount = resources
614            .OfType<Slave>()
615            .Where(x => descendants[r.Id].Select(y => y.Id)
616              .Contains(x.Id))
617            .Count();
618        }
619      } else if (n == ungroupedGroupNode /*|| r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
620        childSlavesCount = resources
621          .OfType<Slave>()
622          .Where(x => x.ParentResourceId == null
623            || (x.ParentResourceId.HasValue && x.ParentResourceId.Value == Guid.Empty))
624          .Count();
625      }
626      if (childSlavesCount > 0)
627        n.Text += " [" + childSlavesCount.ToString() + "]";
628
629      // slave image index, state, utilization
630      if (r is Slave) {
631        n.ImageIndex = slaveImageIndex;
632        var s = r as Slave;
633        if (s.SlaveState == SlaveState.Calculating) {
634          n.ForeColor = calculatingColor;
635          n.Text += " [" + s.CpuUtilization.ToString("N2") + "%]";
636        } else if (s.SlaveState == SlaveState.Offline) {
637          n.ForeColor = offlineColor;
638          if (s.LastHeartbeat.HasValue)
639            n.Text += " [" + (s.LastHeartbeat != null ? s.LastHeartbeat.Value.ToString("g") : null) + "]";
640        }
641      } else {
642        n.ImageIndex = slaveGroupImageIndex;
643      }
644
645      // ungrouped
646      if (n == ungroupedGroupNode /*r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
647        n.ForeColor = SystemColors.GrayText;
648      }
649    }
650
651    private void ResetTreeNodes(TreeNodeCollection nodes, IEnumerable<Resource> resources) {
652      foreach (TreeNode n in nodes) {
653        StyleTreeNode(n, (Resource)n.Tag, resources);
654        if (n.Nodes.Count > 0) {
655          ResetTreeNodes(n.Nodes, resources);
656        }
657      }
658    }
659
660    private async void ChangeSelectedResource(Resource resource) {
661      selectedResource = resource;
662      viewHost.Content = selectedResource;
663
664      HiveAdminClient.Instance.DowntimeForResourceId = selectedResource != null ? selectedResource.Id : Guid.Empty;
665      if (tabSlaveGroup.SelectedTab == tabSchedule) {
666        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
667          action: () => UpdateSchedule(),
668          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
669      }
670
671      SetEnabledStateOfControls();
672    }
673
674    private void ChangeSelectedResourceNode(TreeNode resourceNode) {
675      if (resourceNode == null) return;
676      SelectedResource = (Resource)resourceNode.Tag;
677      ResetTreeNodes(treeView.Nodes, Content);
678      resourceNode.BackColor = selectedBackColor;
679      resourceNode.ForeColor = selectedForeColor;
680      resourceNode.Text += SELECTED_TAG;
681    }
682
683    private void ShowHiveInformationDialog() {
684      if (InvokeRequired) Invoke((Action)ShowHiveInformationDialog);
685      else {
686        using (HiveInformationDialog dialog = new HiveInformationDialog()) {
687          dialog.ShowDialog(this);
688        }
689      }
690    }
691
692    private void ResetView() {
693      if (InvokeRequired) Invoke((Action)ResetView);
694      else {
695        treeView.Nodes.Clear();
696
697        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
698          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
699        }
700
701        viewHost.Content = null;
702        if (scheduleView.Content != null) {
703          scheduleView.Content.Clear();
704        }
705
706        HiveAdminClient.Instance.ResetDowntime();
707      }
708    }
709
710
711    private Dictionary<Guid, HashSet<Resource>> GetResourceDescendants() {
712      var resourceDescendants = new Dictionary<Guid, HashSet<Resource>>();
713      var resources = Content.Union(HiveAdminClient.Instance.DisabledParentResources).ToList();
714
715      foreach (var r in resources) resourceDescendants.Add(r.Id, new HashSet<Resource>());
716      foreach (var r in resources) {
717        var parentResourceId = r.ParentResourceId;
718        while (parentResourceId != null) {
719          var parent = resources.SingleOrDefault(x => x.Id == parentResourceId);
720          if (parent != null) {
721            resourceDescendants[parent.Id].Add(r);
722            parentResourceId = parent.ParentResourceId;
723          } else {
724            parentResourceId = null;
725          }
726        }
727      }
728      return resourceDescendants;
729    }
730
731    #endregion
732  }
733}
Note: See TracBrowser for help on using the repository browser.