Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs	(revision 15992)
@@ -82,5 +82,12 @@
         nameTextBox.Text = Content.Name;
         descriptionTextBox.Text = Content.Description;
-        ownerComboBox.SelectedItem = AccessClient.Instance.UsersAndGroups.FirstOrDefault(x => x.Id == Content.OwnerUserId);
+
+        ownerComboBox.SelectedIndexChanged -= ownerComboBox_SelectedIndexChanged;
+        var users = AccessClient.Instance.UsersAndGroups.OfType<LightweightUser>();
+        if (!Content.ParentProjectId.HasValue) users = users.Where(x => x.Roles.Select(y => y.Name).Contains(HiveRoles.Administrator));
+        ownerComboBox.DataSource = users.ToList();
+        ownerComboBox.SelectedItem = users.FirstOrDefault(x => x.Id == Content.OwnerUserId);
+        ownerComboBox.SelectedIndexChanged += ownerComboBox_SelectedIndexChanged;
+
         createdTextBox.Text = Content.DateCreated.ToString("ddd, dd.MM.yyyy, HH:mm:ss");
         startDateTimePicker.Value = Content.StartDate;
@@ -135,5 +142,7 @@
         finallyCallback: () => {
           ownerComboBox.SelectedIndexChanged -= ownerComboBox_SelectedIndexChanged;
-          ownerComboBox.DataSource = AccessClient.Instance.UsersAndGroups.OfType<LightweightUser>().ToList();
+          var users = AccessClient.Instance.UsersAndGroups.OfType<LightweightUser>();
+          if (Content != null && !Content.ParentProjectId.HasValue) users = users.Where(x => x.Roles.Select(y => y.Name).Contains(HiveRoles.Administrator));
+          ownerComboBox.DataSource = users.ToList();
           ownerComboBox.SelectedIndexChanged += ownerComboBox_SelectedIndexChanged;
         });
