Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs	(revision 15813)
@@ -216,4 +216,5 @@
 
     private static IEnumerable<UserGroupBase> GetGrantedPermissionsForProject(Guid projectId) {
+      if (projectId == Guid.Empty) return Enumerable.Empty<UserGroupBase>();
       var projectPermissions = HiveServiceLocator.Instance.CallHiveService(s => s.GetProjectPermissions(projectId));
       var userIds = new HashSet<Guid>(projectPermissions.Select(x => x.GrantedUserId));
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs	(revision 15813)
@@ -170,4 +170,5 @@
 
     private static IEnumerable<Resource> GetAssignedResourcesForProject(Guid projectId) {
+      if (projectId == Guid.Empty) return Enumerable.Empty<Resource>();
       var assignedProjectResources = HiveServiceLocator.Instance.CallHiveService(s => s.GetAssignedResourcesForProjectAdministration(projectId));
       return HiveAdminClient.Instance.Resources.Where(x => assignedProjectResources.Select(y => y.ResourceId).Contains(x.Id));
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 15813)
@@ -40,7 +40,10 @@
     private const int greenFlagImageIndex = 0;
     private const int redFlagImageIndex = 1;
-
-    private readonly Color changedColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
-    private readonly Color selectedColor = Color.FromArgb(255, 240, 194, 59); // #f0c23b
+    private const string SELECTED_TAG = ""; // " [selected]";
+    private const string NOT_STORED_TAG = "**"; // " [not stored]";
+    private const string CHANGES_NOT_STORED_TAG = "*"; // " [changes not stored]";
+
+    private readonly Color selectedBackColor = Color.DodgerBlue;
+    private readonly Color selectedForeColor = Color.White;
 
     private Project selectedProject = null;
@@ -222,16 +225,5 @@
       }
 
-      if(!IsAdmin() 
-        && HiveAdminClient.Instance.CheckOwnershipOfParentProject(selectedProject, 
-          UserInformation.Instance.User.Id)) {
-        MessageBox.Show(
-          "Only subprojects of owned projects can be deleted.",
-          "HeuristicLab Hive Administrator",
-          MessageBoxButtons.OK,
-          MessageBoxIcon.Error);
-        return;
-      }
-
-      if (!IsAdmin() && Content.Any(x => x.ParentProjectId == selectedProject.Id)) {
+      if (Content.Any(x => x.ParentProjectId == selectedProject.Id)) {
         MessageBox.Show(
           "Only empty projects can be deleted.",
@@ -387,6 +379,7 @@
         }
         if (newProject.Id == selectedProject.Id && !nodeSelected) {
-          newNode.BackColor = selectedColor;
-          newNode.Text += " [selected]";
+          newNode.BackColor = selectedBackColor;
+          newNode.ForeColor = selectedForeColor;
+          newNode.Text += SELECTED_TAG;
           nodeSelected = true;
         }
@@ -430,7 +423,7 @@
 
       if (p.Id == Guid.Empty) {
-        n.Text += " [not stored]";
+        n.Text += NOT_STORED_TAG;
       } else if (p.Modified) {
-        n.Text += " [changes not stored]";
+        n.Text += CHANGES_NOT_STORED_TAG;
       }
     }
@@ -450,6 +443,13 @@
       projectResourcesView.Content = project;
 
-      bool locked = project == null || (project != null && project.Id == Guid.Empty);
+      bool projectIsNew = project != null && project.Id == Guid.Empty;
+      bool locked = project == null || projectIsNew;
+      bool deleteEnabled = project != null && (
+        projectIsNew
+        || HiveAdminClient.Instance.CheckOwnershipOfParentProject(project, UserInformation.Instance.User.Id)
+        || !HiveAdminClient.Instance.ProjectDescendants[project.Id].Any());
+
       addButton.Enabled = !locked;
+      removeButton.Enabled = deleteEnabled;
       projectPermissionsView.Locked = locked;
       projectResourcesView.Locked = locked;
@@ -461,6 +461,7 @@
       SelectedProject = (Project)projectNode.Tag;
       ResetTreeNodes(projectsTreeView.Nodes);
-      projectNode.BackColor = selectedColor;
-      projectNode.Text += " [selected]";
+      projectNode.BackColor = selectedBackColor;
+      projectNode.ForeColor = selectedForeColor;
+      projectNode.Text += SELECTED_TAG;
     }
 
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs	(revision 15813)
@@ -149,4 +149,5 @@
             | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
