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

Last change on this file since 15922 was 15922, checked in by jzenisek, 16 months ago

#2839:

  • replaced use of TreeView with NoDoubleClickTreeView everywhere allegedly reasonable for Hive
  • updated genealogy computation for HiveAdminClient and corresponding views (ResourcesView & ProjectResourcesView)
File size: 25.7 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
54
55
56    private TreeNode ungroupedGroupNode;
57
58    private Resource selectedResource = null;
59    public Resource SelectedResource {
60      get { return selectedResource; }
61      set { if (selectedResource != value) ChangeSelectedResource(value); }
62    }
63
64    private readonly object locker = new object();
65
66    public new IItemList<Resource> Content {
67      get { return (IItemList<Resource>)base.Content; }
68      set { base.Content = value; }
69    }
70
71    public ResourcesView() {
72      InitializeComponent();
73
74      treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge);
75      treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
76
77      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
78      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
79      AccessClient.Instance.Refreshing += AccessClient_Instance_Refreshing;
80      AccessClient.Instance.Refreshed += AccessClient_Instance_Refreshed;
81    }
82
83    #region Overrides
84    protected override void OnClosing(FormClosingEventArgs e) {
85      AccessClient.Instance.Refreshed -= AccessClient_Instance_Refreshed;
86      AccessClient.Instance.Refreshing -= AccessClient_Instance_Refreshing;
87      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
88      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
89      base.OnClosing(e);
90    }
91
92    protected override void RegisterContentEvents() {
93      base.RegisterContentEvents();
94      Content.ItemsAdded += Content_ItemsAdded;
95      Content.ItemsRemoved += Content_ItemsRemoved;
96    }
97
98    protected override void DeregisterContentEvents() {
99      Content.ItemsRemoved -= Content_ItemsRemoved;
100      Content.ItemsAdded -= Content_ItemsAdded;
101      base.DeregisterContentEvents();
102    }
103
104    protected override void OnContentChanged() {
105      base.OnContentChanged();
106      if (Content == null) {
107        treeView.Nodes.Clear();
108        viewHost.Content = null;
109        scheduleView.Content = null;
110      } else {
111        BuildResourceTree(Content);
112      }
113    }
114
115    protected override void SetEnabledStateOfControls() {
116      base.SetEnabledStateOfControls();
117
118      bool locked = Content == null || Locked || ReadOnly || !IsAdmin();
119      bool scheduleLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty);
120      bool addLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty) || selectedResource is Slave;
121
122      btnAddGroup.Enabled = !addLocked;
123      btnRemoveGroup.Enabled = !locked;
124      btnSave.Enabled = !locked;
125      viewHost.Locked = locked;
126      scheduleView.Locked = locked;
127      scheduleView.SetEnabledStateOfSchedule(!scheduleLocked);
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) parentResourceId = selectedResource.Id;
227      var group = new SlaveGroup {
228        Name = "New Group",
229        OwnerUserId = UserInformation.Instance.User.Id,
230        ParentResourceId = parentResourceId
231      };
232
233      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
234      SelectedResource = group;
235      Content.Add(group);
236    }
237
238    private async void btnRemoveGroup_Click(object sender, EventArgs e) {
239      if (selectedResource == null) return;
240
241      lock (locker) {
242        if (!btnRemoveGroup.Enabled) return;
243        btnRemoveGroup.Enabled = false;
244      }
245
246      if (!IsAdmin()) {
247        MessageBox.Show(
248          "You have no permission to delete resources.",
249          "HeuristicLab Hive Administrator",
250          MessageBoxButtons.OK,
251          MessageBoxIcon.Information);
252        return;
253      }
254
255      if (Content.Any(x => x.ParentResourceId == selectedResource.Id)) {
256        MessageBox.Show(
257          "Only empty resources can be deleted.",
258          "HeuristicLab Hive Administrator",
259          MessageBoxButtons.OK,
260          MessageBoxIcon.Error);
261        return;
262      }
263
264      var result = MessageBox.Show(
265        "Do you really want to delete " + selectedResource.Name + "?",
266        "HeuristicLab Hive Administrator",
267        MessageBoxButtons.YesNo,
268        MessageBoxIcon.Question);
269      if (result == DialogResult.Yes) {
270        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
271          action: () => {
272            RemoveResource(selectedResource);
273          },
274          finallyCallback: () => { 
275            btnRemoveGroup.Enabled = true;
276          });
277      } 
278    }
279
280    private async void btnSave_Click(object sender, EventArgs e) {
281      lock (locker) {
282        if (!btnSave.Enabled) return;
283        btnSave.Enabled = false;
284      }
285
286      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
287        action: () => {
288          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
289          foreach (var resource in resourcesToSave)
290            resource.Store();
291          UpdateResources();
292        },
293        finallyCallback: () => btnSave.Enabled = true);
294
295      OnContentChanged();
296    }
297
298    private void treeSlaveGroup_MouseDown(object sender, MouseEventArgs e) {
299      var node = treeView.GetNodeAt(e.Location);
300      if(node != null && node != ungroupedGroupNode) ChangeSelectedResourceNode(node);
301    }
302
303    private void treeSlaveGroup_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
304      e.Cancel = true;
305    }
306
307    private void treeSlaveGroup_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
308      if(e.Node == ungroupedGroupNode) {
309        e.Cancel = true;
310      }
311    }
312
313    private void treeSlaveGroup_DragDrop(object sender, DragEventArgs e) {
314      if (e.Effect == DragDropEffects.None) return;
315
316      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
317      var targetResource = (targetNode != null) ? (Resource)targetNode.Tag : null;
318      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
319
320      foreach(var r in resources) {
321        r.ParentResourceId = targetResource?.Id;
322      }
323
324      // TODO
325      //HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
326      OnContentChanged();
327    }
328
329    private void treeSlaveGroup_ItemDrag(object sender, ItemDragEventArgs e) {
330      if (!IsAdmin()) return;
331
332      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
333      TreeNode sourceNode = (TreeNode)e.Item;
334      if(!sourceNode.Checked) nodes.Add(sourceNode);
335      nodes.Remove(ungroupedGroupNode);
336      ungroupedGroupNode.Checked = false;
337      var resources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
338
339      if(resources.Count > 0) {
340        DataObject data = new DataObject();
341        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, resources);
342        var action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
343        if(action.HasFlag(DragDropEffects.Move)) {
344          foreach (var node in nodes) node.Remove();
345          StyleTreeNode(ungroupedGroupNode, (Resource)ungroupedGroupNode.Tag, resources);
346        }
347      }
348    }
349
350    private IEnumerable<TreeNode> GetCheckedNodes(TreeNodeCollection nodes) {
351      if (nodes != null) {
352        foreach (var node in nodes.OfType<TreeNode>()) {
353          if (node.Checked && node != ungroupedGroupNode) yield return node;
354            foreach (var child in GetCheckedNodes(node.Nodes))
355              yield return child;
356          }
357      }
358    }
359
360    private void treeSlaveGroup_DragEnterOver(object sender, DragEventArgs e) {
361      e.Effect = DragDropEffects.Move;
362      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
363      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
364      var targetResource = targetNode?.Tag as Resource;
365
366      if(!IsAdmin() 
367        || resources == null
368        || !resources.Any()
369        || resources.Any(x => !HiveAdminClient.Instance.CheckParentChange(x, targetResource))
370        || (targetNode != null && (targetNode == ungroupedGroupNode || targetNode.Parent == ungroupedGroupNode))) {
371        e.Effect = DragDropEffects.None;
372      }
373    }
374
375    private void TabSlaveGroup_TabIndexChanged(object sender, EventArgs e) {
376      throw new NotImplementedException();
377    }
378
379    private async void TabSlaveGroup_Selected(object sender, System.Windows.Forms.TabControlEventArgs e) {
380      if(e.TabPage == tabSchedule) {
381        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
382          action: () => UpdateSchedule(),
383          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
384      }
385      SetEnabledStateOfControls();
386    }
387    #endregion
388
389    #region Helpers
390    private void BuildResourceTree(IEnumerable<Resource> resources) {
391      treeView.Nodes.Clear();
392      if (!resources.Any()) return;
393
394      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
395        .Where(x => x.ParentResourceId == null));
396      var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
397        .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
398      mainResources.UnionWith(parentedMainResources);
399      var subResources = new HashSet<Resource>(resources.Except(mainResources).OrderByDescending(x => x.Name));
400
401      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
402      if (selectedResource != null) SelectedResource = resources.Where(x => x.Id == selectedResource.Id).FirstOrDefault();
403      bool nodeSelected = false;
404
405      TreeNode currentNode = null;
406      Resource currentResource = null;
407
408      while (stack.Any()) {
409        var newResource = stack.Pop();
410        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
411        StyleTreeNode(newNode, newResource, resources);
412
413        if (selectedResource == null) {
414          SelectedResource = newResource;
415        }
416        if (newResource.Id == selectedResource.Id && !nodeSelected) {
417          newNode.BackColor = selectedBackColor;
418          newNode.ForeColor = selectedForeColor;
419          newNode.Text += SELECTED_TAG;
420          nodeSelected = true;
421        }
422
423        // search for parent node of newNode and save in currentNode
424        // necessary since newNodes (stack top items) might be siblings
425        // or grand..grandparents of previous node (currentNode)
426        while (currentNode != null && newResource.ParentResourceId != currentResource.Id) {
427          currentNode = currentNode.Parent;
428          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
429        }
430
431        if (currentNode == null) {
432          treeView.Nodes.Add(newNode);
433        } else {
434          currentNode.Nodes.Add(newNode);
435        }
436
437        if (newResource is SlaveGroup) {
438          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
439          if (childResources.Any()) {
440            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
441              subResources.Remove(resource);
442              stack.Push(resource);
443            }
444            currentNode = newNode;
445            currentResource = newResource;
446          }
447        }
448        newNode.SelectedImageIndex = newNode.ImageIndex;
449      }
450
451      // collapse slave-only nodes
452      foreach(TreeNode n in treeView.Nodes) {
453        CollapseSlaveOnlyNodes(n);
454      }
455     
456      ungroupedGroupNode = new TreeNode(UNGROUPED_GROUP_NAME) {
457        ForeColor = SystemColors.GrayText,
458        Tag = new SlaveGroup() {
459          Name = UNGROUPED_GROUP_NAME,
460          Description = UNGROUPED_GROUP_DESCRIPTION
461        }
462      };
463
464      foreach (var slave in subResources.OfType<Slave>().OrderBy(x => x.Name)) {
465        var slaveNode = new TreeNode(slave.Name) { Tag = slave };
466        StyleTreeNode(slaveNode, slave, resources);
467        ungroupedGroupNode.Nodes.Add(slaveNode);
468        if (selectedResource == null) {
469          SelectedResource = slave;
470        }
471
472        if (slave.Id == selectedResource.Id && !nodeSelected) {
473          slaveNode.BackColor = selectedBackColor;
474          slaveNode.ForeColor = selectedForeColor;
475          slaveNode.Text += SELECTED_TAG;
476          nodeSelected = true;
477        }
478      }
479
480      if (ungroupedGroupNode.Nodes.Count > 0) {
481        ungroupedGroupNode.Text += " [" + ungroupedGroupNode.Nodes.Count.ToString() + "]";
482        ungroupedGroupNode.Expand();
483      }
484      treeView.Nodes.Add(ungroupedGroupNode);     
485    }
486
487    private void CollapseSlaveOnlyNodes(TreeNode tn) {
488      Resource r = (Resource)tn.Tag;
489      var descendants = GetResourceDescendants();
490      if(descendants.ContainsKey(r.Id)) {
491        if(descendants[r.Id].OfType<SlaveGroup>().Any()) {
492          tn.Expand();
493          foreach (TreeNode n in tn.Nodes) CollapseSlaveOnlyNodes(n);
494        } else {
495          tn.Collapse();
496        }
497      }
498    }
499
500    private void ExpandResourceNodesOfInterest(TreeNodeCollection nodes) {
501      foreach (TreeNode n in nodes) {
502        Resource r = (Resource)n.Tag;
503        if (n.Nodes.Count > 0) {
504          if (HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()) {
505            n.Expand();
506            ExpandResourceNodesOfInterest(n.Nodes);
507          } else {
508            n.Collapse();
509          }
510        } else {
511          n.Collapse();
512        }
513      }
514    }
515
516    private void UpdateChildHbIntervall(Resource resource) {
517      foreach (Resource r in Content.Where(x => x.ParentResourceId == resource.Id)) {
518        r.HbInterval = resource.HbInterval;
519        if (r is SlaveGroup) {
520          UpdateChildHbIntervall(r);
521        }
522      }
523    }
524
525    private void UpdateResources() {
526      try {
527        HiveAdminClient.Instance.Refresh();
528        Content = HiveAdminClient.Instance.Resources;
529      } catch(AnonymousUserException) {
530        ShowHiveInformationDialog();
531      }
532    }
533
534    private void RemoveResource(Resource resource) {
535      if (resource == null) return;
536
537      try {
538        if (resource.Id != Guid.Empty) {
539          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
540          foreach (var r in resourcesToSave)
541            r.Store();
542          HiveAdminClient.Delete(resource);
543          UpdateResources();
544        } else {
545          Content.Remove(selectedResource);
546        }
547      } catch(AnonymousUserException) {
548        ShowHiveInformationDialog();
549      }
550    }
551
552    private void UpdateSchedule() {
553      try {
554        HiveAdminClient.Instance.RefreshCalendar();
555      } catch (AnonymousUserException) {
556        ShowHiveInformationDialog();
557      }
558    }
559
560    private bool IsAdmin() {
561      return HiveRoles.CheckAdminUserPermissions();
562    }
563
564    private void StyleTreeNode(TreeNode n, Resource r, IEnumerable<Resource> resources) {
565      n.Text = r.Name;
566      n.BackColor = Color.Transparent;
567      n.ForeColor = Color.Black;
568
569      // not stored (i.e. new), changed
570      if (r.Id == Guid.Empty && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
571        n.Text += NOT_STORED_TAG;
572      } else if (r.Modified && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
573        n.Text += CHANGES_NOT_STORED_TAG;
574      }
575
576      // slave count
577      int childSlavesCount = 0;
578      if (r.Id != Guid.Empty && r is SlaveGroup) {
579        var descendants = GetResourceDescendants();
580        if (descendants.ContainsKey(r.Id)) {
581          childSlavesCount = resources
582            .OfType<Slave>()
583            .Where(x => descendants[r.Id].Select(y => y.Id)
584              .Contains(x.Id))
585            .Count();
586        }
587      } else if(n == ungroupedGroupNode /*|| r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
588        childSlavesCount = resources
589          .OfType<Slave>()
590          .Where(x => x.ParentResourceId == null 
591            || (x.ParentResourceId.HasValue && x.ParentResourceId.Value == Guid.Empty))
592          .Count();
593      }
594      if (childSlavesCount > 0)
595        n.Text += " [" + childSlavesCount.ToString() + "]";
596
597      // slave image index, state, utilization
598      if (r is Slave) {
599        n.ImageIndex = slaveImageIndex;
600        var s = r as Slave;
601        if (s.SlaveState == SlaveState.Calculating) {
602          n.ForeColor = calculatingColor;
603          n.Text += " [" + s.CpuUtilization.ToString("N2") + "%]";
604        } else if (s.SlaveState == SlaveState.Offline) {
605          n.ForeColor = offlineColor;
606          if (s.LastHeartbeat.HasValue)
607            n.Text += " [" + s.LastHeartbeat?.ToString("g") + "]";
608        }
609      } else {
610        n.ImageIndex = slaveGroupImageIndex;
611      }
612
613      // ungrouped
614      if(n == ungroupedGroupNode /*r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
615        n.ForeColor = ForeColor = SystemColors.GrayText;
616      }
617    }
618
619    private void ResetTreeNodes(TreeNodeCollection nodes, IEnumerable<Resource> resources) {
620      foreach (TreeNode n in nodes) {
621        StyleTreeNode(n, (Resource)n.Tag, resources);
622        if (n.Nodes.Count > 0) {
623          ResetTreeNodes(n.Nodes, resources);
624        }
625      }
626    }
627
628    private async void ChangeSelectedResource(Resource resource) {
629      selectedResource = resource;
630      viewHost.Content = selectedResource;
631
632      HiveAdminClient.Instance.DowntimeForResourceId = selectedResource != null ? selectedResource.Id : Guid.Empty;
633      if (tabSlaveGroup.SelectedTab == tabSchedule) {
634        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
635          action: () => UpdateSchedule(),
636          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
637      }
638
639      SetEnabledStateOfControls();
640    }
641
642    private void ChangeSelectedResourceNode(TreeNode resourceNode) {
643      if (resourceNode == null) return;
644      SelectedResource = (Resource)resourceNode.Tag;
645      ResetTreeNodes(treeView.Nodes, Content);
646      resourceNode.BackColor = selectedBackColor;
647      resourceNode.ForeColor = selectedForeColor;
648      resourceNode.Text += SELECTED_TAG;
649    }
650
651    private void ShowHiveInformationDialog() {
652      if (InvokeRequired) Invoke((Action)ShowHiveInformationDialog);
653      else {
654        using (HiveInformationDialog dialog = new HiveInformationDialog()) {
655          dialog.ShowDialog(this);
656        }
657      }
658    }
659
660    private void ResetView() {
661      if (InvokeRequired) Invoke((Action)ResetView);
662      else {
663        treeView.Nodes.Clear();
664
665        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
666          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
667        }
668
669        viewHost.Content = null;
670        if (scheduleView.Content != null) {
671          scheduleView.Content.Clear();
672        }
673
674        HiveAdminClient.Instance.ResetDowntime();
675      }
676    }
677
678
679    private Dictionary<Guid, HashSet<Resource>> GetResourceDescendants() {
680      var resourceDescendants = new Dictionary<Guid, HashSet<Resource>>();
681
682      foreach (var r in Content) resourceDescendants.Add(r.Id, new HashSet<Resource>());
683      foreach(var r in Content) {
684        var parentResourceId = r.ParentResourceId;
685        while(parentResourceId != null) {
686          var parent = Content.SingleOrDefault(x => x.Id == parentResourceId);
687          if(parent != null) {
688            resourceDescendants[parent.Id].Add(r);
689            parentResourceId = parent.ParentResourceId;
690          } else {
691            parentResourceId = null;
692          }
693        }
694      }
695      return resourceDescendants;
696    }
697   
698    #endregion
699  }
700}
Note: See TracBrowser for help on using the repository browser.