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

Last change on this file since 16209 was 16209, checked in by jzenisek, 15 months ago

#2839:

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