source: branches/HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs @ 15559

Last change on this file since 15559 was 15559, checked in by jzenisek, 3 years ago

#2839 worked views for Projects and ProjectResources

File size: 15.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Clients.Access;
29using HeuristicLab.Clients.Hive.Views;
30using HeuristicLab.Collections;
31using HeuristicLab.Common.Resources;
32using HeuristicLab.Core;
33using HeuristicLab.Core.Views;
34using HeuristicLab.MainForm;
35
36namespace HeuristicLab.Clients.Hive.Administrator.Views {
37  [View("Projects View")]
38  [Content(typeof(IItemList<Project>), false)]
39  public partial class ProjectsView : ItemView, IDisposable {
40    private const int greenFlagImageIndex = 0;
41    private const int redFlagImageIndex = 1;
42    private readonly Color changedColor = Color.FromArgb(255, Color.LightGreen);
43    private readonly Color selectedColor = Color.SkyBlue;
44
45    private readonly object locker = new object();
46
47    public new IItemList<Project> Content {
48      get { return (IItemList<Project>)base.Content; }
49      set { base.Content = value; }
50    }
51
52    public ProjectsView() {
53      InitializeComponent();
54
55      projectsTreeView.ImageList.Images.Add(VSImageLibrary.FlagGreen);
56      projectsTreeView.ImageList.Images.Add(VSImageLibrary.FlagRed);
57
58      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
59      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
60      AccessClient.Instance.Refreshing += AccessClient_Instance_Refreshing;
61      AccessClient.Instance.Refreshed += AccessClient_Instance_Refreshed;
62    }
63
64    #region Overrides
65    protected override void OnClosing(FormClosingEventArgs e) {
66      AccessClient.Instance.Refreshed -= AccessClient_Instance_Refreshed;
67      AccessClient.Instance.Refreshing -= AccessClient_Instance_Refreshing;
68      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
69      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
70      base.OnClosing(e);
71    }
72
73    protected override void RegisterContentEvents() {
74      base.RegisterContentEvents();
75      Content.ItemsAdded += Content_ItemsAdded;
76      Content.ItemsRemoved += Content_ItemsRemoved;
77    }
78
79    protected override void DeregisterContentEvents() {
80      Content.ItemsRemoved -= Content_ItemsRemoved;
81      Content.ItemsAdded -= Content_ItemsAdded;
82      base.DeregisterContentEvents();
83    }
84
85    protected override void OnContentChanged() {
86      base.OnContentChanged();
87      if (Content == null) {
88        projectsTreeView.Nodes.Clear();
89        projectView.Content = null;
90        projectPermissionsView.Content = null;
91        projectResourcesView.Content = null;
92      } else {
93        var top = BuildProjectTree(Content);
94        projectView.Content = top;
95        projectPermissionsView.Content = top;
96        projectResourcesView.Content = top;
97      }
98    }
99
100    protected override void SetEnabledStateOfControls() {
101      base.SetEnabledStateOfControls();
102      bool enabled = Content != null && !ReadOnly;
103      refreshButton.Enabled = enabled;
104      addButton.Enabled = enabled;
105      removeButton.Enabled = enabled;
106      saveProjectButton.Enabled = enabled;
107      projectView.Enabled = enabled;
108      projectPermissionsView.Enabled = enabled;
109      projectResourcesView.Enabled = enabled;
110    }
111    #endregion
112
113    #region Event Handlers
114    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Project>> e) {
115      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Project>>>)Content_ItemsAdded, sender, e);
116      else {
117        OnContentChanged();
118      }
119    }
120
121    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Project>> e) {
122      if (InvokeRequired) Invoke((Action<object, CollectionItemsChangedEventArgs<IndexedItem<Project>>>)Content_ItemsRemoved, sender, e);
123      else {
124        OnContentChanged();
125      }
126    }
127
128    private void ProjectViewContent_PropertyChanged(object sender, PropertyChangedEventArgs e) {
129      if (InvokeRequired) Invoke((Action<object, PropertyChangedEventArgs>)ProjectViewContent_PropertyChanged, sender, e);
130      else {
131        OnContentChanged();
132      }
133    }
134
135    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
136      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
137      else {
138        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
139        mainForm.AddOperationProgressToView(this, "Refreshing ...");
140        SetEnabledStateOfControls();
141      }
142    }
143
144    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
145      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
146      else {
147        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
148        mainForm.RemoveOperationProgressFromView(this);
149        SetEnabledStateOfControls();
150      }
151    }
152
153    private void AccessClient_Instance_Refreshing(object sender, EventArgs e) {
154      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshing, sender, e);
155      else {
156        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
157        mainForm.AddOperationProgressToView(this, "Refreshing ...");
158        SetEnabledStateOfControls();
159      }
160    }
161
162    private void AccessClient_Instance_Refreshed(object sender, EventArgs e) {
163      if (InvokeRequired) Invoke((Action<object, EventArgs>)AccessClient_Instance_Refreshed, sender, e);
164      else {
165        var mainForm = MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>();
166        mainForm.RemoveOperationProgressFromView(this);
167        SetEnabledStateOfControls();
168      }
169    }
170
171    private async void ProjectsView_Load(object sender, EventArgs e) {
172      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
173        action: () => UpdateProjects(),
174        finallyCallback: () => Content = HiveAdminClient.Instance.Projects);
175    }
176
177    private async void refreshButton_Click(object sender, EventArgs e) {
178      lock (locker) {
179        if (!refreshButton.Enabled) return;
180        refreshButton.Enabled = false;
181      }
182
183      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
184        action: () => UpdateProjects(),
185        finallyCallback: () => {
186          Content = HiveAdminClient.Instance.Projects;
187          refreshButton.Enabled = true;
188        });
189    }
190
191    private void addButton_Click(object sender, EventArgs e) {
192      var project = new Project {
193        Name = "New Project",
194        OwnerUserId = UserInformation.Instance.User.Id
195      };
196      Content.Add(project);
197    }
198
199    private async void removeButton_Click(object sender, EventArgs e) {
200      lock (locker) {
201        if (!removeButton.Enabled) return;
202        removeButton.Enabled = false;
203      }
204
205      var selectedNode = projectsTreeView.SelectedNode;
206      if (selectedNode == null || selectedNode.Tag == null) return;
207
208      var project = (Project)selectedNode.Tag;
209      var result = MessageBox.Show(
210        "Do you really want to delete " + project.Name + "?",
211        "HeuristicLab Hive Administrator",
212        MessageBoxButtons.YesNo,
213        MessageBoxIcon.Question);
214
215      if (result == DialogResult.Yes) {
216        if (Content.Any(x => x.ParentProjectId == project.Id)) {
217          MessageBox.Show(
218            "Only empty projects can be deleted.",
219            "HeuristicLab Hive Administrator",
220            MessageBoxButtons.OK,
221            MessageBoxIcon.Error);
222        } else {
223          await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
224            action: () => RemoveProject(project),
225            finallyCallback: () => {
226              Content.Remove(project);
227              removeButton.Enabled = true;
228            });
229        }
230      }
231    }
232
233    private async void saveProjectButton_Click(object sender, EventArgs e) {
234      lock (locker) {
235        if (!saveProjectButton.Enabled) return;
236        saveProjectButton.Enabled = false;
237      }
238
239      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
240        action: () => {
241          var projectsToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
242          foreach (var project in projectsToSave)
243            project.Store();
244        },
245        finallyCallback: () => saveProjectButton.Enabled = true);
246    }
247
248    private void projectsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
249      var selectedProject = (Project)e.Node.Tag;
250      ReColorTreeNodes(projectsTreeView.Nodes, selectedColor, Color.Transparent);
251      e.Node.BackColor = selectedColor;
252     
253
254      if (projectView.Content != null)
255        projectView.Content.PropertyChanged -= ProjectViewContent_PropertyChanged;
256
257      projectView.Content = selectedProject;
258      projectPermissionsView.Content = selectedProject;
259      projectResourcesView.Content = selectedProject;
260
261      if (selectedProject != null)
262        selectedProject.PropertyChanged += ProjectViewContent_PropertyChanged;
263
264      if (IsAuthorized(selectedProject)) {
265        if (!tabControl.TabPages.Contains(permissionsTabPage))
266          tabControl.TabPages.Add(permissionsTabPage);
267        if (!tabControl.TabPages.Contains(resourcesTabPage))
268          tabControl.TabPages.Add(resourcesTabPage);
269      } else {
270        if (tabControl.TabPages.Contains(permissionsTabPage))
271          tabControl.TabPages.Remove(permissionsTabPage);
272        if (tabControl.TabPages.Contains(resourcesTabPage))
273          tabControl.TabPages.Remove(resourcesTabPage);
274      }
275    }
276
277    private void projectsTreeView_DragDrop(object sender, DragEventArgs e) {
278      var sourceNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
279      if (sourceNode == null) return;
280
281      var treeView = (TreeView)sender;
282      if (sourceNode.TreeView != treeView) return;
283
284      var targetPoint = treeView.PointToClient(new Point(e.X, e.Y));
285      var targetNode = treeView.GetNodeAt(targetPoint);
286
287      if (sourceNode == targetNode) return;
288
289      if (sourceNode.Parent == null)
290        treeView.Nodes.Remove(sourceNode);
291      else {
292        sourceNode.Parent.Nodes.Remove(sourceNode);
293        ((Project)sourceNode.Tag).ParentProjectId = null;
294      }
295
296      if (targetNode == null) {
297        treeView.Nodes.Add(sourceNode);
298      } else {
299        targetNode.Nodes.Add(sourceNode);
300        ((Project)sourceNode.Tag).ParentProjectId = ((Project)targetNode.Tag).Id;
301      }
302    }
303
304    private void projectsTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
305      var sourceNode = (TreeNode)e.Item;
306      if (IsAuthorized((Project)sourceNode.Tag))
307        DoDragDrop(sourceNode, DragDropEffects.All);
308    }
309
310    private void projectsTreeView_DragEnter(object sender, DragEventArgs e) {
311      e.Effect = DragDropEffects.Move;
312    }
313
314    private void projectsTreeView_DragOver(object sender, DragEventArgs e) {
315      e.Effect = DragDropEffects.Move;
316    }
317
318    private void projectsTreeView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) {
319      e.Action = DragAction.Continue;
320    }
321    #endregion
322
323    #region Helpers
324    private void ReColorTreeNodes(TreeNodeCollection nodes, Color c1, Color c2) {
325      foreach(TreeNode n in nodes) {
326        if(n.BackColor.Equals(c1)) {
327          n.BackColor = c2;
328        }
329        if (n.Nodes.Count > 0) {
330          ReColorTreeNodes(n.Nodes, c1, c2);
331        }
332      }
333    }
334
335    private Project BuildProjectTree(IEnumerable<Project> projects) {
336      projectsTreeView.Nodes.Clear();
337      if (!projects.Any()) return null;
338
339      var mainProjects = new HashSet<Project>(projects.Where(x => x.ParentProjectId == null));
340      var subProbjects = new HashSet<Project>(projects.Except(mainProjects));
341
342      var stack = new Stack<Project>(mainProjects.OrderByDescending(x => x.Name));
343      var top = stack.Peek();
344      bool first = true;
345
346      TreeNode currentNode = null;
347      Project currentProject = null;
348     
349      while (stack.Any()) {
350        var newProject = stack.Pop();
351        var newNode = new TreeNode(newProject.Name) { Tag = newProject };
352        if (first) {
353          newNode.BackColor = selectedColor;
354          first = false;
355        }
356
357        while (currentNode != null && newProject.ParentProjectId != currentProject.Id) {
358          currentNode = currentNode.Parent;
359          currentProject = currentNode == null ? null : (Project)currentNode.Tag;
360        }
361
362        if (currentNode == null) {
363          projectsTreeView.Nodes.Add(newNode);
364          newNode.ImageIndex = greenFlagImageIndex;
365        } else {
366          currentNode.Nodes.Add(newNode);
367          newNode.ImageIndex = redFlagImageIndex;
368        }
369
370        newNode.SelectedImageIndex = newNode.ImageIndex;
371
372        var childProjects = subProbjects.Where(x => x.ParentProjectId == newProject.Id);
373        if (childProjects.Any()) {
374          foreach (var project in childProjects.OrderByDescending(x => x.Name)) {
375            subProbjects.Remove(project);
376            stack.Push(project);
377          }
378          currentNode = newNode;
379          currentProject = newProject;
380        }
381      }
382
383      projectsTreeView.ExpandAll();
384
385      return top;
386    }
387
388    private void UpdateProjects() {
389      try {
390        HiveAdminClient.Instance.Refresh();
391      } catch (AnonymousUserException) {
392        ShowHiveInformationDialog();
393      }
394    }
395
396    private void RemoveProject(Project project) {
397      try {
398        HiveAdminClient.Delete(project);
399      } catch (AnonymousUserException) {
400        ShowHiveInformationDialog();
401      }
402    }
403
404    private bool IsAuthorized(Project project) {
405      return project != null
406          && UserInformation.Instance.UserExists
407          && (project.OwnerUserId == UserInformation.Instance.User.Id || HiveRoles.CheckAdminUserPermissions());
408    }
409
410    private void ShowHiveInformationDialog() {
411      if (InvokeRequired) Invoke((Action)ShowHiveInformationDialog);
412      else {
413        using (HiveInformationDialog dialog = new HiveInformationDialog()) {
414          dialog.ShowDialog(this);
415        }
416      }
417    }
418    #endregion
419  }
420}
Note: See TracBrowser for help on using the repository browser.