@@ -150,6 +159,8 @@
         finallyCallback: () => {
           ownerComboBox.SelectedIndexChanged -= ownerComboBox_SelectedIndexChanged;
-          ownerComboBox.DataSource = AccessClient.Instance.UsersAndGroups.OfType<LightweightUser>().ToList();
-          ownerComboBox.SelectedItem = AccessClient.Instance.UsersAndGroups.FirstOrDefault(x => x.Id == persistedOwnerUserId);
+          var users = AccessClient.Instance.UsersAndGroups.OfType<LightweightUser>();
+          if (Content != null && !Content.ParentProjectId.HasValue) users = users.Where(x => x.Roles.Select(y => y.Name).Contains(HiveRoles.Administrator));
+          ownerComboBox.DataSource = users.ToList();
+          ownerComboBox.SelectedItem = users.FirstOrDefault(x => x.Id == persistedOwnerUserId);
           ownerComboBox.SelectedIndexChanged += ownerComboBox_SelectedIndexChanged;
           refreshButton.Enabled = true;
@@ -203,10 +214,9 @@
     private void indefiniteCheckBox_CheckedChanged(object sender, EventArgs e) {
       if (Content == null) return;
-      var newEndDate = indefiniteCheckBox.Checked ? (DateTime?)null : Content.StartDate;
+      var newEndDate = indefiniteCheckBox.Checked ? (DateTime?)null : endDateTimePicker.Value;
       endDateTimePicker.Enabled = !indefiniteCheckBox.Checked;
       if (Content.EndDate != newEndDate) {
         DeregisterContentEvents();
         Content.EndDate = newEndDate;
-        endDateTimePicker.Value = newEndDate.HasValue ? newEndDate.Value : Content.StartDate;
         RegisterContentEvents();
       }
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 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 15992)
@@ -110,7 +110,7 @@
       bool enabled = Content != null && !Locked && !ReadOnly;
       refreshButton.Enabled = enabled;
-      addButton.Enabled = enabled;
-      removeButton.Enabled = enabled;
-      saveProjectButton.Enabled = enabled;
+      //addButton.Enabled = enabled;
+      //removeButton.Enabled = enabled;
+      //saveProjectButton.Enabled = enabled;
       projectView.Enabled = enabled;
       projectPermissionsView.Enabled = enabled;
@@ -199,4 +199,13 @@
       Guid? parentProjectId = null;
 
+      if(selectedProject == null && !IsAdmin()) {
+        MessageBox.Show(
+          "You are not allowed to add a root project - please select a parent project.",
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.OK,
+          MessageBoxIcon.Information);
+        return;
+      }
+      
       if (selectedProject != null && selectedProject.Id == Guid.Empty) {
         MessageBox.Show(
@@ -459,11 +468,25 @@
       bool projectIsNew = project != null && project.Id == Guid.Empty;
       bool locked = project == null || projectIsNew;
+
+      // if the project is new, or:
+      // the project does have any descendant projects and
+      // the user is an admin or owner of a parent project
       bool deleteEnabled = project != null && (
         projectIsNew
-        || HiveAdminClient.Instance.CheckOwnershipOfParentProject(project, UserInformation.Instance.User.Id)
-        || !HiveAdminClient.Instance.ProjectDescendants[project.Id].Any());
-
-      addButton.Enabled = !locked;
+        ||  (!HiveAdminClient.Instance.ProjectDescendants[project.Id].Any()
+              && (HiveAdminClient.Instance.CheckOwnershipOfParentProject(project, UserInformation.Instance.User.Id)
+              || IsAdmin())
+            )
+      );
+
+      bool addEnabled = !locked;
+      if (!IsAdmin() && project == null) addEnabled = false;
+
+      bool saveEnabled = project != null;
+      if (!IsAdmin() && !project.ParentProjectId.HasValue) saveEnabled = false;
+
+      addButton.Enabled = addEnabled;
       removeButton.Enabled = deleteEnabled;
+      saveProjectButton.Enabled = saveEnabled;
       projectPermissionsView.Locked = locked;
       projectResourcesView.Locked = locked;
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj	(revision 15992)
@@ -105,4 +105,5 @@
     <Compile Include="ExtensionMethods\TreeNodeExtensions.cs" />
     <Compile Include="ListViewItemDateComparer.cs" />
+    <Compile Include="ListViewItemComparer.cs" />
     <Compile Include="MenuItems\CreateHiveJobMenuItem.cs" />
     <Compile Include="MenuItems\RunInHiveMenuItem.cs" />
@@ -244,4 +245,9 @@
       <Private>False</Private>
     </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Views\RefreshableHiveJobView.resx">
+      <DependentUpon>RefreshableHiveJobView.cs</DependentUpon>
+    </EmbeddedResource>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/ListViewItemComparer.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/ListViewItemComparer.cs	(revision 15992)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/ListViewItemComparer.cs	(revision 15992)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Windows.Forms;
+
+namespace HeuristicLab.Clients.Hive.JobManager {
+  public class ListViewItemComparer : IComparer {
+    private int[] cols;
+    public SortOrder[] Orders { get; set; }
+    private const string dateFormat = "dd.MM.yyyy HH:mm";
+
+    public ListViewItemComparer() {
+      cols = new []{ 0 };
+      Orders = new[] { SortOrder.Ascending };
+    }
+
+    public ListViewItemComparer(int[] columns, SortOrder[] orders) {
+      cols = columns;
+      Orders = orders;
+    }
+
+    public int Compare(object x, object y) {
+      int returnVal;
+      bool result;
+      ListViewItem listViewItemX, listViewItemY;
+      listViewItemX = x as ListViewItem;
+      listViewItemY = y as ListViewItem;
+
+      if (listViewItemX == null || listViewItemY == null) {
+        throw new ArgumentException(string.Format("The ListViewItemComparer expects ListViewItems but received {0} and {1}.",
+          x.GetType().ToString(), y.GetType().ToString()));
+      }
+
+      int cmpres = 0;
+      for (int i = 0; i < cols.Length && cmpres == 0; i++) {
+        string textX = listViewItemX.SubItems[cols[i]].Text;
+        string textY = listViewItemY.SubItems[cols[i]].Text;
+
+        DateTime dateX, dateY;
+        int intX, intY;
+        double doubleX, doubleY;
+
+        if(DateTime.TryParse(textX, out dateX) && DateTime.TryParse(textY, out dateY)) {
+          cmpres = DateTime.Compare(dateX, dateY);
+        } else if(Int32.TryParse(textX, out intX) && Int32.TryParse(textY, out intY)) {
+          cmpres = (intX == intY) ? 0 : (intX > intY) ? 1 : -1;
+        } else if(Double.TryParse(textX, out doubleX) && Double.TryParse(textY, out doubleY)) {
+          cmpres = (doubleX == doubleY) ? 0 : (doubleX > doubleY) ? 1 : -1;
+        } else {
+          cmpres = String.Compare(textX, textY);
+        }
+        if(Orders[i] == SortOrder.Descending) {
+          cmpres *= -1;
+        }
+      }
+      return cmpres;
+    }
+  }
+}
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 15992)
@@ -43,10 +43,10 @@
     public const string additionalSlavesGroupDescription = "Contains additional slaves which are either ungrouped or the parenting slave group is not assigned to the selected project.";
 
-    private const string CURRENT_SELECTION_TAG = " [current selection]";
-    private const string NEW_SELECTION_TAG = " [new selection]";
-    private const string CHANGED_SELECTION_TAG = " [changed selection]";
-    private const string ADDED_SELECTION_TAG = " [added selection]";
-    private const string REMOVED_SELECTION_TAG = " [removed selection]";
-    private const string SELECTED_TAG = " [selected]";
+    private const string CURRENT_SELECTION_TAG = " [current assignment]";
+    private const string NEW_SELECTION_TAG = " [new assignment]";
+    private const string CHANGED_SELECTION_TAG = " [changed assignment]";
+    private const string ADDED_SELECTION_TAG = " [added assignment]";
+    private const string REMOVED_SELECTION_TAG = " [removed assignment]";
+    private const string SELECTED_TAG = " [assigned]";
     private const string INCLUDED_TAG = " [included]";
     private const string ADDED_INCLUDE_TAG = " [added include]";
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs	(revision 15992)
@@ -41,17 +41,27 @@
       this.itemsListView.Columns.Add(new ColumnHeader("Date") { Text = "Date" });
       this.itemsListView.Columns.Add(new ColumnHeader("Name") { Text = "Name" });
+      this.itemsListView.Columns.Add(new ColumnHeader("Project") { Text = "Project" });
 
       this.itemsListView.HeaderStyle = ColumnHeaderStyle.Clickable;
       this.itemsListView.FullRowSelect = true;
 
-      this.itemsListView.ListViewItemSorter = new ListViewItemDateComparer(0, SortOrder.Ascending);
+      this.itemsListView.ListViewItemSorter = new ListViewItemComparer(new int[] { 2, 0 }, new SortOrder[] { SortOrder.Ascending, SortOrder.Ascending });
+
+      foreach (ColumnHeader c in this.itemsListView.Columns) {
+        c.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+        int w = c.Width;
+        c.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
+        if(w > c.Width) {
+          c.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+        }
+      }
     }
 
     protected override void SortItemsListView(SortOrder sortOrder) {
       if (itemsListView.Sorting == sortOrder || sortOrder == SortOrder.None) return;
-      ((ListViewItemDateComparer)itemsListView.ListViewItemSorter).Order = sortOrder;
+      ((ListViewItemComparer)itemsListView.ListViewItemSorter).Orders[1] = sortOrder;
       itemsListView.Sorting = sortOrder;
       itemsListView.Sort();
-      AdjustListViewColumnSizes();
+      //AdjustListViewColumnSizes();
     }
 
