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 15791)
+++ /branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 15792)
@@ -250,5 +250,7 @@
       if (result == DialogResult.Yes) {
         await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
-          action: () => RemoveProject(selectedProject),
+          action: () => {
+            RemoveProject(selectedProject);  
+          },
           finallyCallback: () => {
             removeButton.Enabled = true;
@@ -358,45 +360,4 @@
 
     #region Helpers
-    private void ResetTreeNodes(TreeNodeCollection nodes, Color c1, Color c2, bool resetText) {
-      foreach (TreeNode n in nodes) {
-        var pro = ((Project)n.Tag);
-        if (n.BackColor.Equals(c1)) {
-          n.BackColor = c2;
-        }
-        if (resetText) {
-          n.Text = pro.Name;
-
-          if (pro.Id == Guid.Empty) {
-            n.Text += " [not stored]";
-          } else if (pro.Modified) {
-            n.Text += " [changes not stored]";
-          }
-        }
-        if (n.Nodes.Count > 0) {
-          ResetTreeNodes(n.Nodes, c1, c2, resetText);
-        }
-      }
-    }
-
-    private void ChangeSelectedProject(Project project) {
-      projectView.Content = project;
-      projectPermissionsView.Content = project;
-      projectResourcesView.Content = project;
-
-      bool locked = project == null || (project != null && project.Id == Guid.Empty);
-      addButton.Enabled = !locked;
-      projectPermissionsView.Locked = locked;
-      projectResourcesView.Locked = locked;
-      selectedProject = project;
-    }
-
-    private void ChangeSelectedProjectNode(TreeNode projectNode) {
-      if (projectNode == null) return;
-      SelectedProject = (Project)projectNode.Tag;
-      ResetTreeNodes(projectsTreeView.Nodes, selectedColor, Color.Transparent, true);
-      projectNode.BackColor = selectedColor;
-      projectNode.Text += " [selected]";
-    }
-
     private void BuildProjectTree(IEnumerable<Project> projects) {
       projectsTreeView.Nodes.Clear();
@@ -407,5 +368,5 @@
         .Where(x => x.ParentProjectId.HasValue
         && !projects.Select(y => y.Id).Contains(x.ParentProjectId.Value)));
-            mainProjects.UnionWith(parentedMainProjects);
+      mainProjects.UnionWith(parentedMainProjects);
       var subProbjects = new HashSet<Project>(projects.Except(mainProjects));
 
@@ -416,14 +377,10 @@
       TreeNode currentNode = null;
       Project currentProject = null;
-      
+
       while (stack.Any()) {
         var newProject = stack.Pop();
         var newNode = new TreeNode(newProject.Name) { Tag = newProject };
-
-        if (newProject.Id == Guid.Empty) {
-          newNode.Text += " [not stored]";
-        } else if(newProject.Modified) {
-          newNode.Text += " [changes not stored]";
-        }
+        StyleTreeNode(newNode, newProject);
+      
         if (selectedProject == null) {
           SelectedProject = newProject;
@@ -467,4 +424,45 @@
     }
 
+    private void StyleTreeNode(TreeNode n, Project p) {
+      n.Text = p.Name;
+      n.BackColor = Color.Transparent;
+      n.ForeColor = Color.Black;
+
+      if (p.Id == Guid.Empty) {
+        n.Text += " [not stored]";
+      } else if (p.Modified) {
+        n.Text += " [changes not stored]";
+      }
+    }
+
+    private void ResetTreeNodes(TreeNodeCollection nodes) {
+      foreach (TreeNode n in nodes) {
+        StyleTreeNode(n, (Project)n.Tag);
+        if (n.Nodes.Count > 0) {
+          ResetTreeNodes(n.Nodes);
+        }
+      }
+    }
+
+    private void ChangeSelectedProject(Project project) {
+      projectView.Content = project;
+      projectPermissionsView.Content = project;
+      projectResourcesView.Content = project;
+
+      bool locked = project == null || (project != null && project.Id == Guid.Empty);
+      addButton.Enabled = !locked;
+      projectPermissionsView.Locked = locked;
+      projectResourcesView.Locked = locked;
+      selectedProject = project;
+    }
+
+    private void ChangeSelectedProjectNode(TreeNode projectNode) {
+      if (projectNode == null) return;
+      SelectedProject = (Project)projectNode.Tag;
+      ResetTreeNodes(projectsTreeView.Nodes);
+      projectNode.BackColor = selectedColor;
+      projectNode.Text += " [selected]";
+    }
+
     private void UpdateProjects() {
       try {
@@ -480,6 +478,13 @@
 
       try {
-        if(project.Id != Guid.Empty) HiveAdminClient.Delete(project);
-        Content.Remove(selectedProject);
+        if (project.Id != Guid.Empty) {
+          var projectsToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
+          foreach (var p in projectsToSave)
+            p.Store();
+          HiveAdminClient.Delete(project);
+          UpdateProjects();
+        } else {
+          Content.Remove(project);
+        }
       } catch (AnonymousUserException) {
         ShowHiveInformationDialog();
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 15791)
+++ /branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs	(revision 15792)
@@ -45,4 +45,6 @@
     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 calculatingColor = Color.FromArgb(255, 58, 114, 35); // #3a7223
+    private readonly Color offlineColor = Color.FromArgb(255, 187, 36, 36); // #bb2424
 
     private Resource selectedResource = null;
@@ -215,4 +217,5 @@
       };
 
+      HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
       SelectedResource = group;
       Content.Add(group);
@@ -252,6 +255,8 @@
       if (result == DialogResult.Yes) {
         await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
-          action: () => RemoveResource(selectedResource),
-          finallyCallback: () => {
+          action: () => {
+            RemoveResource(selectedResource);
+          },
+          finallyCallback: () => { 
             btnRemoveGroup.Enabled = true;
           });
@@ -279,5 +284,5 @@
     private void treeSlaveGroup_MouseDown(object sender, MouseEventArgs e) {
       var node = treeView.GetNodeAt(e.Location);
-      if(node != null && node.Name != ungroupedGroupName) ChangeSelectedResourceNode(node);
+      if(node != null && !node.Text.StartsWith(ungroupedGroupName)) ChangeSelectedResourceNode(node);
     }
 
@@ -325,4 +330,5 @@
       }
 
+      HiveAdminClient.Instance.UpdateResourceGenealogy(Content);
       SelectedResource = sourceResource;
       OnContentChanged();
@@ -350,5 +356,5 @@
         || sourceNode == targetNode
         || !HiveAdminClient.Instance.CheckParentChange(sourceResource, targetResource)
-        || (targetNode != null && (targetNode.Text == ungroupedGroupName || targetNode.Parent != null && targetNode.Parent.Text == ungroupedGroupName))) {
+        || (targetNode != null && (targetNode.Text.StartsWith(ungroupedGroupName) || targetNode.Parent != null && targetNode.Parent.Text.StartsWith(ungroupedGroupName)))) {
         e.Effect = DragDropEffects.None;
       }
@@ -361,25 +367,4 @@
 
     #region Helpers
-    private void ResetTreeNodes(TreeNodeCollection nodes, Color c1, Color c2, bool resetText) {
-      foreach (TreeNode n in nodes) {
-        var res = ((Resource)n.Tag);
-        if (n.BackColor.Equals(c1)) {
-          n.BackColor = c2;
-        }
-        if (resetText) {
-          n.Text = res.Name;
-
-          if (res.Id == Guid.Empty && res.Name != ungroupedGroupName) {
-            n.Text += " [not stored]";
-          } else if (res.Modified && res.Name != ungroupedGroupName) {
-            n.Text += " [changes not stored]";
-          }
-        }
-        if (n.Nodes.Count > 0) {
-          ResetTreeNodes(n.Nodes, c1, c2, resetText);
-        }
-      }
-    }
-
     private void BuildResourceTree(IEnumerable<Resource> resources) {
       treeView.Nodes.Clear();
@@ -400,13 +385,9 @@
       Resource currentResource = null;
 
-      while(stack.Any()) {
+      while (stack.Any()) {
         var newResource = stack.Pop();
         var newNode = new TreeNode(newResource.Name) { Tag = newResource };
-
-        if(newResource.Id == Guid.Empty) {
-          newNode.Text += " [not stored]";
-        } else if(newResource.Modified) {
-          newNode.Text += " [changes not stored]";
-        }
+        StyleTreeNode(newNode, newResource, resources);
+
         if (selectedResource == null) {
           SelectedResource = newResource;
@@ -426,5 +407,5 @@
         }
 
-        if(currentNode == null) {
+        if (currentNode == null) {
           treeView.Nodes.Add(newNode);
         } else {
@@ -432,12 +413,8 @@
         }
 
-        if(newResource is Slave) {
-          newNode.ImageIndex = slaveImageIndex;
-        } else {
-          newNode.ImageIndex = slaveGroupImageIndex;
-
+        if (newResource is SlaveGroup) {
           var childResources = subResources.Where(x => x.ParentResourceId == newResource.Id);
-          if(childResources.Any()) {
-            foreach(var resource in childResources.OrderByDescending(x => x.Name)) {
+          if (childResources.Any()) {
+            foreach (var resource in childResources.OrderByDescending(x => x.Name)) {
               subResources.Remove(resource);
               stack.Push(resource);
@@ -448,6 +425,4 @@
         }
         newNode.SelectedImageIndex = newNode.ImageIndex;
-        //if (newResource.OwnerUserId == UserInformation.Instance.User.Id)
-        //  newNode.BackColor = ownedResourceColor;
       }
 
@@ -460,15 +435,14 @@
       };
 
+      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);
-        if(selectedResource == null) {
+        ungroupedSlavesCount++;
+        if (selectedResource == null) {
           SelectedResource = slave;
         }
-        if (slave.Id == Guid.Empty) {
-          slaveNode.Text += " [not stored]";
-        } else if (slave.Modified) {
-          slaveNode.Text += " [changes not stored]";
-        }
+
         if (slave.Id == selectedResource.Id && !nodeSelected) {
           slaveNode.BackColor = selectedColor;
@@ -478,6 +452,9 @@
       }
 
+      if (ungroupedSlavesCount > 0)
+        ungroupedNode.Text += " [" + ungroupedSlavesCount.ToString() + "]";
       treeView.Nodes.Add(ungroupedNode);
       treeView.ExpandAll();
+      
     }
 
@@ -488,34 +465,4 @@
           UpdateChildHbIntervall(r);
         }
-      }
-    }
-
-    private bool CheckParentsEqualsMovedNode(TreeNode dest, TreeNode movedNode) {
-      TreeNode tmp = dest;
-
-      while (tmp != null) {
-        if (tmp == movedNode) {
-          return true;
-        }
-        tmp = tmp.Parent;
-      }
-      return false;
-    }
-
-    private void ResetView() {
-      if (InvokeRequired) Invoke((Action)ResetView);
-      else {
-        treeView.Nodes.Clear();
-
-        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
-          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
-        }
-
-        viewHost.Content = null;
-        if (scheduleView.Content != null) {
-          scheduleView.Content.Clear();
-        }
-
-        HiveAdminClient.Instance.ResetDowntime();
       }
     }
@@ -534,6 +481,13 @@
 
       try {
-        if(resource.Id != Guid.Empty) HiveAdminClient.Delete(resource);
-        Content.Remove(selectedResource);
+        if (resource.Id != Guid.Empty) {
+          var resourcesToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
+          foreach (var r in resourcesToSave)
+            r.Store();
+          HiveAdminClient.Delete(resource);
+          UpdateResources();
+        } else {
+          Content.Remove(selectedResource);
+        }
       } catch(AnonymousUserException) {
         ShowHiveInformationDialog();
@@ -549,15 +503,70 @@
     }
 
-    private bool IsAuthorized(Resource resource) {
-      return resource != null
-          && resource.Name != ungroupedGroupName
-          //&& resource.Id != Guid.Empty
-          && UserInformation.Instance.UserExists
-          && (HiveRoles.CheckAdminUserPermissions()
-            || HiveAdminClient.Instance.CheckOwnershipOfResource(resource, UserInformation.Instance.User.Id));
-    }
-
     private bool IsAdmin() {
       return HiveRoles.CheckAdminUserPermissions();
+    }
+
+    private void StyleTreeNode(TreeNode n, Resource r, IEnumerable<Resource> resources) {
+      n.Text = r.Name;
+      n.BackColor = Color.Transparent;
+      n.ForeColor = Color.Black;
+
+      // slave count
+      int childSlavesCount = 0;
+      if (r.Id != Guid.Empty && r is SlaveGroup) {
+        var descendants = HiveAdminClient.Instance.ResourceDescendants;
+        if (descendants.ContainsKey(r.Id)) {
+          childSlavesCount = resources
+            .OfType<Slave>()
+            .Where(x => descendants[r.Id].Select(y => y.Id)
+            .Contains(x.Id))
+            .Count();
+        }
+      } else if(r.Name.StartsWith(ungroupedGroupName)) {
+        childSlavesCount = resources
+          .OfType<Slave>()
+          .Where(x => x.ParentResourceId == null 
+            || (x.ParentResourceId.HasValue && x.ParentResourceId.Value == Guid.Empty))
+          .Count();
+      }
+      if (childSlavesCount > 0)
+        n.Text += " [" + childSlavesCount.ToString() + "]";
+
+      // slave image index, state, utilization
+      if (r is Slave) {
+        n.ImageIndex = slaveImageIndex;
+        var s = r as Slave;
+        if (s.SlaveState == SlaveState.Calculating) {
+          n.ForeColor = calculatingColor;
+          n.Text += " [" + s.CpuUtilization.ToString("N2") + "%]";
+        } else if (s.SlaveState == SlaveState.Offline) {
+          n.ForeColor = offlineColor;
+          if (s.LastHeartbeat.HasValue)
+            n.Text += " [" + s.LastHeartbeat?.ToString("g") + "]";
+        }
+      } else {
+        n.ImageIndex = slaveGroupImageIndex;
+      }
+
+      // 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)) {
+        n.ForeColor = ForeColor = SystemColors.GrayText;
+      }
+    }
+
+    private void ResetTreeNodes(TreeNodeCollection nodes, IEnumerable<Resource> resources) {
+      foreach (TreeNode n in nodes) {
+        StyleTreeNode(n, (Resource)n.Tag, resources);
+        if (n.Nodes.Count > 0) {
+          ResetTreeNodes(n.Nodes, resources);
+        }
+      }
     }
 
@@ -571,5 +580,6 @@
 
       bool locked = !IsAdmin() || resource == null;
-      bool addLocked = locked || (resource != null && resource.Id == Guid.Empty);
+      bool scheduleLocked = locked || (resource != null && resource.Id == Guid.Empty);
+      bool addLocked = locked || (resource != null && resource.Id == Guid.Empty) || resource is Slave;
 
       btnAddGroup.Enabled = !addLocked;
@@ -578,5 +588,5 @@
       viewHost.Locked = locked;
       scheduleView.Locked = locked;
-      scheduleView.SetEnabledStateOfSchedule(!addLocked);
+      scheduleView.SetEnabledStateOfSchedule(!scheduleLocked);
     }
 
@@ -584,5 +594,5 @@
       if (resourceNode == null) return;
       SelectedResource = (Resource)resourceNode.Tag;
-      ResetTreeNodes(treeView.Nodes, selectedColor, Color.Transparent, true);
+      ResetTreeNodes(treeView.Nodes, Content);
       resourceNode.BackColor = selectedColor;
       resourceNode.Text += " [selected]";
@@ -597,4 +607,23 @@
       }
     }
+
+    private void ResetView() {
+      if (InvokeRequired) Invoke((Action)ResetView);
+      else {
+        treeView.Nodes.Clear();
+
+        if (viewHost.Content != null && viewHost.Content is SlaveGroup) {
+          ((SlaveGroup)viewHost.Content).PropertyChanged -= SlaveViewContent_PropertyChanged;
+        }
+
+        viewHost.Content = null;
+        if (scheduleView.Content != null) {
+          scheduleView.Content.Clear();
+        }
+
+        HiveAdminClient.Instance.ResetDowntime();
+      }
+    }
+
     #endregion
   }
