#region License Information /* HeuristicLab * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using HeuristicLab.Clients.Access; using HeuristicLab.Common.Resources; using HeuristicLab.Core.Views; using HeuristicLab.MainForm; namespace HeuristicLab.Clients.Hive.Administrator.Views { [View("ProjectView")] [Content(typeof(Project), IsDefaultView = false)] public partial class ProjectResourcesView : ItemView { private const int slaveImageIndex = 0; private const int slaveGroupImageIndex = 1; public const string ungroupedGroupName = "UNGROUPED"; public const string ungroupedGroupDescription = "Contains slaves that are not assigned to any group."; private readonly HashSet assignedResources = new HashSet(); private readonly HashSet inheritedResources = new HashSet(); private readonly Color ownedResourceColor = Color.LightGreen; public new Project Content { get { return (Project)base.Content; } set { base.Content = value; } } public ProjectResourcesView() { InitializeComponent(); treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge); treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge); } #region Overrides protected override void OnContentChanged() { base.OnContentChanged(); if (Content == null) { assignedResources.Clear(); inheritedResources.Clear(); treeView.Nodes.Clear(); detailsViewHost.Content = null; } else { UpdateAssignedResources(); UpdateInheritedResources(); var top = BuildResourceTree(HiveAdminClient.Instance.Resources); detailsViewHost.Content = top; } } #endregion #region Event Handlers private void ProjectResourcesView_Load(object sender, EventArgs e) { } private void refreshButton_Click(object sender, EventArgs e) { UpdateAssignedResources(); UpdateInheritedResources(); var top = BuildResourceTree(HiveAdminClient.Instance.Resources); detailsViewHost.Content = top; } private void inheritButton_Click(object sender, EventArgs e) { SetAssignedProjectResources(Content.Id, Enumerable.Empty()); UpdateAssignedResources(); UpdateInheritedResources(); var top = BuildResourceTree(HiveAdminClient.Instance.Resources); detailsViewHost.Content = top; } private async void saveButton_Click(object sender, EventArgs e) { await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions( action: () => SetAssignedProjectResources(Content.Id, assignedResources.Select(x => x.Id))); } private void treeView_AfterSelect(object sender, TreeViewEventArgs e) { var selectedResource = (Resource)e.Node.Tag; detailsViewHost.Content = selectedResource; } private void treeView_BeforeCheck(object sender, TreeViewCancelEventArgs e) { var checkedResource = (Resource)e.Node.Tag; if (inheritedResources.Contains(checkedResource) || checkedResource.Id == Guid.Empty) e.Cancel = true; } private void treeView_AfterCheck(object sender, TreeViewEventArgs e) { var checkedResource = (Resource)e.Node.Tag; if (e.Node.Checked) assignedResources.Add(checkedResource); else assignedResources.Remove(checkedResource); } #endregion #region Helpers private static IEnumerable GetAssignedResourcesForProject(Guid projectId) { var assignedProjectResources = HiveServiceLocator.Instance.CallHiveService(s => s.GetAssignedResourcesForProject(projectId)); var resourceIds = new HashSet(assignedProjectResources.Select(x => x.ResourceId)); return HiveAdminClient.Instance.Resources.Where(x => resourceIds.Contains(x.Id)); } private static void SetAssignedProjectResources(Guid projectId, IEnumerable resourceIds) { HiveServiceLocator.Instance.CallHiveService(s => { var currentlyAssignedResources = s.GetAssignedResourcesForProject(projectId); s.UnassignProjectResources(projectId, currentlyAssignedResources.Select(x => x.ResourceId).ToList()); s.AssignProjectResources(projectId, resourceIds.ToList()); }); } private void UpdateAssignedResources() { assignedResources.Clear(); foreach (var r in GetAssignedResourcesForProject(Content.Id)) assignedResources.Add(r); } private void UpdateInheritedResources() { inheritedResources.Clear(); var parentProject = HiveAdminClient.Instance.Projects.SingleOrDefault(x => x.Id == Content.ParentProjectId); while (parentProject != null) { foreach (var r in GetAssignedResourcesForProject(parentProject.Id)) inheritedResources.Add(r); parentProject = HiveAdminClient.Instance.Projects.SingleOrDefault(x => x.Id == parentProject.ParentProjectId); } } private Resource BuildResourceTree(IEnumerable resources) { treeView.Nodes.Clear(); if (!resources.Any()) return null; treeView.BeforeCheck -= treeView_BeforeCheck; treeView.AfterCheck -= treeView_AfterCheck; var slaveGroups = new HashSet(resources.OfType()); var slaves = new HashSet(resources.OfType()); var stack = new Stack(slaveGroups.OrderByDescending(x => x.Name)); var top = stack.Peek(); TreeNode currentNode = null; Resource currentResource = null; while (stack.Any()) { var newResource = stack.Pop(); var newNode = new TreeNode(newResource.Name) { Tag = newResource }; while (currentNode != null && newResource.ParentResourceId != currentResource.Id) { currentNode = currentNode.Parent; currentResource = currentNode == null ? null : (Resource)currentNode.Tag; } if (currentNode == null) { treeView.Nodes.Add(newNode); } else { currentNode.Nodes.Add(newNode); } if (newResource is Slave) { newNode.ImageIndex = slaveImageIndex; } else { newNode.ImageIndex = slaveGroupImageIndex; var childSlaves = slaves.Where(x => x.ParentResourceId == newResource.Id); foreach (var slave in childSlaves.OrderBy(x => x.Name)) { slaves.Remove(slave); var slaveNode = new TreeNode(slave.Name) { Tag = slave }; slaveNode.SelectedImageIndex = slaveNode.ImageIndex = slaveImageIndex; if (slave.OwnerUserId == UserInformation.Instance.User.Id) slaveNode.BackColor = ownedResourceColor; if (inheritedResources.Contains(slave)) { slaveNode.Checked = true; slaveNode.Text += " (Inherited)"; slaveNode.ForeColor = SystemColors.GrayText; } else if (assignedResources.Contains(slave)) slaveNode.Checked = true; newNode.Nodes.Add(slaveNode); } var childSlaveGroups = slaveGroups.Where(x => x.ParentResourceId == newResource.Id); if (childSlaveGroups.Any()) { foreach (var slaveGroup in childSlaveGroups.OrderByDescending(x => x.Name)) { slaveGroups.Remove(slaveGroup); stack.Push(slaveGroup); } currentNode = newNode; currentResource = newResource; } } newNode.SelectedImageIndex = newNode.ImageIndex; if (newResource.OwnerUserId == UserInformation.Instance.User.Id) newNode.BackColor = ownedResourceColor; if (inheritedResources.Contains(newResource)) { newNode.Checked = true; newNode.Text += " (Inherited)"; newNode.ForeColor = SystemColors.GrayText; } else if (assignedResources.Contains(newResource)) newNode.Checked = true; } var ungroupedNode = new TreeNode(ungroupedGroupName) { ForeColor = SystemColors.GrayText, Tag = new SlaveGroup() { Name = ungroupedGroupName, Description = ungroupedGroupDescription } }; foreach (var slave in slaves.OrderBy(x => x.Name)) { var slaveNode = new TreeNode(slave.Name) { Tag = slave }; ungroupedNode.Nodes.Add(slaveNode); } treeView.Nodes.Add(ungroupedNode); treeView.BeforeCheck += treeView_BeforeCheck; treeView.AfterCheck += treeView_AfterCheck; treeView.ExpandAll(); return top; } #endregion } }