Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs @ 15658

Last change on this file since 15658 was 15658, checked in by jzenisek, 6 years ago

#2839

  • worked on (restricted) accessibility of hive's administration area for non-admin roles
  • adapted HiveClient & HiveAdminClient entity loading (client- & service-side)
File size: 17.3 KB
RevLine 
[6976]1#region License Information
2/* HeuristicLab
[15401]3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[6976]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;
[15422]23using System.Collections.Generic;
[15401]24using System.ComponentModel;
[6976]25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
[8051]28using HeuristicLab.Clients.Access;
[6976]29using HeuristicLab.Clients.Hive.Views;
[15412]30using HeuristicLab.Collections;
[15401]31using HeuristicLab.Common.Resources;
[6976]32using HeuristicLab.Core;
33using HeuristicLab.Core.Views;
34using HeuristicLab.MainForm;
35
36namespace HeuristicLab.Clients.Hive.Administrator.Views {
37  [View("Resources View")]
[7928]38  [Content(typeof(IItemList<Resource>), false)]
[6976]39  public partial class ResourcesView : ItemView, IDisposable {
[15401]40    private const int slaveImageIndex = 0;
41    private const int slaveGroupImageIndex = 1;
[15422]42    public const string ungroupedGroupName = "UNGROUPED";
43    public const string ungroupedGroupDescription = "Contains slaves that are not assigned to any group.";
[15401]44
45    private readonly Color ownedResourceColor = Color.LightGreen;
46    private readonly object locker = new object();
47
[6976]48    public new IItemList<Resource> Content {
49      get { return (IItemList<Resource>)base.Content; }
50      set { base.Content = value; }
51    }
52
53    public ResourcesView() {
54      InitializeComponent();
55
[15422]56      treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge);
57      treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
[8051]58
[15401]59      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
60      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
61      AccessClient.Instance.Refreshing += AccessClient_Instance_Refreshing;
62      AccessClient.Instance.Refreshed += AccessClient_Instance_Refreshed;
[6976]63    }
64
[15401]65    #region Overrides
66    protected override void OnClosing(FormClosingEventArgs e) {
67      AccessClient.Instance.Refreshed -= AccessClient_Instance_Refreshed;
68      AccessClient.Instance.Refreshing -= AccessClient_Instance_Refreshing;
69      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
70      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
71      base.OnClosing(e);
[6976]72    }
73
[15401]74    protected override void RegisterContentEvents() {
75      base.RegisterContentEvents();
76      Content.ItemsAdded += Content_ItemsAdded;
77      Content.ItemsRemoved += Content_ItemsRemoved;
[6976]78    }
79
80    protected override void DeregisterContentEvents() {
[15401]81      Content.ItemsRemoved -= Content_ItemsRemoved;
82      Content.ItemsAdded -= Content_ItemsAdded;
[6976]83      base.DeregisterContentEvents();
84    }
85
86    protected override void OnContentChanged() {
87      base.OnContentChanged();
88      if (Content == null) {
[15422]89        treeView.Nodes.Clear();
90        viewHost.Content = null;
[8051]91        scheduleView.Content = null;
[6976]92      } else {
[15422]93        var top = BuildResourceTree(Content);
94        viewHost.Content = top;
[6976]95      }
96    }
97
98    protected override void SetEnabledStateOfControls() {
99      base.SetEnabledStateOfControls();
[15567]100      bool enabled = Content != null && !Locked;
[15401]101      btnAddGroup.Enabled = enabled;
102      btnRemoveGroup.Enabled = enabled;
103      btnSave.Enabled = enabled;
[15422]104      scheduleView.SetEnabledStateOfSchedule(enabled && IsAuthorized((Resource)viewHost.Content));
[6976]105    }
[15401]106    #endregion
[6976]107
[15401]108    #region Event Handlers
[15412]109    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
110      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsAdded, sender, e);
111      else {
112        OnContentChanged();
113      }
[8051]114    }
[6976]115
[15412]116    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Resource>> e) {
117      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Resource>>>)Content_ItemsRemoved, sender, e);
118      else {
119        OnContentChanged();
120      }
[6976]121    }
122
[15401]123    private void SlaveViewContent_PropertyChanged(object sender, PropertyChangedEventArgs e) {
[15412]124      if (InvokeRequired) Invoke((Action<object, PropertyChangedEventArgs>)SlaveViewContent_PropertyChanged, sender, e);
125      else {
126        OnContentChanged();
127        if (e.PropertyName == "HbInterval") {
[15422]128          UpdateChildHbIntervall((Resource)viewHost.Content);
[15412]129        }
[6976]130      }
131    }
132
[15401]133    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
134      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
135      else {
136        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
137        mainForm.AddOperationProgressToView(this, "Refreshing ...");
138        SetEnabledStateOfControls();
[6976]139      }
140    }
141
[15401]142    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
143      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
144      else {
145        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
146        mainForm.RemoveOperationProgressFromView(this);
147        SetEnabledStateOfControls();
148      }
[6976]149    }
150
[15401]151    private void AccessClient_Instance_Refreshing(object sender, EventArgs e) {
152      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshing, sender, e);
153      else {
154        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
155        mainForm.AddOperationProgressToView(this, "Refreshing ...");
156        SetEnabledStateOfControls();
157      }
[6976]158    }
159
[15401]160    private void AccessClient_Instance_Refreshed(object sender, EventArgs e) {
161      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshed, sender, e);
162      else {
163        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
164        mainForm.RemoveOperationProgressFromView(this);
165        SetEnabledStateOfControls();
166      }
[6976]167    }
168
[15401]169    private async void ResourcesView_Load(object sender, EventArgs e) {
170      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
[15412]171        action: () => UpdateResources());
[15401]172    }
173
174    private async void btnRefresh_Click(object sender, EventArgs e) {
175      lock (locker) {
[15422]176        if (!btnRefresh.Enabled) return;
177        btnRefresh.Enabled = false;
[6976]178      }
[15401]179
180      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
181        action: () => UpdateResources(),
[15422]182        finallyCallback: () => btnRefresh.Enabled = true);
[6976]183    }
184
[15401]185    private void btnAddGroup_Click(object sender, EventArgs e) {
186      var group = new SlaveGroup {
187        Name = "New Group",
188        OwnerUserId = UserInformation.Instance.User.Id
189      };
190      Content.Add(group);
191    }
192
193    private async void btnRemoveGroup_Click(object sender, EventArgs e) {
194      lock (locker) {
[15422]195        if (!btnRemoveGroup.Enabled) return;
196        btnRemoveGroup.Enabled = false;
[6976]197      }
[15401]198
199      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
200        action: () => RemoveResource(),
[15422]201        finallyCallback: () => btnRemoveGroup.Enabled = true);
[6976]202    }
203
[15401]204    private async void btnSave_Click(object sender, EventArgs e) {
205      lock (locker) {
[15422]206        if (!btnSave.Enabled) return;
207        btnSave.Enabled = false;
[15401]208      }
209
210      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
211        action: () => {
212          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
213          foreach (var resource in resourcesToSave)
214            resource.Store();
215        },
[15422]216        finallyCallback: () => btnSave.Enabled = true);
[15401]217    }
218
219    private async void treeSlaveGroup_AfterSelect(object sender, TreeViewEventArgs e) {
220      var selectedResource = (Resource)e.Node.Tag;
221
[15422]222      if (viewHost.Content != null && viewHost.Content is SlaveGroup)
223        ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
[15401]224
[15422]225      viewHost.Content = selectedResource;
226      HiveAdminClient.Instance.DowntimeForResourceId = selectedResource != null ? selectedResource.Id : Guid.Empty;
227      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
228        action: () => UpdateSchedule(),
229        finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
[15401]230
[15412]231      if (selectedResource != null && selectedResource is SlaveGroup)
232        selectedResource.PropertyChanged += SlaveViewContent_PropertyChanged;
[15401]233
[15412]234      if (IsAuthorized(selectedResource)) {
235        if (!tabSlaveGroup.TabPages.Contains(tabSchedule))
236          tabSlaveGroup.TabPages.Add(tabSchedule);
237      } else {
238        if (tabSlaveGroup.TabPages.Contains(tabSchedule))
239          tabSlaveGroup.TabPages.Remove(tabSchedule);
240      }
[15401]241    }
242
[6976]243    private void treeSlaveGroup_DragDrop(object sender, DragEventArgs e) {
[15422]244      var sourceNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
245      if (sourceNode == null) return;
[6976]246
[15422]247      var treeView = (TreeView)sender;
248      if (sourceNode.TreeView != treeView) return;
[6976]249
[15422]250      var targetPoint = treeView.PointToClient(new Point(e.X, e.Y));
251      var targetNode = treeView.GetNodeAt(targetPoint);
[6976]252
[15422]253      if (sourceNode == targetNode) return;
[6976]254
[15422]255      if (targetNode.Text == ungroupedGroupName || targetNode.Parent != null && targetNode.Parent.Text == ungroupedGroupName) {
256        MessageBox.Show(
257          string.Format(@"You cannot drag resources to group ""{0}"". This group only contains slaves which have not been assigned to a real group yet.", ungroupedGroupName),
258          "HeuristicLab Hive Administrator",
259          MessageBoxButtons.OK,
260          MessageBoxIcon.Information);
261        return;
262      }
[8051]263
[15422]264      if (sourceNode.Parent == null)
265        treeView.Nodes.Remove(sourceNode);
266      else {
267        sourceNode.Parent.Nodes.Remove(sourceNode);
268        ((Resource)sourceNode.Tag).ParentResourceId = null;
269      }
[8051]270
[15422]271      if (targetNode == null) {
272        treeView.Nodes.Add(sourceNode);
273      } else {
274        targetNode.Nodes.Add(sourceNode);
275        ((Resource)sourceNode.Tag).ParentResourceId = ((Project)targetNode.Tag).Id;
[6976]276      }
277    }
278
279    private void treeSlaveGroup_ItemDrag(object sender, ItemDragEventArgs e) {
280      TreeNode sourceNode = (TreeNode)e.Item;
[8051]281      if (IsAuthorized((Resource)sourceNode.Tag))
282        DoDragDrop(sourceNode, DragDropEffects.All);
[6976]283    }
284
285    private void treeSlaveGroup_DragEnter(object sender, DragEventArgs e) {
286      e.Effect = DragDropEffects.Move;
287    }
288
289    private void treeSlaveGroup_DragOver(object sender, DragEventArgs e) {
290      e.Effect = DragDropEffects.Move;
291    }
292
293    private void treeSlaveGroup_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) {
294      e.Action = DragAction.Continue;
295    }
[15401]296    #endregion
297
298    #region Helpers
[15422]299    private Resource BuildResourceTree(IEnumerable<Resource> resources) {
300      treeView.Nodes.Clear();
301      if (!resources.Any()) return null;
302
[15557]303      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>().Where(x => x.ParentResourceId == null));
[15658]304      var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
305        .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
306      mainResources.UnionWith(parentedMainResources);
307      var subResources = new HashSet<Resource>(resources.Except(mainResources).OrderByDescending(x => x.Name));
[15422]308
[15557]309      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
[15658]310      Resource top = null;
[15422]311
312      TreeNode currentNode = null;
313      Resource currentResource = null;
314
[15557]315      while(stack.Any()) {
[15658]316        if (top == null) top = stack.Peek();
[15422]317        var newResource = stack.Pop();
318        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
319
[15557]320        // search for parent node of newNode and save in currentNode
321        // necessary since newNodes (stack top items) might be siblings
322        // or grand..grandparents of previous node (currentNode)
323        while(currentNode != null && newResource.ParentResourceId != currentResource.Id) {
[15422]324          currentNode = currentNode.Parent;
325          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
[15401]326        }
327
[15557]328        if(currentNode == null) {
[15422]329          treeView.Nodes.Add(newNode);
330        } else {
331          currentNode.Nodes.Add(newNode);
332        }
333
[15557]334        if(newResource is Slave) {
[15422]335          newNode.ImageIndex = slaveImageIndex;
336        } else {
337          newNode.ImageIndex = slaveGroupImageIndex;
338
[15557]339          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
340          if(childResources.Any()) {
341            foreach(var resource in childResources.OrderByDescending(x => x.Name)) {
342              subResources.Remove(resource);
343              stack.Push(resource);
[15422]344            }
345            currentNode = newNode;
346            currentResource = newResource;
347          }
348        }
349        newNode.SelectedImageIndex = newNode.ImageIndex;
[15576]350        //if (newResource.OwnerUserId == UserInformation.Instance.User.Id)
351        //  newNode.BackColor = ownedResourceColor;
[15401]352      }
[15422]353
354      var ungroupedNode = new TreeNode(ungroupedGroupName) {
355        ForeColor = SystemColors.GrayText,
356        Tag = new SlaveGroup() {
357          Name = ungroupedGroupName,
358          Description = ungroupedGroupDescription
359        }
360      };
361
[15557]362      foreach (var slave in subResources.OfType<Slave>().OrderBy(x => x.Name)) {
[15422]363        var slaveNode = new TreeNode(slave.Name) { Tag = slave };
364        ungroupedNode.Nodes.Add(slaveNode);
365      }
366
367      treeView.Nodes.Add(ungroupedNode);
368      treeView.ExpandAll();
369
370      return top;
[15401]371    }
372
373    private void UpdateChildHbIntervall(Resource resource) {
374      foreach (Resource r in Content.Where(x => x.ParentResourceId == resource.Id)) {
375        r.HbInterval = resource.HbInterval;
376        if (r is SlaveGroup) {
377          UpdateChildHbIntervall(r);
378        }
379      }
380    }
381
382    private bool CheckParentsEqualsMovedNode(TreeNode dest, TreeNode movedNode) {
383      TreeNode tmp = dest;
384
385      while (tmp != null) {
386        if (tmp == movedNode) {
387          return true;
388        }
389        tmp = tmp.Parent;
390      }
391      return false;
392    }
393
394    private void ResetView() {
395      if (InvokeRequired) Invoke((Action)ResetView);
396      else {
[15422]397        treeView.Nodes.Clear();
[6976]398
[15422]399        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
400          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
[7256]401        }
[15401]402
[15422]403        viewHost.Content = null;
[7256]404        if (scheduleView.Content != null) {
405          scheduleView.Content.Clear();
406        }
[15401]407
[7256]408        HiveAdminClient.Instance.ResetDowntime();
[6976]409      }
410    }
411
412    private void UpdateResources() {
[15412]413      HiveAdminClient.Instance.Refresh();
414      Content = HiveAdminClient.Instance.Resources;
[6976]415    }
416
[15401]417    private void RemoveResource() {
[15422]418      var selectedNode = treeView.SelectedNode;
[15401]419      if (selectedNode == null || selectedNode.Tag == null) return;
[7256]420
[15401]421      var resource = (Resource)selectedNode.Tag;
422      var result = MessageBox.Show(
423        "Do you really want to delete " + resource.Name + "?",
424        "HeuristicLab Hive Administrator",
425        MessageBoxButtons.YesNo,
426        MessageBoxIcon.Question);
427
428      if (result == DialogResult.Yes) {
429        if (resource is Slave) {
430          Content.Remove(resource);
431          HiveAdminClient.Delete(resource);
432        } else if (resource is SlaveGroup) {
433          if (Content.Any(x => x.ParentResourceId == resource.Id)) {
434            MessageBox.Show(
435              "Only empty resources can be deleted.",
436              "HeuristicLab Hive Administrator",
437              MessageBoxButtons.OK,
438              MessageBoxIcon.Error);
439          } else {
440            Content.Remove(resource);
441            HiveAdminClient.Delete(resource);
442          }
[7256]443        }
444      }
445    }
446
[6976]447    private void UpdateSchedule() {
[15412]448      try {
449        HiveAdminClient.Instance.RefreshCalendar();
450      } catch (AnonymousUserException) {
451        ShowHiveInformationDialog();
[15401]452      }
[8051]453    }
454
[15401]455    private bool IsAuthorized(Resource resource) {
456      return resource != null
[15422]457          && resource.Name != ungroupedGroupName
[15401]458          && resource.Id != Guid.Empty
459          && UserInformation.Instance.UserExists
460          && (resource.OwnerUserId == UserInformation.Instance.User.Id || HiveRoles.CheckAdminUserPermissions());
[8051]461    }
462
[15401]463    private void ShowHiveInformationDialog() {
464      if (InvokeRequired) Invoke((Action)ShowHiveInformationDialog);
465      else {
466        using (HiveInformationDialog dialog = new HiveInformationDialog()) {
467          dialog.ShowDialog(this);
468        }
[6976]469      }
470    }
[15401]471    #endregion
[6976]472  }
473}
Note: See TracBrowser for help on using the repository browser.