Index: /branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs
===================================================================
--- /branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs	(revision 15791)
+++ /branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs	(revision 15792)
@@ -77,10 +77,10 @@
     private Dictionary<Guid, HashSet<Resource>> resourceAncestors;
     public Dictionary<Guid, HashSet<Resource>> ResourceAncestors {
-      get { return ResourceAncestors; }
+      get { return resourceAncestors; }
     }
 
     private Dictionary<Guid, HashSet<Resource>> resourceDescendants;
     public Dictionary<Guid, HashSet<Resource>> ResourceDescendants {
-      get { return ResourceDescendants; }
+      get { return resourceDescendants; }
     }
 
@@ -122,6 +122,6 @@
         });
 
-        UpdateResourceGenealogy();
-        UpdateProjectGenealogy();
+        UpdateResourceGenealogy(resources);
+        UpdateProjectGenealogy(projects);
       }
       catch {
@@ -133,5 +133,5 @@
     }
 
-    private void UpdateResourceGenealogy() {
+    public void UpdateResourceGenealogy(IItemList<Resource> resources) {
       resourceAncestors.Clear();
       resourceDescendants.Clear();
@@ -157,5 +157,5 @@
     }
 
-    private void UpdateProjectGenealogy() {
+    public void UpdateProjectGenealogy(IItemList<Project> projects) {
       projectAncestors.Clear();
       projectDescendants.Clear();