@@ -133,5 +143,10 @@
         base.Content_ItemsAdded(sender, e);
         foreach (ColumnHeader c in this.itemsListView.Columns) {
+          c.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+          int w = c.Width;
           c.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
+          if (w > c.Width) {
+            c.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+          }
         }
         foreach (var item in e.Items) {
@@ -180,4 +195,6 @@
       listViewItem.SubItems.Insert(0, new ListViewItem.ListViewSubItem(listViewItem, item.Job.DateCreated.ToString()));
       listViewItem.SubItems.Insert(1, new ListViewItem.ListViewSubItem(listViewItem, item.Job.Name));
+      listViewItem.SubItems.Insert(2, new ListViewItem.ListViewSubItem(listViewItem, HiveClient.Instance.GetProjectAncestry(item.Job.ProjectId)));
+      
       listViewItem.Group = GetListViewGroup(item.Job.OwnerUsername);
       return listViewItem;
@@ -189,4 +206,5 @@
       listViewItem.SubItems[0].Text = item == null ? "null" : item.Job.DateCreated.ToString("dd.MM.yyyy HH:mm");
       listViewItem.SubItems[1].Text = item == null ? "null" : item.Job.Name;
+      listViewItem.SubItems[2].Text = item == null ? "null" : HiveClient.Instance.GetProjectAncestry(item.Job.ProjectId);
       listViewItem.Group = GetListViewGroup(item.Job.OwnerUsername);
       listViewItem.ToolTipText = item == null ? string.Empty : item.ItemName + ": " + item.ItemDescription;
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs	(revision 15992)
@@ -46,4 +46,5 @@
     private void InitializeComponent() {
       this.components = new System.ComponentModel.Container();
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RefreshableHiveJobView));
       this.tabControl = new HeuristicLab.MainForm.WindowsForms.DragOverTabControl();
       this.tasksTabPage = new System.Windows.Forms.TabPage();
@@ -51,4 +52,5 @@
       this.permissionTabPage = new System.Windows.Forms.TabPage();
       this.refreshPermissionsButton = new System.Windows.Forms.Button();
+      this.hiveExperimentPermissionListView = new HeuristicLab.Clients.Hive.JobManager.Views.HiveJobPermissionListView();
       this.runsTabPage = new System.Windows.Forms.TabPage();
       this.runCollectionViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
@@ -66,8 +68,11 @@
       this.nameLabel = new System.Windows.Forms.Label();
       this.nameTextBox = new System.Windows.Forms.TextBox();
+      this.descriptionLabel = new System.Windows.Forms.Label();
+      this.descriptionTextBox = new System.Windows.Forms.TextBox();
       this.toolTip = new System.Windows.Forms.ToolTip(this.components);
       this.refreshButton = new System.Windows.Forms.Button();
       this.updateButton = new System.Windows.Forms.Button();
       this.UnloadButton = new System.Windows.Forms.Button();
+      this.searchButton = new System.Windows.Forms.Button();
       this.refreshAutomaticallyCheckBox = new System.Windows.Forms.CheckBox();
       this.infoGroupBox = new System.Windows.Forms.GroupBox();
@@ -78,6 +83,4 @@
       this.calculatingLabel = new System.Windows.Forms.Label();
       this.jobsLabel = new System.Windows.Forms.Label();
-      this.searchButton = new System.Windows.Forms.Button();
-      this.hiveExperimentPermissionListView = new HeuristicLab.Clients.Hive.JobManager.Views.HiveJobPermissionListView();
       this.tabControl.SuspendLayout();
       this.tasksTabPage.SuspendLayout();
@@ -100,5 +103,5 @@
       this.tabControl.Controls.Add(this.stateTabPage);
       this.tabControl.Controls.Add(this.logTabPage);
-      this.tabControl.Location = new System.Drawing.Point(0, 78);
+      this.tabControl.Location = new System.Drawing.Point(0, 106);
       this.tabControl.Name = "tabControl";
       this.tabControl.SelectedIndex = 0;
@@ -147,5 +150,5 @@
       // refreshPermissionsButton
       // 
-      this.refreshPermissionsButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Refresh;
+      this.refreshPermissionsButton.Image = ((System.Drawing.Image)(resources.GetObject("refreshPermissionsButton.Image")));
       this.refreshPermissionsButton.Location = new System.Drawing.Point(3, 3);
       this.refreshPermissionsButton.Name = "refreshPermissionsButton";
@@ -155,4 +158,19 @@
       this.refreshPermissionsButton.UseVisualStyleBackColor = true;
       this.refreshPermissionsButton.Click += new System.EventHandler(this.refreshPermissionsButton_Click);
+      // 
+      // hiveExperimentPermissionListView
+      // 
+      this.hiveExperimentPermissionListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.hiveExperimentPermissionListView.Caption = "HiveExperimentPermissionList View";
+      this.hiveExperimentPermissionListView.Content = null;
+      this.hiveExperimentPermissionListView.HiveExperimentId = new System.Guid("00000000-0000-0000-0000-000000000000");
+      this.hiveExperimentPermissionListView.Location = new System.Drawing.Point(3, 33);
+      this.hiveExperimentPermissionListView.Name = "hiveExperimentPermissionListView";
+      this.hiveExperimentPermissionListView.ReadOnly = false;
+      this.hiveExperimentPermissionListView.ShowDetails = true;
+      this.hiveExperimentPermissionListView.Size = new System.Drawing.Size(703, 390);
+      this.hiveExperimentPermissionListView.TabIndex = 0;
       // 
       // runsTabPage
@@ -235,9 +253,9 @@
       // 
       this.startButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.startButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Play;
-      this.startButton.Location = new System.Drawing.Point(0, 536);
+      this.startButton.Image = ((System.Drawing.Image)(resources.GetObject("startButton.Image")));
+      this.startButton.Location = new System.Drawing.Point(0, 564);
       this.startButton.Name = "startButton";
       this.startButton.Size = new System.Drawing.Size(24, 24);
-      this.startButton.TabIndex = 5;
+      this.startButton.TabIndex = 4;
       this.toolTip.SetToolTip(this.startButton, "Start/Resume Experiment");
       this.startButton.UseVisualStyleBackColor = true;
@@ -247,9 +265,9 @@
       // 
       this.stopButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.stopButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Stop;
-      this.stopButton.Location = new System.Drawing.Point(60, 536);
+      this.stopButton.Image = ((System.Drawing.Image)(resources.GetObject("stopButton.Image")));
+      this.stopButton.Location = new System.Drawing.Point(60, 564);
       this.stopButton.Name = "stopButton";
       this.stopButton.Size = new System.Drawing.Size(24, 24);
-      this.stopButton.TabIndex = 7;
+      this.stopButton.TabIndex = 6;
       this.toolTip.SetToolTip(this.stopButton, "Stop Experiment");
       this.stopButton.UseVisualStyleBackColor = true;