+      this.treeView.CheckBoxes = true;
       this.treeView.ImageIndex = 0;
       this.treeView.ImageList = this.imageListSlaveGroups;
@@ -162,5 +163,5 @@
       this.treeView.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeSlaveGroup_DragEnterOver);
       this.treeView.DragOver += new System.Windows.Forms.DragEventHandler(this.treeSlaveGroup_DragEnterOver);
-      this.treeView.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.treeSlaveGroup_QueryContinueDrag);
+      this.treeView.BeforeCheck += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeSlaveGroup_BeforeCheck);
       // 
       // tabSlaveGroup
@@ -176,4 +177,6 @@
       this.tabSlaveGroup.Size = new System.Drawing.Size(585, 541);
       this.tabSlaveGroup.TabIndex = 1;
+      //this.tabSlaveGroup.TabIndexChanged += TabSlaveGroup_TabIndexChanged;
+      this.tabSlaveGroup.Selected += TabSlaveGroup_Selected;
       // 
       // tabDetails
@@ -245,5 +248,4 @@
 
     }
-
     #endregion
 
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs	(revision 15813)
@@ -40,11 +40,19 @@
     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.";
+    public const string UNGROUPED_GROUP_NAME = "UNGROUPED";
+    public const string UNGROUPED_GROUP_DESCRIPTION = "Contains slaves that are not assigned to any group.";
+    private const string SELECTED_TAG = ""; // " [selected]";
+    private const string NOT_STORED_TAG = "**"; // " [not stored]";
+    private const string CHANGES_NOT_STORED_TAG = "*"; // " [changes not stored]";
 
     private readonly Color changedColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
-    private readonly Color selectedColor = Color.FromArgb(255, 240, 194, 59); // #f0c23b
+    private readonly Color selectedBackColor = Color.DodgerBlue;
+    private readonly Color selectedForeColor = Color.White;
     private readonly Color calculatingColor = Color.FromArgb(255, 58, 114, 35); // #3a7223
     private readonly Color offlineColor = Color.FromArgb(255, 187, 36, 36); // #bb2424
+
+
+
+    private TreeNode ungroupedGroupNode;
 
     private Resource selectedResource = null;
@@ -107,9 +115,15 @@
     protected override void SetEnabledStateOfControls() {
       base.SetEnabledStateOfControls();
-      bool enabled = Content != null && !Locked && !ReadOnly && IsAdmin();
-      btnAddGroup.Enabled = enabled;
-      btnRemoveGroup.Enabled = enabled;
-      btnSave.Enabled = enabled;
-      scheduleView.SetEnabledStateOfSchedule(enabled && IsAdmin());
+
+      bool locked = Content == null || Locked || ReadOnly || !IsAdmin();
+      bool scheduleLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty);
+      bool addLocked = locked || (selectedResource != null && selectedResource.Id == Guid.Empty) || selectedResource is Slave;
+
+      btnAddGroup.Enabled = !addLocked;
+      btnRemoveGroup.Enabled = !locked;
+      btnSave.Enabled = !locked;
+      viewHost.Locked = locked;
+      scheduleView.Locked = locked;
+      scheduleView.SetEnabledStateOfSchedule(!scheduleLocked);
     }
     #endregion
@@ -284,5 +298,5 @@
     private void treeSlaveGroup_MouseDown(object sender, MouseEventArgs e) {
       var node = treeView.GetNodeAt(e.Location);
-      if(node != null && !node.Text.StartsWith(ungroupedGroupName)) ChangeSelectedResourceNode(node);
+      if(node != null && node != ungroupedGroupNode /*!node.Text.StartsWith(UNGROUPED_GROUP_NAME)*/) ChangeSelectedResourceNode(node);
     }
 
