source: branches/2965_CancelablePersistence/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs @ 16433

Last change on this file since 16433 was 16433, checked in by pfleck, 11 months ago

#2965 Merged recent trunk changes.
Enabled the prepared hooks that allows to cancel the save file using the recently introduced cancelable progressbars (in FileManager).

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