@@ -260,8 +278,8 @@
       this.executionTimeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
       this.executionTimeLabel.AutoSize = true;
-      this.executionTimeLabel.Location = new System.Drawing.Point(491, 543);
+      this.executionTimeLabel.Location = new System.Drawing.Point(491, 571);
       this.executionTimeLabel.Name = "executionTimeLabel";
       this.executionTimeLabel.Size = new System.Drawing.Size(83, 13);
-      this.executionTimeLabel.TabIndex = 9;
+      this.executionTimeLabel.TabIndex = 100;
       this.executionTimeLabel.Text = "&Execution Time:";
       // 
@@ -269,9 +287,9 @@
       // 
       this.executionTimeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-      this.executionTimeTextBox.Location = new System.Drawing.Point(580, 540);
+      this.executionTimeTextBox.Location = new System.Drawing.Point(580, 568);
       this.executionTimeTextBox.Name = "executionTimeTextBox";
       this.executionTimeTextBox.ReadOnly = true;
       this.executionTimeTextBox.Size = new System.Drawing.Size(137, 20);
-      this.executionTimeTextBox.TabIndex = 10;
+      this.executionTimeTextBox.TabIndex = 100;
       // 
       // pauseButton
@@ -279,9 +297,9 @@
       this.pauseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
       this.pauseButton.Enabled = false;
-      this.pauseButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Pause;
-      this.pauseButton.Location = new System.Drawing.Point(30, 536);
+      this.pauseButton.Image = ((System.Drawing.Image)(resources.GetObject("pauseButton.Image")));
+      this.pauseButton.Location = new System.Drawing.Point(30, 564);
       this.pauseButton.Name = "pauseButton";
       this.pauseButton.Size = new System.Drawing.Size(24, 24);
-      this.pauseButton.TabIndex = 6;
+      this.pauseButton.TabIndex = 5;
       this.toolTip.SetToolTip(this.pauseButton, "Pause Experiment");
       this.pauseButton.UseVisualStyleBackColor = true;
@@ -291,8 +309,8 @@
       // 
       this.projectLabel.AutoSize = true;
-      this.projectLabel.Location = new System.Drawing.Point(3, 56);
+      this.projectLabel.Location = new System.Drawing.Point(3, 83);
       this.projectLabel.Name = "projectLabel";
       this.projectLabel.Size = new System.Drawing.Size(43, 13);
-      this.projectLabel.TabIndex = 12;
+      this.projectLabel.TabIndex = 100;
       this.projectLabel.Text = "Project:";
       // 
@@ -301,9 +319,9 @@
       this.projectNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-      this.projectNameTextBox.Location = new System.Drawing.Point(82, 52);
+      this.projectNameTextBox.Location = new System.Drawing.Point(100, 80);
       this.projectNameTextBox.Name = "projectNameTextBox";
       this.projectNameTextBox.ReadOnly = true;
-      this.projectNameTextBox.Size = new System.Drawing.Size(489, 20);
-      this.projectNameTextBox.TabIndex = 2;
+      this.projectNameTextBox.Size = new System.Drawing.Size(471, 20);
+      this.projectNameTextBox.TabIndex = 100;
       this.projectNameTextBox.Validated += new System.EventHandler(this.resourceNamesTextBox_Validated);
       // 
@@ -311,8 +329,8 @@
       // 
       this.nameLabel.AutoSize = true;
-      this.nameLabel.Location = new System.Drawing.Point(3, 30);
+      this.nameLabel.Location = new System.Drawing.Point(3, 35);
       this.nameLabel.Name = "nameLabel";
       this.nameLabel.Size = new System.Drawing.Size(38, 13);
-      this.nameLabel.TabIndex = 20;
+      this.nameLabel.TabIndex = 100;
       this.nameLabel.Text = "Name:";
       // 
@@ -321,17 +339,36 @@
       this.nameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-      this.nameTextBox.Location = new System.Drawing.Point(52, 27);
+      this.nameTextBox.Location = new System.Drawing.Point(71, 32);
       this.nameTextBox.Name = "nameTextBox";
-      this.nameTextBox.Size = new System.Drawing.Size(519, 20);
+      this.nameTextBox.Size = new System.Drawing.Size(500, 20);
       this.nameTextBox.TabIndex = 1;
       this.nameTextBox.Validated += new System.EventHandler(this.nameTextBox_Validated);
       // 
+      // descriptionLabel
+      // 
+      this.descriptionLabel.AutoSize = true;
+      this.descriptionLabel.Location = new System.Drawing.Point(3, 59);
+      this.descriptionLabel.Name = "descriptionLabel";
+      this.descriptionLabel.Size = new System.Drawing.Size(63, 13);
+      this.descriptionLabel.TabIndex = 100;
+      this.descriptionLabel.Text = "Description:";
+      // 
+      // descriptionTextBox
+      // 
+      this.descriptionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.descriptionTextBox.Location = new System.Drawing.Point(71, 56);
+      this.descriptionTextBox.Name = "descriptionTextBox";
+      this.descriptionTextBox.Size = new System.Drawing.Size(500, 20);
+      this.descriptionTextBox.TabIndex = 2;
+      this.descriptionTextBox.Validated += new System.EventHandler(this.descriptionTextBox_Validated);
+      // 
       // refreshButton
       // 
-      this.refreshButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Refresh;
+      this.refreshButton.Image = ((System.Drawing.Image)(resources.GetObject("refreshButton.Image")));
       this.refreshButton.Location = new System.Drawing.Point(3, 0);
       this.refreshButton.Name = "refreshButton";
       this.refreshButton.Size = new System.Drawing.Size(24, 24);
-      this.refreshButton.TabIndex = 22;
+      this.refreshButton.TabIndex = 7;
       this.toolTip.SetToolTip(this.refreshButton, "Refresh Data");
       this.refreshButton.UseVisualStyleBackColor = true;
@@ -340,9 +377,9 @@
       // updateButton
       // 
-      this.updateButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Save;
+      this.updateButton.Image = ((System.Drawing.Image)(resources.GetObject("updateButton.Image")));
       this.updateButton.Location = new System.Drawing.Point(30, 0);
       this.updateButton.Name = "updateButton";
       this.updateButton.Size = new System.Drawing.Size(24, 24);
