Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2892_LR-prediction-intervals/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs @ 16388

Last change on this file since 16388 was 16388, checked in by gkronber, 5 years ago

#2892: Merging r15750:16382 (HEAD) from trunk to branch, resolving conflicts

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