@@ -291,76 +305,82 @@
     }
 
+    private void treeSlaveGroup_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
+      if(e.Node == ungroupedGroupNode) {
+        e.Cancel = true;
+      }
+    }
+
     private void treeSlaveGroup_DragDrop(object sender, DragEventArgs e) {
       if (e.Effect == DragDropEffects.None) return;
 
-      var sourceNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
-      if (sourceNode == null) return;
-      var sourceResource = ((Resource)sourceNode.Tag);
-      if (sourceResource == null) return;
-
-      var treeView = (TreeView)sender;
-      if (sourceNode.TreeView != treeView) return;
-
-      var targetPoint = treeView.PointToClient(new Point(e.X, e.Y));
-      var targetNode = treeView.GetNodeAt(targetPoint);
-
+      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
       var targetResource = (targetNode != null) ? (Resource)targetNode.Tag : null;
-
-      if(!HiveAdminClient.Instance.CheckParentChange(sourceResource, targetResource)) {
-        MessageBox.Show(
-          "You cannot drag resources to this group.",
-          "HeuristicLab Hive Administrator",
-          MessageBoxButtons.OK,
-          MessageBoxIcon.Information);
-        return;
-      }
-
-      if (sourceNode.Parent == null)
-        treeView.Nodes.Remove(sourceNode);
-      else {
-        sourceNode.Parent.Nodes.Remove(sourceNode);
-        sourceResource.ParentResourceId = null;
-      }
-
-      if (targetNode == null) {
-        treeView.Nodes.Add(sourceNode);
-      } else if(targetResource.Id != Guid.Empty) {
-        targetNode.Nodes.Add(sourceNode);
-        sourceResource.ParentResourceId = targetResource.Id;
+      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
+
+      foreach(var r in resources) {
+        r.ParentResourceId = targetResource?.Id;
       }
 
       HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
-      SelectedResource = sourceResource;
       OnContentChanged();
     }
 
     private void treeSlaveGroup_ItemDrag(object sender, ItemDragEventArgs e) {
+      if (!IsAdmin()) return;
+
+      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
       TreeNode sourceNode = (TreeNode)e.Item;
-      if (IsAdmin())
-        DoDragDrop(sourceNode, DragDropEffects.All);
+      if(!sourceNode.Checked) nodes.Add(sourceNode);
+      nodes.Remove(ungroupedGroupNode);
+      ungroupedGroupNode.Checked = false;
+      var resources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
+
+      if(resources.Count > 0) {
+        DataObject data = new DataObject();
+        data.SetData(HeuristicLab.Common.Constants.DragDropDataFormat, resources);
+        var action = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
+        if(action.HasFlag(DragDropEffects.Move)) {
+          foreach (var node in nodes) node.Remove();
+          StyleTreeNode(ungroupedGroupNode, (Resource)ungroupedGroupNode.Tag, resources);
+        }
+      }
+    }
+
+    private IEnumerable<TreeNode> GetCheckedNodes(TreeNodeCollection nodes) {
+      if (nodes != null) {
+        foreach (var node in nodes.OfType<TreeNode>()) {
+          if (node.Checked && node != ungroupedGroupNode) yield return node;
+            foreach (var child in GetCheckedNodes(node.Nodes))
+              yield return child;
+          }
+      }
     }
 
     private void treeSlaveGroup_DragEnterOver(object sender, DragEventArgs e) {
       e.Effect = DragDropEffects.Move;
-
-      var sourceNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
-      var sourceResource = ((Resource)sourceNode.Tag);
-
-      var targetPoint = treeView.PointToClient(new Point(e.X, e.Y));
-      var targetNode = treeView.GetNodeAt(targetPoint);
-      var targetResource = (targetNode != null) ? (Resource)targetNode.Tag : null;
+      var resources = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat) as IEnumerable<Resource>;
+      var targetNode = treeView.GetNodeAt(treeView.PointToClient(new Point(e.X, e.Y)));
+      var targetResource = targetNode?.Tag as Resource;
 
       if(!IsAdmin() 
-        || sourceNode == null 
-        || sourceResource == null 
-        || sourceNode == targetNode
-        || !HiveAdminClient.Instance.CheckParentChange(sourceResource, targetResource)
-        || (targetNode != null && (targetNode.Text.StartsWith(ungroupedGroupName) || targetNode.Parent != null && targetNode.Parent.Text.StartsWith(ungroupedGroupName)))) {
+        || resources == null
+        || !resources.Any()
+        || resources.Any(x => !HiveAdminClient.Instance.CheckParentChange(x, targetResource))
+        || (targetNode != null && (targetNode == ungroupedGroupNode || targetNode.Parent == ungroupedGroupNode))) {
         e.Effect = DragDropEffects.None;
       }
     }
 