-      this.updateButton.TabIndex = 23;
+      this.updateButton.TabIndex = 8;
       this.toolTip.SetToolTip(this.updateButton, "Update Job (Name, Project, Resources)");
       this.updateButton.UseVisualStyleBackColor = true;
@@ -351,12 +388,23 @@
       // UnloadButton
       // 
-      this.UnloadButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Disconnect;
+      this.UnloadButton.Image = ((System.Drawing.Image)(resources.GetObject("UnloadButton.Image")));
       this.UnloadButton.Location = new System.Drawing.Point(57, 0);
       this.UnloadButton.Name = "UnloadButton";
       this.UnloadButton.Size = new System.Drawing.Size(24, 24);
-      this.UnloadButton.TabIndex = 27;
+      this.UnloadButton.TabIndex = 9;
       this.toolTip.SetToolTip(this.UnloadButton, "Unload Job");
       this.UnloadButton.UseVisualStyleBackColor = true;
       this.UnloadButton.Click += new System.EventHandler(this.UnloadButton_Click);
+      // 
+      // searchButton
+      // 
+      this.searchButton.Image = ((System.Drawing.Image)(resources.GetObject("searchButton.Image")));
+      this.searchButton.Location = new System.Drawing.Point(71, 79);
+      this.searchButton.Name = "searchButton";
+      this.searchButton.Size = new System.Drawing.Size(24, 24);
+      this.searchButton.TabIndex = 3;
+      this.toolTip.SetToolTip(this.searchButton, "Select project and resources");
+      this.searchButton.UseVisualStyleBackColor = true;
+      this.searchButton.Click += new System.EventHandler(this.searchButton_Click);
       // 
       // refreshAutomaticallyCheckBox
@@ -366,5 +414,5 @@
       this.refreshAutomaticallyCheckBox.Name = "refreshAutomaticallyCheckBox";
       this.refreshAutomaticallyCheckBox.Size = new System.Drawing.Size(127, 17);
-      this.refreshAutomaticallyCheckBox.TabIndex = 24;
+      this.refreshAutomaticallyCheckBox.TabIndex = 100;
       this.refreshAutomaticallyCheckBox.Text = "&Refresh automatically";
       this.refreshAutomaticallyCheckBox.UseVisualStyleBackColor = true;
@@ -380,5 +428,5 @@
       this.infoGroupBox.Controls.Add(this.calculatingLabel);
       this.infoGroupBox.Controls.Add(this.jobsLabel);
-      this.infoGroupBox.Location = new System.Drawing.Point(580, 5);
+      this.infoGroupBox.Location = new System.Drawing.Point(578, 16);
       this.infoGroupBox.Name = "infoGroupBox";
       this.infoGroupBox.Size = new System.Drawing.Size(133, 89);
@@ -394,5 +442,5 @@
       this.finishedTextBox.Name = "finishedTextBox";
       this.finishedTextBox.Size = new System.Drawing.Size(53, 20);
-      this.finishedTextBox.TabIndex = 5;
+      this.finishedTextBox.TabIndex = 100;
       // 
       // calculatingTextBox
@@ -403,5 +451,5 @@
       this.calculatingTextBox.Name = "calculatingTextBox";
       this.calculatingTextBox.Size = new System.Drawing.Size(53, 20);
-      this.calculatingTextBox.TabIndex = 4;
+      this.calculatingTextBox.TabIndex = 100;
       // 
       // jobsTextBox
@@ -412,5 +460,5 @@
       this.jobsTextBox.Name = "jobsTextBox";
       this.jobsTextBox.Size = new System.Drawing.Size(53, 20);
-      this.jobsTextBox.TabIndex = 3;
+      this.jobsTextBox.TabIndex = 100;
       // 
       // finishedLabel
@@ -420,5 +468,5 @@
       this.finishedLabel.Name = "finishedLabel";
       this.finishedLabel.Size = new System.Drawing.Size(49, 13);
-      this.finishedLabel.TabIndex = 2;
+      this.finishedLabel.TabIndex = 100;
       this.finishedLabel.Text = "Finished:";
       // 
@@ -429,5 +477,5 @@
       this.calculatingLabel.Name = "calculatingLabel";
       this.calculatingLabel.Size = new System.Drawing.Size(62, 13);
-      this.calculatingLabel.TabIndex = 1;
+      this.calculatingLabel.TabIndex = 100;
       this.calculatingLabel.Text = "Calculating:";
       // 
@@ -438,32 +486,6 @@
       this.jobsLabel.Name = "jobsLabel";
       this.jobsLabel.Size = new System.Drawing.Size(46, 13);
-      this.jobsLabel.TabIndex = 0;
+      this.jobsLabel.TabIndex = 100;
       this.jobsLabel.Text = "Waiting:";
-      // 
-      // searchButton
-      // 
-      this.searchButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Zoom;
-      this.searchButton.Location = new System.Drawing.Point(52, 50);
-      this.searchButton.Name = "searchButton";
-      this.searchButton.Size = new System.Drawing.Size(24, 24);
-      this.searchButton.TabIndex = 26;
-      this.toolTip.SetToolTip(this.searchButton, "Select project and resources");
-      this.searchButton.UseVisualStyleBackColor = true;
-      this.searchButton.Click += new System.EventHandler(this.searchButton_Click);
-      // 
-      // hiveExperimentPermissionListView
-      // 
-      this.hiveExperimentPermissionListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.hiveExperimentPermissionListView.Caption = "HiveExperimentPermissionList View";
-      this.hiveExperimentPermissionListView.Content = null;
-      this.hiveExperimentPermissionListView.HiveExperimentId = new System.Guid("00000000-0000-0000-0000-000000000000");
-      this.hiveExperimentPermissionListView.Location = new System.Drawing.Point(3, 33);
-      this.hiveExperimentPermissionListView.Name = "hiveExperimentPermissionListView";
-      this.hiveExperimentPermissionListView.ReadOnly = false;
-      this.hiveExperimentPermissionListView.ShowDetails = true;
-      this.hiveExperimentPermissionListView.Size = new System.Drawing.Size(703, 390);
-      this.hiveExperimentPermissionListView.TabIndex = 0;
       // 
       // RefreshableHiveJobView
