Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs @ 17181

Last change on this file since 17181 was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

File size: 20.3 KB
RevLine 
[15422]1#region License Information
2/* HeuristicLab
[17181]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[15422]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.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Clients.Access;
28using HeuristicLab.Common.Resources;
29using HeuristicLab.Core.Views;
30using HeuristicLab.MainForm;
31
32namespace HeuristicLab.Clients.Hive.Administrator.Views {
33  [View("ProjectView")]
34  [Content(typeof(Project), IsDefaultView = false)]
35  public partial class ProjectResourcesView : ItemView {
36    private const int slaveImageIndex = 0;
37    private const int slaveGroupImageIndex = 1;
[16117]38    public const string UNGROUPED_GROUP_NAME = "UNGROUPED";
39    public const string UNGROUPED_GROUP_DESCRIPTION = "Contains slaves that are not assigned to any group.";
40    public const string IMMUTABLE_TAG = " [assigned, immutable]";
41    public const string INCLUDED_TAG = " [included]";
42    public const string ADDED_ASSIGNMENT_TAG = " [added assignment]";
43    public const string REMOVED_ASSIGNMENT_TAG = " [removed assignment]";
44    public const string ADDED_INCLUDE_TAG = " [added include]";
45    public const string REMOVED_INCLUDE_TAG = " [removed include]";
[15422]46
47    private readonly HashSet<Resource> assignedResources = new HashSet<Resource>();
[15559]48    private readonly HashSet<Resource> newAssignedResources = new HashSet<Resource>();
[16117]49    private readonly HashSet<Resource> includedResources = new HashSet<Resource>();
50    private readonly HashSet<Resource> newIncludedResources = new HashSet<Resource>();
[15658]51
[15567]52    private readonly Color addedAssignmentColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
53    private readonly Color removedAssignmentColor = Color.FromArgb(255, 236, 159, 72); // #ec9f48
54    private readonly Color addedIncludeColor = Color.FromArgb(25, 169, 221, 221); // #a9dddd
55    private readonly Color removedIncludeColor = Color.FromArgb(25, 249, 210, 145); // #f9d291
[16117]56    private readonly Color selectedBackColor = Color.DodgerBlue;
57    private readonly Color selectedForeColor = Color.White;
58    private readonly Color grayTextColor = SystemColors.GrayText;
[15422]59
[16117]60    private HashSet<Resource> projectExclusiveResources = new HashSet<Resource>();
61    private TreeNode ungroupedGroupNode;
62
[15422]63    public new Project Content {
64      get { return (Project)base.Content; }
65      set { base.Content = value; }
66    }
67
68    public ProjectResourcesView() {
69      InitializeComponent();
70
71      treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge);
72      treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
[17059]73
74      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
75      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
[15422]76    }
77
78    #region Overrides
79    protected override void OnContentChanged() {
80      base.OnContentChanged();
81      if (Content == null) {
82        assignedResources.Clear();
[15559]83        newAssignedResources.Clear();
[16117]84        includedResources.Clear();
[15422]85        treeView.Nodes.Clear();
86        detailsViewHost.Content = null;
87      } else {
88        UpdateAssignedResources();
[16117]89        UpdateIncludedResources();
[17059]90        detailsViewHost.Content = BuildResourceTree();
[15422]91      }
[17059]92      SetEnabledStateOfControls();
[15422]93    }
[15559]94
[15760]95    protected override void SetEnabledStateOfControls() {
96      base.SetEnabledStateOfControls();
97      bool enabled = Content != null && !Locked && !ReadOnly;
98
99      inheritButton.Enabled = enabled;
100      saveButton.Enabled = enabled;
101      treeView.Enabled = enabled;
[17059]102
103      if (detailsViewHost != null) {
104        detailsViewHost.Locked = true;
105      }
[15760]106    }
[15422]107    #endregion
108
109    #region Event Handlers
[17059]110    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
111      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
112      else {
113        SetEnabledStateOfControls();
114      }
115    }
116
117    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
118      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
119      else {
120        OnContentChanged();
121      }
122    }
123
[17063]124    private void ProjectResourcesView_Disposed(object sender, EventArgs e) {
125      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
126      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
[15422]127    }
128
129    private void refreshButton_Click(object sender, EventArgs e) {
[16117]130      HiveAdminClient.Instance.Refresh();
[15422]131      UpdateAssignedResources();
[16117]132      UpdateIncludedResources();
133      var top = BuildResourceTree();
[15422]134      detailsViewHost.Content = top;
135    }
136
[15576]137    private async void inheritButton_Click(object sender, EventArgs e) {
138      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
139        action: () => {
[15642]140          SetAssignedProjectResources(Content.Id, newAssignedResources.Select(x => x.Id), false, true, false);
[15576]141        });
[16117]142      HiveAdminClient.Instance.Refresh();
[15576]143      UpdateResourceTree();
[15422]144    }
145
146    private async void saveButton_Click(object sender, EventArgs e) {
147      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
[15559]148        action: () => {
[15642]149          SetAssignedProjectResources(Content.Id, newAssignedResources.Select(x => x.Id), false, false, false);
[15559]150        });
[16117]151      HiveAdminClient.Instance.Refresh();
[15559]152      UpdateResourceTree();
[15422]153    }
154
[16117]155    private void treeView_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
156      if (e.Node == null || e.Node == ungroupedGroupNode)
157        e.Cancel = true;
158
159      var selectedResource = (Resource)e.Node.Tag;
[17063]160      if (HiveAdminClient.Instance.DisabledParentResources.Contains(selectedResource))
[16117]161        e.Cancel = true;
162    }
163
[15422]164    private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
165      var selectedResource = (Resource)e.Node.Tag;
166      detailsViewHost.Content = selectedResource;
167    }
168
169    private void treeView_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
[16117]170      if (e.Node == null || e.Node == ungroupedGroupNode) {
171        e.Cancel = true;
172        return;
173      }
[17063]174
[15422]175      var checkedResource = (Resource)e.Node.Tag;
[16117]176      if (checkedResource == null
177        || checkedResource.Id == Guid.Empty
[17063]178        || HiveAdminClient.Instance.DisabledParentResources.Contains(checkedResource)
[16117]179        || newIncludedResources.Contains(checkedResource)) {
[15658]180        e.Cancel = true;
[16117]181      } else if (!IsAdmin()) {
[17063]182        if (!HiveAdminClient.Instance.CheckOwnershipOfParentProject(Content, UserInformation.Instance.User.Id)
183          || !HiveAdminClient.Instance.GetAvailableProjectAncestors(Content.Id).Any()
184          || projectExclusiveResources.Contains(checkedResource)) {
185          e.Cancel = true;
186        }
[15658]187      }
[15422]188    }
189
190    private void treeView_AfterCheck(object sender, TreeViewEventArgs e) {
191      var checkedResource = (Resource)e.Node.Tag;
[15559]192      if (e.Node.Checked) {
193        newAssignedResources.Add(checkedResource);
194      } else {
195        newAssignedResources.Remove(checkedResource);
196      }
197
[15576]198      UpdateNewResourceTree();
[15422]199    }
200    #endregion
201
202    #region Helpers
[15559]203
204    private void UpdateResourceTree() {
205      UpdateAssignedResources();
[16117]206      UpdateIncludedResources();
207
208      var top = BuildResourceTree();
[15559]209      detailsViewHost.Content = top;
210    }
211
[15576]212    private void UpdateNewResourceTree() {
213      UpdateNewAssignedResources();
[16117]214      UpdateNewIncludedResources();
215      var top = BuildResourceTree();
[15576]216      detailsViewHost.Content = top;
217    }
218
[16117]219    private IEnumerable<Resource> GetAvailableResourcesForProjectAdministration(Guid projectId) {
220      projectExclusiveResources.Clear();
221      if (projectId == Guid.Empty) return Enumerable.Empty<Resource>();
222      var resources = HiveAdminClient.Instance.Resources.Where(x => x.Id != Guid.Empty);
223      if (!resources.Any()) return resources;
224      if (IsAdmin()) return resources;
225
226      // get project specific assigned resources
[17063]227      var projectResources = resources.Where(x =>
[16117]228        HiveAdminClient.Instance.ProjectResourceAssignments
229          .Where(a => a.ProjectId == projectId)
230          .Select(a => a.ResourceId)
231        .Contains(x.Id));
232
233      // look up for assignments of ancestor projects
234      var projectIds = new HashSet<Guid>();
235      HiveAdminClient.Instance.GetAvailableProjectAncestors(projectId).ToList().ForEach(x => projectIds.Add(x.Id));
236
[17063]237      var ancestorProjectResources = resources.Where(x =>
[16117]238        HiveAdminClient.Instance.ProjectResourceAssignments
239          .Where(a => projectIds.Contains(a.ProjectId))
240          .Select(a => a.ResourceId)
241        .Contains(x.Id));
242
243      // look down for included resources of ancestor projects
244      HashSet<Resource> availableResources = new HashSet<Resource>(ancestorProjectResources);
245      foreach (var r in ancestorProjectResources) {
[17063]246        foreach (var d in HiveAdminClient.Instance.GetAvailableResourceDescendants(r.Id)) {
[16117]247          availableResources.Add(d);
248        }
249      }
250
251      // determine resources, which are exclusively assigned to the currently selected project
252      projectResources
253        .Except(availableResources)
254        .ToList()
255        .ForEach(x => projectExclusiveResources.Add(x));
256
257      // look down for included resources of currently selected project
258      if (projectExclusiveResources.Any()) {
259        foreach (var r in projectExclusiveResources.ToArray()) {
260          foreach (var d in HiveAdminClient.Instance.GetAvailableResourceDescendants(r.Id)) {
261            projectExclusiveResources.Add(d);
[17063]262          }
[16117]263        }
264      }
265
266      return availableResources.Union(projectExclusiveResources);
[15422]267    }
268
[16117]269    private IEnumerable<Resource> GetAssignedResourcesForProject(Guid projectId) {
270      if (projectId == Guid.Empty) return Enumerable.Empty<Resource>();
271      return HiveAdminClient.Instance.Resources.Where(x =>
272        HiveAdminClient.Instance.ProjectResourceAssignments
273          .Where(a => a.ProjectId == projectId)
274          .Select(a => a.ResourceId)
275        .Contains(x.Id));
276    }
277
[15642]278    private void SetAssignedProjectResources(Guid projectId, IEnumerable<Guid> resourceIds, bool reassign, bool cascading, bool reassignCascading) {
[15576]279      if (projectId == null || resourceIds == null) return;
[15422]280      HiveServiceLocator.Instance.CallHiveService(s => {
[17063]281        s.SaveProjectResourceAssignments(projectId, resourceIds.ToList(), reassign, cascading, reassignCascading);
[15422]282      });
283    }
284
[15559]285    private void UpdateNewAssignedResources() {
[17063]286      for (int i = newAssignedResources.Count - 1; i >= 0; i--) {
287        if (newAssignedResources.Intersect(HiveAdminClient.Instance.GetAvailableResourceAncestors(newAssignedResources.ElementAt(i).Id)).Any()) {
[15559]288          newAssignedResources.Remove(newAssignedResources.ElementAt(i));
289        }
290      }
291    }
292
[15422]293    private void UpdateAssignedResources() {
294      assignedResources.Clear();
[15559]295      newAssignedResources.Clear();
296      foreach (var r in GetAssignedResourcesForProject(Content.Id)) {
[15422]297        assignedResources.Add(r);
[15559]298        newAssignedResources.Add(r);
299      }
[15422]300    }
301
[16117]302    private void UpdateIncludedResources() {
303      includedResources.Clear();
304      newIncludedResources.Clear();
305      foreach (var a in assignedResources) {
306        foreach (var r in HiveAdminClient.Instance.GetAvailableResourceDescendants(a.Id)) {
307          includedResources.Add(r);
308          newIncludedResources.Add(r);
[15559]309        }
310      }
311    }
312
[16117]313    private void UpdateNewIncludedResources() {
314      newIncludedResources.Clear();
315      foreach (var a in newAssignedResources) {
316        foreach (var r in HiveAdminClient.Instance.GetAvailableResourceDescendants(a.Id)) {
317          newIncludedResources.Add(r);
[15559]318        }
319      }
[15422]320    }
321
[16117]322    private Resource BuildResourceTree() {
[15422]323      treeView.Nodes.Clear();
324
325      treeView.BeforeCheck -= treeView_BeforeCheck;
326      treeView.AfterCheck -= treeView_AfterCheck;
327
[16117]328      var resources = GetAvailableResourcesForProjectAdministration(Content.Id);
329
330      var disabledParentResources = HiveAdminClient.Instance.DisabledParentResources;
[15559]331      var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>().Where(x => x.ParentResourceId == null));
[16117]332      //var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
333      //  .Where(x => x.ParentResourceId.HasValue && !resources.Select(y => y.Id).Contains(x.ParentResourceId.Value)));
334      //mainResources.UnionWith(parentedMainResources);
335      var mainDisabledParentResources = new HashSet<Resource>(disabledParentResources.Where(x => x.ParentResourceId == null || x.ParentResourceId == Guid.Empty));
336      mainResources.UnionWith(mainDisabledParentResources);
337      var subResources = new HashSet<Resource>(resources.Union(disabledParentResources).Except(mainResources).OrderByDescending(x => x.Name));
[15422]338
[15559]339      var stack = new Stack<Resource>(mainResources.OrderByDescending(x => x.Name));
[17063]340
[15627]341      Resource top = null;
[16117]342      //bool nodeSelected = false;
343      if (detailsViewHost != null && detailsViewHost.Content != null && detailsViewHost.Content is Resource) {
344        var resourceId = ((Resource)detailsViewHost.Content).Id;
345        top = resources.Where(x => x.Id == resourceId).FirstOrDefault();
346      }
[15422]347
[17063]348
[15422]349      TreeNode currentNode = null;
350      Resource currentResource = null;
351
[15567]352      var addedAssignments = newAssignedResources.Except(assignedResources);
353      var removedAssignments = assignedResources.Except(newAssignedResources);
[16117]354      var addedIncludes = newIncludedResources.Except(includedResources);
355      var removedIncludes = includedResources.Except(newIncludedResources);
[15567]356
[15422]357      while (stack.Any()) {
358        var newResource = stack.Pop();
359        var newNode = new TreeNode(newResource.Name) { Tag = newResource };
360
[17063]361        if (top == null && !disabledParentResources.Contains(newResource)) {
[16117]362          top = newResource;
363        }
364
365        //if(!nodeSelected && top != null && newResource.Id == top.Id) {
366        //  newNode.BackColor = selectedBackColor;
367        //  newNode.ForeColor = selectedForeColor;
368        //  nodeSelected = true;
369        //}
370
[15559]371        // search for parent node of newNode and save in currentNode
372        // necessary since newNodes (stack top items) might be siblings
373        // or grand..grandparents of previous node (currentNode)
[15422]374        while (currentNode != null && newResource.ParentResourceId != currentResource.Id) {
375          currentNode = currentNode.Parent;
376          currentResource = currentNode == null ? null : (Resource)currentNode.Tag;
377        }
378
379        if (currentNode == null) {
380          treeView.Nodes.Add(newNode);
381        } else {
382          currentNode.Nodes.Add(newNode);
383        }
384
[16117]385        if (disabledParentResources.Contains(newResource)) {
386          newNode.Checked = false;
387          newNode.ForeColor = grayTextColor;
388        } else if (newAssignedResources.Contains(newResource)) {
[15559]389          newNode.Checked = true;
[17063]390          if (!HiveRoles.CheckAdminUserPermissions()) {
391            if (!HiveAdminClient.Instance.CheckOwnershipOfParentProject(Content, UserInformation.Instance.User.Id)
392              || !HiveAdminClient.Instance.GetAvailableProjectAncestors(Content.Id).Any()
[16117]393              || projectExclusiveResources.Contains(newResource)) {
[15658]394              newNode.ForeColor = SystemColors.GrayText;
[16117]395              newNode.Text += IMMUTABLE_TAG;
[15658]396            }
397          }
398
[16117]399        } else if (newIncludedResources.Contains(newResource)) {
[15559]400          newNode.Checked = true;
401          newNode.ForeColor = SystemColors.GrayText;
402        }
403
[17059]404        if (includedResources.Contains(newResource) && newIncludedResources.Contains(newResource)) {
[16117]405          newNode.Text += INCLUDED_TAG;
[15567]406        } else if (addedIncludes.Contains(newResource)) {
407          newNode.BackColor = addedIncludeColor;
408          newNode.ForeColor = SystemColors.GrayText;
[16117]409          newNode.Text += ADDED_INCLUDE_TAG;
[15567]410        } else if (removedIncludes.Contains(newResource)) {
411          newNode.BackColor = removedIncludeColor;
[16117]412          newNode.Text += REMOVED_INCLUDE_TAG;
[15559]413        }
414
[15567]415        if (addedAssignments.Contains(newResource)) {
416          newNode.BackColor = addedAssignmentColor;
417          newNode.ForeColor = SystemColors.ControlText;
[16117]418          newNode.Text += ADDED_ASSIGNMENT_TAG;
[15567]419        } else if (removedAssignments.Contains(newResource)) {
420          newNode.BackColor = removedAssignmentColor;
421          newNode.ForeColor = SystemColors.ControlText;
[16117]422          newNode.Text += REMOVED_ASSIGNMENT_TAG;
[15567]423        }
424
[15422]425        if (newResource is Slave) {
426          newNode.ImageIndex = slaveImageIndex;
427        } else {
428          newNode.ImageIndex = slaveGroupImageIndex;
429
[15559]430          var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
431          if (childResources.Any()) {
432            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
433              subResources.Remove(resource);
434              stack.Push(resource);
[15422]435            }
436            currentNode = newNode;
437            currentResource = newResource;
438          }
439        }
440        newNode.SelectedImageIndex = newNode.ImageIndex;
441      }
442
[17059]443      ExpandResourceNodesOfInterest(treeView.Nodes);
444
445      bool expandUngroupedGroupNode = false;
[15658]446      var ungroupedSlaves = subResources.OfType<Slave>().OrderBy(x => x.Name);
[17063]447      if (ungroupedSlaves.Any()) {
[16117]448        ungroupedGroupNode = new TreeNode(UNGROUPED_GROUP_NAME) {
[15658]449          ForeColor = SystemColors.GrayText,
450          Tag = new SlaveGroup() {
[16117]451            Name = UNGROUPED_GROUP_NAME,
452            Description = UNGROUPED_GROUP_DESCRIPTION
[15658]453          }
454        };
455
456        foreach (var slave in ungroupedSlaves) {
457          var slaveNode = new TreeNode(slave.Name) { Tag = slave };
[17059]458          if (newAssignedResources.Contains(slave)) {
459            slaveNode.Checked = true;
460            expandUngroupedGroupNode = true;
461          }
462
463          if (!HiveRoles.CheckAdminUserPermissions()) {
464            slaveNode.ForeColor = SystemColors.GrayText;
465            slaveNode.Text += IMMUTABLE_TAG;
466          } else {
467            if (addedAssignments.Contains(slave)) {
468              slaveNode.BackColor = addedAssignmentColor;
469              slaveNode.ForeColor = SystemColors.ControlText;
470              slaveNode.Text += ADDED_ASSIGNMENT_TAG;
471            } else if (removedAssignments.Contains(slave)) {
472              slaveNode.BackColor = removedAssignmentColor;
473              slaveNode.ForeColor = SystemColors.ControlText;
474              slaveNode.Text += REMOVED_ASSIGNMENT_TAG;
475              expandUngroupedGroupNode = true;
476            }
477          }
[16117]478          ungroupedGroupNode.Nodes.Add(slaveNode);
[15422]479        }
[17059]480
[17063]481        if (expandUngroupedGroupNode) ungroupedGroupNode.Expand();
[16117]482        treeView.Nodes.Add(ungroupedGroupNode);
483      } else if (ungroupedGroupNode != null) {
484        ungroupedGroupNode.Nodes.Clear();
[15422]485      }
486
487      treeView.BeforeCheck += treeView_BeforeCheck;
[17063]488      treeView.AfterCheck += treeView_AfterCheck;
[15422]489
490      return top;
491    }
[15559]492
[16117]493    private void ExpandResourceNodesOfInterest(TreeNodeCollection nodes) {
494      foreach (TreeNode n in nodes) {
495        Resource r = (Resource)n.Tag;
496        if (n.Nodes.Count > 0) {
497          if (HiveAdminClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()) {
498            n.Expand();
499            ExpandResourceNodesOfInterest(n.Nodes);
[15658]500          } else {
[16117]501            n.Collapse();
[15658]502          }
[16117]503        } else {
504          n.Collapse();
[15658]505        }
506      }
507    }
508
[16117]509    private bool IsAdmin() {
510      return HiveRoles.CheckAdminUserPermissions();
511    }
512
[15422]513    #endregion
514  }
515}
Note: See TracBrowser for help on using the repository browser.