source: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs @ 15995

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

#2839: adapted illustration of project and resource ancestry in HiveAdministrator and HiveJobAdministrator

File size: 27.0 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 || Locked || ReadOnly || !IsAdmin();
120      bool scheduleLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty);
121      bool addLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty) || selectedResource is Slave;
122
123      btnAddGroup.Enabled = !addLocked;
124      btnRemoveGroup.Enabled = !locked;
125      btnSave.Enabled = !locked;
126      viewHost.Enabled = true;
127      //viewHost.Locked = locked;
128      viewHost.Locked = false;
129      viewHost.ReadOnly = false;
130      scheduleView.Locked = locked;
131      //scheduleView.SetEnabledStateOfSchedule(!scheduleLocked);
132    }
133    #endregion
134
135    #region Event Handlers
136    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
137      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsAdded, sender, e);
138      else {
139        OnContentChanged();
140      }
141    }
142
143    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
144      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsRemoved, sender, e);
145      else {
146        OnContentChanged();
147      }
148    }
149
150    private void SlaveViewContent_PropertyChanged(object sender, PropertyChangedEventArgs e) {
151      if (InvokeRequired) Invoke((Action<object, PropertyChangedEventArgs>)SlaveViewContent_PropertyChanged, sender, e);
152      else {
153        OnContentChanged();
154        if (e.PropertyName == "HbInterval") {
155          UpdateChildHbIntervall((Resource)viewHost.Content);
156        }
157      }
158    }
159
160    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
161      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
162      else {
163        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
164        mainForm.AddOperationProgressToView(this, "Refreshing ...");
165        SetEnabledStateOfControls();
166      }
167    }
168
169    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
170      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
171      else {
172        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
173        mainForm.RemoveOperationProgressFromView(this);
174        SetEnabledStateOfControls();
175      }
176    }
177
178    private void AccessClient_Instance_Refreshing(object sender, EventArgs e) {
179      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshing, sender, e);
180      else {
181        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
182        mainForm.AddOperationProgressToView(this, "Refreshing ...");
183        SetEnabledStateOfControls();
184      }
185    }
186
187    private void AccessClient_Instance_Refreshed(object sender, EventArgs e) {
188      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshed, sender, e);
189      else {
190        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
191        mainForm.RemoveOperationProgressFromView(this);
192        SetEnabledStateOfControls();
193      }
194    }
195
196    private async void ResourcesView_Load(object sender, EventArgs e) {
197      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
198        action: () => UpdateResources());
199    }
200
201    private async void btnRefresh_Click(object sender, EventArgs e) {
202      lock (locker) {
203        if (!btnRefresh.Enabled) return;
204        btnRefresh.Enabled = false;
205      }
206
207      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
208        action: () => UpdateResources(),
209        finallyCallback: () => btnRefresh.Enabled = true);
210    }
211
212    private void btnAddGroup_Click(object sender, EventArgs e) {
213      Guid? parentResourceId = null;
214      if(!IsAdmin()) {
215        MessageBox.Show(
216          "You have no permission to add a resource group.",
217          "HeuristicLab Hive Administrator",
218          MessageBoxButtons.OK,
219          MessageBoxIcon.Information);
220        return;
221      } else if(selectedResource != null && selectedResource.Id == Guid.Empty) {
222        MessageBox.Show(
223          "You cannot add a resource group to a not yet stored group.",
224          "HeuristicLab Hive Administrator",
225          MessageBoxButtons.OK,
226          MessageBoxIcon.Information);
227        return;
228      }
229     
230      if (selectedResource != null && selectedResource is SlaveGroup) parentResourceId = selectedResource.Id;
231      var group = new SlaveGroup {
232        Name = "New Group",
233        OwnerUserId = UserInformation.Instance.User.Id,
234        ParentResourceId = parentResourceId
235      };
236
237      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
238      SelectedResource = group;
239      Content.Add(group);
240    }
241
242    private async void btnRemoveGroup_Click(object sender, EventArgs e) {
243      if (selectedResource == null) return;
244
245      lock (locker) {
246        if (!btnRemoveGroup.Enabled) return;
247        btnRemoveGroup.Enabled = false;
248      }
249
250      if (!IsAdmin()) {
251        MessageBox.Show(
252          "You have no permission to delete resources.",
253          "HeuristicLab Hive Administrator",
254          MessageBoxButtons.OK,
255          MessageBoxIcon.Information);
256        return;
257      }
258
259      if (Content.Any(x => x.ParentResourceId == selectedResource.Id)) {
260        MessageBox.Show(
261          "Only empty resources can be deleted.",
262          "HeuristicLab Hive Administrator",
263          MessageBoxButtons.OK,
264          MessageBoxIcon.Error);
265        return;
266      }
267
268      var result = MessageBox.Show(
269        "Do you really want to delete " + selectedResource.Name + "?",
270        "HeuristicLab Hive Administrator",
271        MessageBoxButtons.YesNo,
272        MessageBoxIcon.Question);
273      if (result == DialogResult.Yes) {
274        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
275          action: () => {
276            RemoveResource(selectedResource);
277          },
278          finallyCallback: () => {
279            btnRemoveGroup.Enabled = true;
280          });
281      }
282    }
283
284    private async void btnSave_Click(object sender, EventArgs e) {
285      lock (locker) {
286        if (!btnSave.Enabled) return;
287        btnSave.Enabled = false;
288      }
289
290      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
291        action: () => {
292          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
293          foreach (var resource in resourcesToSave)
294            resource.Store();
295          UpdateResources();
296        },
297        finallyCallback: () => btnSave.Enabled = true);
298
299      OnContentChanged();
300    }
301
302    private void treeSlaveGroup_MouseDown(object sender, MouseEventArgs e) {
303      var node = treeView.GetNodeAt(e.Location);
304      if (node == null || node == ungroupedGroupNode) return;
305      var r = (Resource)node.Tag;
306      if(!HiveAdminClient.Instance.DisabledParentResources.Contains(r)) ChangeSelectedResourceNode(node);
307    }
308
309    private void treeSlaveGroup_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
310      e.Cancel = true;
311    }
312
313    private void treeSlaveGroup_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
314      if(e.Node == ungroupedGroupNode) {
315        e.Cancel = true;
316      } else {
317        var r = (Resource)e.Node.Tag;
318        if(HiveAdminClient.Instance.DisabledParentResources.Contains(r)) {
319          e.Cancel = true;
320        }
321      }
322    }
323
324    private void treeSlaveGroup_DragDrop(object sender, DragEventArgs e) {
325      if (e.Effect == DragDropEffects.None) return;
326
327      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
328      var targetResource = (targetNode != null) ? (Resource)targetNode.Tag : null;
329      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
330
331      foreach(var r in resources) {
332        r.ParentResourceId = targetResource?.Id;
333      }
334
335      // TODO
336      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
337      OnContentChanged();
338    }
339
340    private void treeSlaveGroup_ItemDrag(object sender, ItemDragEventArgs e) {
341      if (!IsAdmin()) return;
342
343      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
344      TreeNode sourceNode = (TreeNode)e.Item;
345      if(!sourceNode.Checked) nodes.Add(sourceNode);
346      nodes.Remove(ungroupedGroupNode);
347      ungroupedGroupNode.Checked = false;
348      var resources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
349
350      if(resources.Count > 0) {
351        DataObject data = new DataObject();
352        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, resources);
353        var action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
354        if(action.HasFlag(DragDropEffects.Move)) {
355          foreach (var node in nodes) node.Remove();
356          StyleTreeNode(ungroupedGroupNode, (Resource)ungroupedGroupNode.Tag, resources);
357        }
358      }
359    }
360
361    private IEnumerable<TreeNode> GetCheckedNodes(TreeNodeCollection nodes) {
362      if (nodes != null) {
363        foreach (var node in nodes.OfType<TreeNode>()) {
364          if (node.Checked && node != ungroupedGroupNode) yield return node;
365            foreach (var child in GetCheckedNodes(node.Nodes))
366              yield return child;
367          }
368      }
369    }
370
371    private void treeSlaveGroup_DragEnterOver(object sender, DragEventArgs e) {
372      e.Effect = DragDropEffects.Move;
373      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
374      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
375      var targetResource = targetNode?.Tag as Resource;
376
377      if(!IsAdmin()
378        || resources == null
379        || !resources.Any()
380        || resources.Any(x => !HiveAdminClient.Instance.CheckParentChange(x, targetResource))
381        || (targetNode != null && (targetNode == ungroupedGroupNode || targetNode.Parent == ungroupedGroupNode))) {
382        e.Effect = DragDropEffects.None;
383      }
384    }
385
386    private void TabSlaveGroup_TabIndexChanged(object sender, EventArgs e) {
387      throw new NotImplementedException();
388    }
389
390    private async void TabSlaveGroup_Selected(object sender, System.Windows.Forms.TabControlEventArgs e) {
391      if(e.TabPage == tabSchedule) {
392        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
393          action: () => UpdateSchedule(),
394          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
395      }
396      SetEnabledStateOfControls();
397    }
398    #endregion
399
400    #region Helpers
401    private void BuildResourceTree(IEnumerable<Resource> resources) {
402      treeView.Nodes.Clear();
403      if (!resources.Any()) return;
404
405      var disabledParentResources = HiveAdminClient.Instance.DisabledParentResources;
406      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
407        .Where(x => x.ParentResourceId == null));
408      //var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
409      //  .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
410      //mainResources.UnionWith(parentedMainResources);
411      var mainDisabledParentResources = new HashSet<Resource>(disabledParentResources.Where(x => x.ParentResourceId == null || x.ParentResourceId == Guid.Empty));
412      mainResources.UnionWith(mainDisabledParentResources);
413      var subResources = new HashSet<Resource>(resources.Union(disabledParentResources).Except(mainResources).OrderByDescending(x => x.Name));
414
415      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
416      if (selectedResource != null) SelectedResource = resources.Where(x => x.Id == selectedResource.Id).FirstOrDefault();
417      bool nodeSelected = false;
418
419      TreeNode currentNode = null;
420      Resource currentResource = null;
421
422      while (stack.Any()) {
423        var newResource = stack.Pop();
424        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
425        StyleTreeNode(newNode, newResource, resources);
426
427        if (selectedResource == null && !disabledParentResources.Contains(newResource)) {
428          SelectedResource = newResource;
429        }
430        if (!nodeSelected && selectedResource != null && newResource.Id == selectedResource.Id) {
431          newNode.BackColor = selectedBackColor;
432          newNode.ForeColor = selectedForeColor;
433          newNode.Text += SELECTED_TAG;
434          nodeSelected = true;
435        }
436
437        if(disabledParentResources.Contains(newResource)) {
438          newNode.Checked = false;
439          newNode.ForeColor = grayTextColor;
440        }
441
442        // search for parent node of newNode and save in currentNode
443        // necessary since newNodes (stack top items) might be siblings
444        // or grand..grandparents of previous node (currentNode)
445        while (currentNode != null && newResource.ParentResourceId != currentResource.Id) {
446          currentNode = currentNode.Parent;
447          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
448        }
449
450        if (currentNode == null) {
451          treeView.Nodes.Add(newNode);
452        } else {
453          currentNode.Nodes.Add(newNode);
454        }
455
456        if (newResource is SlaveGroup) {
457          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
458          if (childResources.Any()) {
459            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
460              subResources.Remove(resource);
461              stack.Push(resource);
462            }
463            currentNode = newNode;
464            currentResource = newResource;
465          }
466        }
467        newNode.SelectedImageIndex = newNode.ImageIndex;
468      }
469
470      // collapse slave-only nodes
471      foreach(TreeNode n in treeView.Nodes) {
472        CollapseSlaveOnlyNodes(n);
473      }
474     
475      ungroupedGroupNode = new TreeNode(UNGROUPED_GROUP_NAME) {
476        ForeColor = SystemColors.GrayText,
477        Tag = new SlaveGroup() {
478          Name = UNGROUPED_GROUP_NAME,
479          Description = UNGROUPED_GROUP_DESCRIPTION
480        }
481      };
482
483      foreach (var slave in subResources.OfType<Slave>().OrderBy(x => x.Name)) {
484        var slaveNode = new TreeNode(slave.Name) { Tag = slave };
485        StyleTreeNode(slaveNode, slave, resources);
486        ungroupedGroupNode.Nodes.Add(slaveNode);
487        if (selectedResource == null) {
488          SelectedResource = slave;
489        }
490
491        if (slave.Id == selectedResource.Id && !nodeSelected) {
492          slaveNode.BackColor = selectedBackColor;
493          slaveNode.ForeColor = selectedForeColor;
494          slaveNode.Text += SELECTED_TAG;
495          nodeSelected = true;
496        }
497      }
498
499      if (ungroupedGroupNode.Nodes.Count > 0) {
500        ungroupedGroupNode.Text += " [" + ungroupedGroupNode.Nodes.Count.ToString() + "]";
501        ungroupedGroupNode.Expand();
502      }
503      treeView.Nodes.Add(ungroupedGroupNode);     
504    }
505
506    private void CollapseSlaveOnlyNodes(TreeNode tn) {
507      Resource r = (Resource)tn.Tag;
508      var descendants = GetResourceDescendants();
509      if(descendants.ContainsKey(r.Id)) {
510        if(descendants[r.Id].OfType<SlaveGroup>().Any()) {
511          tn.Expand();
512          foreach (TreeNode n in tn.Nodes) CollapseSlaveOnlyNodes(n);
513        } else {
514          tn.Collapse();
515        }
516      }
517    }
518
519    private void ExpandResourceNodesOfInterest(TreeNodeCollection nodes) {
520      foreach (TreeNode n in nodes) {
521        Resource r = (Resource)n.Tag;
522        if (n.Nodes.Count > 0) {
523          if (HiveAdminClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()) {
524            n.Expand();
525            ExpandResourceNodesOfInterest(n.Nodes);
526          } else {
527            n.Collapse();
528          }
529        } else {
530          n.Collapse();
531        }
532      }
533    }
534
535    private void UpdateChildHbIntervall(Resource resource) {
536      foreach (Resource r in Content.Where(x => x.ParentResourceId == resource.Id)) {
537        r.HbInterval = resource.HbInterval;
538        if (r is SlaveGroup) {
539          UpdateChildHbIntervall(r);
540        }
541      }
542    }
543
544    private void UpdateResources() {
545      try {
546        HiveAdminClient.Instance.Refresh();
547        Content = HiveAdminClient.Instance.Resources;
548      } catch(AnonymousUserException) {
549        ShowHiveInformationDialog();
550      }
551    }
552
553    private void RemoveResource(Resource resource) {
554      if (resource == null) return;
555
556      try {
557        if (resource.Id != Guid.Empty) {
558          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
559          foreach (var r in resourcesToSave)
560            r.Store();
561          HiveAdminClient.Delete(resource);
562          UpdateResources();
563        } else {
564          Content.Remove(selectedResource);
565        }
566      } catch(AnonymousUserException) {
567        ShowHiveInformationDialog();
568      }
569    }
570
571    private void UpdateSchedule() {
572      try {
573        HiveAdminClient.Instance.RefreshCalendar();
574      } catch (AnonymousUserException) {
575        ShowHiveInformationDialog();
576      }
577    }
578
579    private bool IsAdmin() {
580      return HiveRoles.CheckAdminUserPermissions();
581    }
582
583    private void StyleTreeNode(TreeNode n, Resource r, IEnumerable<Resource> resources) {
584      n.Text = r.Name;
585      n.BackColor = Color.Transparent;
586      n.ForeColor = Color.Black;
587
588      if(HiveAdminClient.Instance.DisabledParentResources.Select(x => x.Id).Contains(r.Id)) {
589        n.ForeColor = grayTextColor;
590      } else if (r.Id == Guid.Empty && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
591        // not stored (i.e. new)
592        n.Text += NOT_STORED_TAG;
593      } else if (r.Modified && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
594        // changed
595        n.Text += CHANGES_NOT_STORED_TAG;
596      }
597
598      // slave count
599      int childSlavesCount = 0;
600      if (r.Id != Guid.Empty && r is SlaveGroup) {
601        var descendants = GetResourceDescendants();
602        if (descendants.ContainsKey(r.Id)) {
603          childSlavesCount = resources
604            .OfType<Slave>()
605            .Where(x => descendants[r.Id].Select(y => y.Id)
606              .Contains(x.Id))
607            .Count();
608        }
609      } else if(n == ungroupedGroupNode /*|| r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
610        childSlavesCount = resources
611          .OfType<Slave>()
612          .Where(x => x.ParentResourceId == null
613            || (x.ParentResourceId.HasValue && x.ParentResourceId.Value == Guid.Empty))
614          .Count();
615      }
616      if (childSlavesCount > 0)
617        n.Text += " [" + childSlavesCount.ToString() + "]";
618
619      // slave image index, state, utilization
620      if (r is Slave) {
621        n.ImageIndex = slaveImageIndex;
622        var s = r as Slave;
623        if (s.SlaveState == SlaveState.Calculating) {
624          n.ForeColor = calculatingColor;
625          n.Text += " [" + s.CpuUtilization.ToString("N2") + "%]";
626        } else if (s.SlaveState == SlaveState.Offline) {
627          n.ForeColor = offlineColor;
628          if (s.LastHeartbeat.HasValue)
629            n.Text += " [" + s.LastHeartbeat?.ToString("g") + "]";
630        }
631      } else {
632        n.ImageIndex = slaveGroupImageIndex;
633      }
634
635      // ungrouped
636      if(n == ungroupedGroupNode /*r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
637        n.ForeColor = ForeColor = SystemColors.GrayText;
638      }
639    }
640
641    private void ResetTreeNodes(TreeNodeCollection nodes, IEnumerable<Resource> resources) {
642      foreach (TreeNode n in nodes) {
643        StyleTreeNode(n, (Resource)n.Tag, resources);
644        if (n.Nodes.Count > 0) {
645          ResetTreeNodes(n.Nodes, resources);
646        }
647      }
648    }
649
650    private async void ChangeSelectedResource(Resource resource) {
651      selectedResource = resource;
652      viewHost.Content = selectedResource;
653
654      HiveAdminClient.Instance.DowntimeForResourceId = selectedResource != null ? selectedResource.Id : Guid.Empty;
655      if (tabSlaveGroup.SelectedTab == tabSchedule) {
656        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
657          action: () => UpdateSchedule(),
658          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
659      }
660
661      SetEnabledStateOfControls();
662    }
663
664    private void ChangeSelectedResourceNode(TreeNode resourceNode) {
665      if (resourceNode == null) return;
666      SelectedResource = (Resource)resourceNode.Tag;
667      ResetTreeNodes(treeView.Nodes, Content);
668      resourceNode.BackColor = selectedBackColor;
669      resourceNode.ForeColor = selectedForeColor;
670      resourceNode.Text += SELECTED_TAG;
671    }
672
673    private void ShowHiveInformationDialog() {
674      if (InvokeRequired) Invoke((Action)ShowHiveInformationDialog);
675      else {
676        using (HiveInformationDialog dialog = new HiveInformationDialog()) {
677          dialog.ShowDialog(this);
678        }
679      }
680    }
681
682    private void ResetView() {
683      if (InvokeRequired) Invoke((Action)ResetView);
684      else {
685        treeView.Nodes.Clear();
686
687        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
688          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
689        }
690
691        viewHost.Content = null;
692        if (scheduleView.Content != null) {
693          scheduleView.Content.Clear();
694        }
695
696        HiveAdminClient.Instance.ResetDowntime();
697      }
698    }
699
700
701    private Dictionary<Guid, HashSet<Resource>> GetResourceDescendants() {
702      var resourceDescendants = new Dictionary<Guid, HashSet<Resource>>();
703      var resources = Content.Union(HiveAdminClient.Instance.DisabledParentResources).ToList();
704
705      foreach (var r in resources) resourceDescendants.Add(r.Id, new HashSet<Resource>());
706      foreach(var r in resources) {
707        var parentResourceId = r.ParentResourceId;
708        while(parentResourceId != null) {
709          var parent = resources.SingleOrDefault(x => x.Id == parentResourceId);
710          if(parent != null) {
711            resourceDescendants[parent.Id].Add(r);
712            parentResourceId = parent.ParentResourceId;
713          } else {
714            parentResourceId = null;
715          }
716        }
717      }
718      return resourceDescendants;
719    }
720   
721    #endregion
722  }
723}
Note: See TracBrowser for help on using the repository browser.