@@ -478,4 +500,6 @@
       this.Controls.Add(this.nameTextBox);
       this.Controls.Add(this.nameLabel);
+      this.Controls.Add(this.descriptionTextBox);
+      this.Controls.Add(this.descriptionLabel);
       this.Controls.Add(this.tabControl);
       this.Controls.Add(this.startButton);
@@ -487,5 +511,5 @@
       this.Controls.Add(this.stopButton);
       this.Name = "RefreshableHiveJobView";
-      this.Size = new System.Drawing.Size(717, 560);
+      this.Size = new System.Drawing.Size(717, 588);
       this.tabControl.ResumeLayout(false);
       this.tasksTabPage.ResumeLayout(false);
@@ -515,4 +539,6 @@
     private System.Windows.Forms.Label nameLabel;
     private System.Windows.Forms.TextBox nameTextBox;
+    private System.Windows.Forms.Label descriptionLabel;
+    private System.Windows.Forms.TextBox descriptionTextBox;
     private System.Windows.Forms.ToolTip toolTip;
     private System.Windows.Forms.Button refreshButton;
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 15992)
@@ -121,4 +121,5 @@
         if (Content == null) {
           nameTextBox.Text = string.Empty;
+          descriptionTextBox.Text = string.Empty;
           executionTimeTextBox.Text = string.Empty;
           projectNameTextBox.Text = string.Empty;
@@ -139,4 +140,5 @@
 
           nameTextBox.Text = Content.Job.Name;
+          descriptionTextBox.Text = Content.Job.Description;
           executionTimeTextBox.Text = Content.ExecutionTime.ToString();
           refreshAutomaticallyCheckBox.Checked = Content.RefreshAutomatically;
@@ -183,4 +185,5 @@
       tabControl.Enabled = !Locked;
       nameTextBox.Enabled = !Locked;
+      descriptionTextBox.Enabled = !Locked;
       projectNameTextBox.Enabled = !Locked;
       searchButton.Enabled = !Locked;
@@ -208,4 +211,5 @@
 
           this.nameTextBox.ReadOnly = Content.IsProgressing;
+          this.descriptionTextBox.ReadOnly = Content.IsProgressing;
           this.searchButton.Enabled = !Content.IsProgressing && Content.ExecutionState != ExecutionState.Stopped;
           this.jobsTreeView.ReadOnly = !Content.IsControllable || Content.ExecutionState != ExecutionState.Prepared || alreadyUploaded || Content.IsProgressing;
@@ -457,4 +461,9 @@
     }
 
+    private void descriptionTextBox_Validated(object sender, EventArgs e) {
+      if (!SuppressEvents && Content.Job != null && Content.Job.Description != descriptionTextBox.Text)
+        Content.Job.Description = descriptionTextBox.Text;
+    }
+
     private void resourceNamesTextBox_Validated(object sender, EventArgs e) {
       //if (!SuppressEvents && Content.Job != null && Content.Job.ResourceNames != resourceNamesTextBox.Text)
@@ -478,4 +487,17 @@
     }
 
+    private void updateButton_Click2(object sender, EventArgs e) {
+      if (Content.ExecutionState == ExecutionState.Stopped) {
+        MessageBox.Show("Job cannot be updated once it stopped.", "HeuristicLab Hive Job Manager", MessageBoxButtons.OK, MessageBoxIcon.Information);
+        return;
+      }
+
+      HiveClient.UpdateJob(
+        (Exception ex) => ErrorHandling.ShowErrorDialog(this, "Update failed.", ex), 
+        Content, 
+        new CancellationToken());
+      UpdateSelectorDialog();
+    }
+
     private void updateButton_Click(object sender, EventArgs e) {
       if (Content.ExecutionState == ExecutionState.Stopped) {
@@ -484,8 +506,12 @@
       }
 
-      HiveClient.UpdateJob(
-        (Exception ex) => ErrorHandling.ShowErrorDialog(this, "Update failed.", ex), 
-        Content, 
-        new CancellationToken());
+      var invoker = new Action<RefreshableJob>(HiveClient.UpdateJob);
+      invoker.BeginInvoke(Content, (ar) => {
+        try {
+          invoker.EndInvoke(ar);
+        } catch (Exception ex) {
+          ThreadPool.QueueUserWorkItem(delegate (object exception) { ErrorHandling.ShowErrorDialog(this, (Exception)exception); }, ex);
+        }
+      }, null);
       UpdateSelectorDialog();
     }
Index: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveClient.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveClient.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveClient.cs	(revision 15992)
@@ -151,7 +151,7 @@
         });
 
-        UpdateResourceGenealogy();
-        UpdateProjectGenealogy();
-        UpdateDisabledParentProjects();
+        RefreshResourceGenealogy();
+        RefreshProjectGenealogy();
+        RefreshDisabledParentProjects();
       }
       catch {
@@ -186,7 +186,7 @@
         });
 
-        UpdateResourceGenealogy();
-        UpdateProjectGenealogy();
-        UpdateDisabledParentProjects();
+        RefreshResourceGenealogy();
+        RefreshProjectGenealogy();
+        RefreshDisabledParentProjects();
       } catch {
         projects = null;
@@ -214,5 +214,5 @@
     }
 