-    private void treeSlaveGroup_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) {
-      e.Action = DragAction.Continue;
+    private void TabSlaveGroup_TabIndexChanged(object sender, EventArgs e) {
+      throw new NotImplementedException();
+    }
+
+    private async void TabSlaveGroup_Selected(object sender, System.Windows.Forms.TabControlEventArgs e) {
+      if(e.TabPage == tabSchedule) {
+        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
+          action: () => UpdateSchedule(),
+          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
+      }
+      SetEnabledStateOfControls();
     }
     #endregion
@@ -394,6 +414,7 @@
         }
         if (newResource.Id == selectedResource.Id && !nodeSelected) {
-          newNode.BackColor = selectedColor;
-          newNode.Text += " [selected]";
+          newNode.BackColor = selectedBackColor;
+          newNode.ForeColor = selectedForeColor;
+          newNode.Text += SELECTED_TAG;
           nodeSelected = true;
         }
@@ -427,18 +448,21 @@
       }
 
-      var ungroupedNode = new TreeNode(ungroupedGroupName) {
+      // collapse slave-only nodes
+      foreach(TreeNode n in treeView.Nodes) {
+        CollapseSlaveOnlyNodes(n);
+      }
+      
+      ungroupedGroupNode = new TreeNode(UNGROUPED_GROUP_NAME) {
         ForeColor = SystemColors.GrayText,
         Tag = new SlaveGroup() {
-          Name = ungroupedGroupName,
-          Description = ungroupedGroupDescription
+          Name = UNGROUPED_GROUP_NAME,
+          Description = UNGROUPED_GROUP_DESCRIPTION
         }
       };
 
-      int ungroupedSlavesCount = 0;
       foreach (var slave in subResources.OfType<Slave>().OrderBy(x => x.Name)) {
         var slaveNode = new TreeNode(slave.Name) { Tag = slave };
         StyleTreeNode(slaveNode, slave, resources);
-        ungroupedNode.Nodes.Add(slaveNode);
-        ungroupedSlavesCount++;
+        ungroupedGroupNode.Nodes.Add(slaveNode);
         if (selectedResource == null) {
           SelectedResource = slave;
@@ -446,15 +470,29 @@
 
         if (slave.Id == selectedResource.Id && !nodeSelected) {
-          slaveNode.BackColor = selectedColor;
-          slaveNode.Text += " [selected]";
+          slaveNode.BackColor = selectedBackColor;
+          slaveNode.ForeColor = selectedForeColor;
+          slaveNode.Text += SELECTED_TAG;
           nodeSelected = true;
         }
       }
 
-      if (ungroupedSlavesCount > 0)
-        ungroupedNode.Text += " [" + ungroupedSlavesCount.ToString() + "]";
-      treeView.Nodes.Add(ungroupedNode);
-      treeView.ExpandAll();
-      
+      if (ungroupedGroupNode.Nodes.Count > 0) {
+        ungroupedGroupNode.Text += " [" + ungroupedGroupNode.Nodes.Count.ToString() + "]";
+        ungroupedGroupNode.Expand();
+      }
+      treeView.Nodes.Add(ungroupedGroupNode);      
+    }
+
+    private void CollapseSlaveOnlyNodes(TreeNode tn) {
+      Resource r = (Resource)tn.Tag;
+      var descendants = HiveAdminClient.Instance.ResourceDescendants;
+      if(descendants.ContainsKey(r.Id)) {
+        if(descendants[r.Id].OfType<SlaveGroup>().Any()) {
+          tn.Expand();
+          foreach (TreeNode n in tn.Nodes) CollapseSlaveOnlyNodes(n);
+        } else {
+          tn.Collapse();
+        }
+      }
     }
 
@@ -511,4 +549,11 @@
       n.BackColor = Color.Transparent;
       n.ForeColor = Color.Black;
+
+      // not stored (i.e. new), changed
+      if (r.Id == Guid.Empty && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
+        n.Text += NOT_STORED_TAG;
+      } else if (r.Modified && n != ungroupedGroupNode /*!r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
+        n.Text += CHANGES_NOT_STORED_TAG;
+      }
 
       // slave count
@@ -523,5 +568,5 @@
             .Count();
         }
-      } else if(r.Name.StartsWith(ungroupedGroupName)) {
+      } else if(n == ungroupedGroupNode /*|| r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
         childSlavesCount = resources
           .OfType<Slave>()
@@ -549,13 +594,6 @@
       }
 
-      // not stored (i.e. new), changed
-      if (r.Id == Guid.Empty && !r.Name.StartsWith(ungroupedGroupName)) {
-        n.Text += " [not stored]";
-      } else if (r.Modified && !r.Name.StartsWith(ungroupedGroupName)) {
-        n.Text += " [changes not stored]";
-      }
-
       // ungrouped
-      if(r.Name.StartsWith(ungroupedGroupName)) {
+      if(n == ungroupedGroupNode /*r.Name.StartsWith(UNGROUPED_GROUP_NAME)*/) {
         n.ForeColor = ForeColor = SystemColors.GrayText;
       }
@@ -574,19 +612,13 @@
       selectedResource = resource;
       viewHost.Content = selectedResource;
+
       HiveAdminClient.Instance.DowntimeForResourceId = selectedResource != null ? selectedResource.Id : Guid.Empty;
-      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
-        action: () => UpdateSchedule(),
-        finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
-
-      bool locked = !IsAdmin() || resource == null;
-      bool scheduleLocked = locked || (resource != null && resource.Id == Guid.Empty);
-      bool addLocked = locked || (resource != null && resource.Id == Guid.Empty) || resource is Slave;
-
-      btnAddGroup.Enabled = !addLocked;
-      btnRemoveGroup.Enabled = !locked;
-      btnSave.Enabled = !locked;
-      viewHost.Locked = locked;
-      scheduleView.Locked = locked;
-      scheduleView.SetEnabledStateOfSchedule(!scheduleLocked);
+      if (tabSlaveGroup.SelectedTab == tabSchedule) {
+        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
+          action: () => UpdateSchedule(),
+          finallyCallback: () => scheduleView.Content = HiveAdminClient.Instance.Downtimes);
+      }
+
+      SetEnabledStateOfControls();
     }
 
@@ -595,6 +627,7 @@
       SelectedResource = (Resource)resourceNode.Tag;
       ResetTreeNodes(treeView.Nodes, Content);
-      resourceNode.BackColor = selectedColor;
-      resourceNode.Text += " [selected]";
+      resourceNode.BackColor = selectedBackColor;
+      resourceNode.ForeColor = selectedForeColor;
+      resourceNode.Text += SELECTED_TAG;
     }
 
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs	(revision 15792)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs	(revision 15813)
@@ -235,5 +235,5 @@
       } else {
         if (Content == null || Locked || ReadOnly) state = false;
-        groupBox1.Enabled = state;
+        //groupBox1.Enabled = state;
         btnClearCal.Enabled = state;
         btnSaveCal.Enabled = state;
