Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 16773 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

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