-    private void UpdateResourceGenealogy() {
+    private void RefreshResourceGenealogy() {
       resourceAncestors.Clear();
       resourceDescendants.Clear();
@@ -234,5 +234,5 @@
     }
 
-    private void UpdateProjectGenealogy() {
+    private void RefreshProjectGenealogy() {
       projectAncestors.Clear();
       projectDescendants.Clear();
@@ -254,5 +254,5 @@
     }
 
-    private void UpdateDisabledParentProjects() {
+    private void RefreshDisabledParentProjects() {
       disabledParentProjects = new HashSet<Project>();
 
@@ -414,12 +414,29 @@
 
     public static void UpdateJob(Action<Exception> exceptionCallback, RefreshableJob refreshableJob, CancellationToken cancellationToken) {
-      HiveServiceLocator.Instance.CallHiveService(service => {
-        HiveClient.StoreAsync(
-          new Action<Exception>((Exception ex) => {
-            //refreshableJob.ExecutionState = ExecutionState.Prepared;
-            exceptionCallback(ex);
-          }), refreshableJob.Job, cancellationToken);
-      });
-    }
+      refreshableJob.IsProgressing = true;
+      refreshableJob.Progress.Status = "Saving Job...";
+      HiveClient.StoreAsync(
+        new Action<Exception>((Exception ex) => {
+          exceptionCallback(ex);
+        }), refreshableJob.Job, cancellationToken);
+      refreshableJob.IsProgressing = false;
+      refreshableJob.Progress.Finish();
+    }
+
+    public static void UpdateJob(RefreshableJob refreshableJob) {
+      refreshableJob.IsProgressing = true;
+
+      try {
+        refreshableJob.Progress.Start("Saving Job...");
+        HiveClient.StoreAsync(new Action<Exception>((Exception ex) => {
+          throw new Exception("Update failed.", ex);
+        }), refreshableJob.Job, new CancellationToken());
+      } finally {
+        refreshableJob.IsProgressing = false;
+        refreshableJob.Progress.Finish();
+      }
+    }
+
+
 
     #region Upload Job
@@ -687,4 +704,11 @@
       });
     }
+
+    public string GetProjectAncestry(Guid projectId) {
+      if (projectId == null || projectId == Guid.Empty) return "";
+      var projects = projectAncestors[projectId].Reverse().ToList();
+      projects.Add(projectId);
+      return string.Join(" » ", projects.Select(x => ProjectNames[x]).ToArray());
+    }
   }
 }
Index: branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/Interfaces/IRoleVerifier.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/Interfaces/IRoleVerifier.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/Interfaces/IRoleVerifier.cs	(revision 15992)
@@ -23,4 +23,5 @@
   public interface IRoleVerifier {
     bool IsInRole(string role);
+    bool IsUserInRole(string username, string role);
     bool IsInAnyRole(params string[] roles);
     bool IsInAllRoles(params string[] roles);
Index: branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/RoleVerifier.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/RoleVerifier.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Services.Access/3.3/RoleVerifier.cs	(revision 15992)
@@ -29,4 +29,7 @@
       return Roles.IsUserInRole(role);
     }
+    public bool IsUserInRole(string username, string role) {
+      return Roles.IsUserInRole(username, role);
+    }
     public bool IsInAnyRole(params string[] roles) {
       return roles.Any(x => Roles.IsUserInRole(x));
Index: branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/HiveService.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 15992)
@@ -43,4 +43,5 @@
     private const string NOT_AUTHORIZED_PROJECTRESOURCE = "Selected project is not authorized to access the requested resource";
     private const string NOT_AUTHORIZED_USERPROJECT = "Current user is not authorized to access the requested project";
+    private const string NOT_AUTHORIZED_PROJECTOWNER = "The set user is not authorized to own the project";
     private const string NO_JOB_UPDATE_POSSIBLE = "This job has already been flagged for deletion, thus, it can not be updated anymore.";
 
@@ -768,6 +769,7 @@
       RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
       // check if current (non-admin) user is owner of one of projectDto's-parents
+      // note: non-admin users are not allowed to administer root projects (i.e. projects without parental entry)
       if (!RoleVerifier.IsInRole(HiveRoles.Administrator)) {
-        if(projectDto.ParentProjectId.HasValue) {
+        if(projectDto != null && projectDto.ParentProjectId.HasValue) {
           AuthorizationManager.AuthorizeForProjectAdministration(projectDto.ParentProjectId.Value, false);
         } else {
@@ -775,5 +777,13 @@
         }
       }
-      
+
+      // check that non-admins can not be set as owner of root projects
+      if (projectDto != null && !projectDto.ParentProjectId.HasValue) {
+        var owner = UserManager.GetUserById(projectDto.OwnerUserId);
+        if (owner == null || !RoleVerifier.IsUserInRole(owner.UserName, HiveRoles.Administrator)) {
+          throw new SecurityException(NOT_AUTHORIZED_PROJECTOWNER);
+        }
+      }
+
       var pm = PersistenceManager;
       using (new PerformanceLogger("AddProject")) {
@@ -797,8 +807,21 @@
       RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
       // check if current (non-admin) user is owner of the project or the projectDto's-parents
+      // note: non-admin users are not allowed to administer root projects (i.e. projects without parental entry)
       if (!RoleVerifier.IsInRole(HiveRoles.Administrator)) {
-        AuthorizationManager.AuthorizeForProjectAdministration(projectDto.Id, false);
-      }
-
+        if (projectDto != null && projectDto.ParentProjectId.HasValue) {
+          AuthorizationManager.AuthorizeForProjectAdministration(projectDto.Id, false);
+        } else {
+          throw new SecurityException(NOT_AUTHORIZED_USERPROJECT);
+        }
+      }
+
+      // check that non-admins can not be set as owner of root projects
+      if(projectDto != null && !projectDto.ParentProjectId.HasValue) {
+        var owner = UserManager.GetUserById(projectDto.OwnerUserId);
+        if(owner == null || !RoleVerifier.IsUserInRole(owner.UserName, HiveRoles.Administrator)) {
+          throw new SecurityException(NOT_AUTHORIZED_PROJECTOWNER);
+        }
+      }
+      
       var pm = PersistenceManager;
       using (new PerformanceLogger("UpdateProject")) {
@@ -863,5 +886,6 @@
       RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
       // check if current (non-admin) user is owner of one of the projectDto's-parents
-      if (!RoleVerifier.IsInRole(HiveRoles.Administrator)) {
+      // note: non-admin users are not allowed to administer root projects (i.e. projects without parental entry)
+      if (!RoleVerifier.IsInRole(HiveRoles.Administrator)) {        
         AuthorizationManager.AuthorizeForProjectAdministration(projectId, true);
       }
@@ -922,5 +946,5 @@
             .Select(x => x.ToDto()).ToList();
           var now = DateTime.Now;
-          return projects.Where(x => x.StartDate <= now && x.EndDate >= now).ToList();
+          return projects.Where(x => x.StartDate <= now && (x.EndDate == null || x.EndDate >= now)).ToList();
         });
       }
@@ -999,4 +1023,10 @@
           if (project == null) return;
           var projectPermissions = project.ProjectPermissions.Select(x => x.GrantedUserId).ToArray();
+
+          // guarantee that project owner is always permitted
+          if(!grantedUserIds.Contains(project.OwnerUserId)) {
+            grantedUserIds.Add(project.OwnerUserId);
+          }
+
           //var addedPermissions = grantedUserIds.Except(projectPermissions);
           var removedPermissions = projectPermissions.Except(grantedUserIds);
@@ -1030,8 +1060,8 @@
 
             // (3) get all Guids which are in removedPermissions but not in grantedUserIds
-            var definatelyNotPermittedGuids = notpermittedGuids.Except(permittedGuids);
+            var definitelyNotPermittedGuids = notpermittedGuids.Except(permittedGuids);
 
             // (4) delete jobs of those
-            assignedJobResourceDao.DeleteByProjectIdAndUserIds(project.ProjectId, definatelyNotPermittedGuids);
+            assignedJobResourceDao.DeleteByProjectIdAndUserIds(project.ProjectId, definitelyNotPermittedGuids);
 
 
@@ -1068,10 +1098,23 @@
 
             foreach(var p in childProjects) {
+              var cpAssignedPermissions = p.ProjectPermissions.Select(x => x.GrantedUserId).ToList();
+              // guarantee that project owner is always permitted
+              if (!cpAssignedPermissions.Contains(p.OwnerUserId)) {
+                cpAssignedPermissions.Add(p.OwnerUserId);
+              }
+              var cpRemovedPermissions = cpAssignedPermissions.Where(x => x != p.OwnerUserId).Except(grantedUserIds);
+
+              // remove left-over job assignments (for non-reassignments)
+              if(!reassignCascading) {
+                assignedJobResourceDao.DeleteByProjectIdAndUserIds(p.ProjectId, cpRemovedPermissions);
+              }
+
               // remove project permissions
-              if(reassignCascading) {
+              if (reassignCascading) {
                 p.ProjectPermissions.Clear();
               } else {
                 foreach(var item in p.ProjectPermissions
-                  .Where(x => removedPermissions.Contains(x.GrantedUserId))
+                  .Where(x => x.GrantedUserId != p.OwnerUserId 
+                    && (removedPermissions.Contains(x.GrantedUserId) || cpRemovedPermissions.Contains(x.GrantedUserId)))
                   .ToList()) {
                   p.ProjectPermissions.Remove(item);
@@ -1081,5 +1124,8 @@
 
               // add project permissions
-              foreach (var id in grantedUserIds) {
+              var cpGrantedUserIds = new HashSet<Guid>(grantedUserIds);
+              cpGrantedUserIds.Add(p.OwnerUserId);
+
+              foreach (var id in cpGrantedUserIds) {
                 if (p.ProjectPermissions.All(x => x.GrantedUserId != id)) {
                   p.ProjectPermissions.Add(new DA.ProjectPermission {
@@ -1181,13 +1227,21 @@
           if (cascading) {
             var childProjects = projectDao.GetChildProjectsById(projectId).ToList();
+            var childProjectIds = childProjects.Select(x => x.ProjectId).ToList();
 
             // remove job assignments
             if (reassignCascading) {
-              assignedJobResourceDao.DeleteByProjectIds(childProjects.Select(x => x.ProjectId).ToList());
+              assignedJobResourceDao.DeleteByProjectIds(childProjectIds);
             } else {
-              var childProjectIds = childProjects.Select(x => x.ProjectId).ToList();
               assignedJobResourceDao.DeleteByProjectIdsAndResourceIds(childProjectIds, removedAssignments);
             }
             foreach (var p in childProjects) {
+              var cpAssignedResources = p.AssignedProjectResources.Select(x => x.ResourceId).ToArray();
+              var cpRemovedAssignments = cpAssignedResources.Except(resourceIds);
+
+              // remove left-over job assignments (for non-reassignments)
+              if(!reassignCascading) {
+                assignedJobResourceDao.DeleteByProjectIdAndResourceIds(p.ProjectId, cpRemovedAssignments);
+              }
+
               // remove project assignments
               if (reassignCascading) {
@@ -1195,5 +1249,5 @@
               } else {
                 foreach (var item in p.AssignedProjectResources
-                  .Where(x => removedAssignments.Contains(x.ResourceId))
+                  .Where(x => removedAssignments.Contains(x.ResourceId) || cpRemovedAssignments.Contains(x.ResourceId))
                   .ToList()) {
                   p.AssignedProjectResources.Remove(item);
@@ -1780,5 +1834,5 @@
         if (project != null) {
           if (project.StartDate > date) throw new ArgumentException("Cannot add job to specified project. The start date of the project is still in the future.");
-          else if (project.EndDate < date) throw new ArgumentException("Cannot add job to specified project. The end date of the project is already in the past.");
+          else if (project.EndDate != null && project.EndDate < date) throw new ArgumentException("Cannot add job to specified project. The end date of the project is already reached.");
         } else {
           throw new ArgumentException("Cannot add job to specified project. The project seems not to be available anymore.");
Index: branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs
===================================================================
--- branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs	(revision 15991)
+++ branches/2839_HiveProjectManagement/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs	(revision 15992)
@@ -39,4 +39,5 @@
     private const string USER_NOT_IDENTIFIED = "User could not be identified";
     private const string TASK_NOT_EXISTENT = "Queried task could not be found";
+    private const string PROJECT_NOT_EXISTENT = "Queried project could not be found";
 
     private IPersistenceManager PersistenceManager {
@@ -98,4 +99,11 @@
       var projectDao = pm.ProjectDao;
       pm.UseTransaction(() => {
+        var project = projectDao.GetById(projectId);
+        if (project == null) throw new ArgumentException(PROJECT_NOT_EXISTENT);
+        if(!RoleVerifier.IsInRole(HiveRoles.Administrator)
+          && !project.ParentProjectId.HasValue) {
+          throw new SecurityException(NOT_AUTHORIZED_USERPROJECT);
+        }
+
         List<Project> projectBranch = null;
         if(parentalOwnership) projectBranch = projectDao.GetParentProjectsById(projectId).ToList();
