/*
* Copyright (c) 2009 Craig Sutherland
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
namespace FastForward.Monitor
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using FastForward.Monitor.Properties;
using FastForward.WinCore;
using FastForward.WinCore.Configuration;
using ThoughtWorks.CruiseControl.Remote;
using ThoughtWorks.CruiseControl.Remote.Monitor;
using ThoughtWorks.CruiseControl.Remote.Parameters;
///
/// The main UI for the application.
///
public partial class MainForm
: Form
{
#region Private fields
private ApplicationConfig configuration;
private ServerList serverList;
private object selectedControl;
private Dictionary servers = new Dictionary();
private Dictionary queues = new Dictionary();
private Dictionary requests = new Dictionary();
private int allQueuesSort = 0;
private int allQueueRequestsSort = 0;
private WindowManager webPages = new WindowManager();
private WindowManager currentStatuses = new WindowManager();
private WindowManager buildHistories = new WindowManager();
private WindowManager packages = new WindowManager();
private WindowManager properties = new WindowManager();
private PluginHost pluginHost;
private Dictionary plugins = new Dictionary();
private Dictionary pluginTabs = new Dictionary();
private Dictionary allErrors = new Dictionary();
#endregion
#region Constructors
///
/// Initialise a new .
///
///
///
public MainForm(ServerList servers, ApplicationConfig configuration)
{
InitializeComponent();
this.configuration = configuration;
this.serverList = servers;
}
#endregion
#region Public methods
#region InitialiseForm()
///
/// Initialise the main form.
///
public void InitialiseForm()
{
using (Trace.Start("Initialising main form"))
{
pluginHost = new MainFormPluginHost(this);
serverList.ServerAdded += servers_ServerAdded;
serverList.ServerRemoved += servers_ServerRemoved;
foreach (var server in serverList.Servers)
{
AddServer(server);
}
RefreshServers();
selectedControl = allProjectsView;
InitialiseFromConfiguration();
DisplayStatus("Application loaded");
}
}
#endregion
#region Terminate()
///
/// Shut down the application.
///
public void Terminate()
{
foreach (var plugin in plugins.Values)
{
try
{
plugin.Terminate();
}
catch
{
// Ignore any errors here - this could be due to the UI being unstable
}
}
// Just to make sure we don't re-terminate and shutdown again
plugins.Clear();
}
#endregion
#region LogErrorMessage()
///
/// Logs an error message.
///
///
///
public void LogErrorMessage(string source, string message)
{
allErrors.Add(DateTime.Now, message);
var count = allErrors.Count;
errorReport.Text = string.Format("{0} error{1}", count, count == 1 ? string.Empty : "s");
statusLabel.Text = message;
statusLabel.Image = applicationImages.Images["Failure"];
statusLabel.Owner.Refresh();
}
#endregion
#region DisplayStatus()
///
/// Display a success message.
///
/// The message to display.
public void DisplayStatus(string message)
{
statusLabel.Text = message;
statusLabel.Image = applicationImages.Images["Success"];
statusLabel.Owner.Refresh();
}
///
/// Display a success message.
///
/// The message to display.
public void DisplayStatus(string message, int count, string singleItem, string pluralItem)
{
statusLabel.Text = string.Format(message, count, count == 1 ? singleItem : pluralItem);
statusLabel.Image = applicationImages.Images["Success"];
statusLabel.Owner.Refresh();
}
#endregion
#endregion
#region Private methods
#region InitialiseFromConfiguration()
///
/// Initialise this form from the configuration.
///
private void InitialiseFromConfiguration()
{
using (Trace.Start("Loading configuration settings"))
{
// Load the window position
if (configuration.Monitor.Left != int.MinValue) Left = configuration.Monitor.Left;
if (configuration.Monitor.Top != int.MinValue) Top = configuration.Monitor.Top;
if (configuration.Monitor.Width != int.MinValue) Width = configuration.Monitor.Width;
if (configuration.Monitor.Height != int.MinValue) Height = configuration.Monitor.Height;
WindowState = configuration.Monitor.State;
// Set the windows properties
ChangeWindowsProperties();
webPages.ConfiguredWindows.AddRange(from record in configuration.ConfiguredWindows where record.Name.StartsWith("WebPage") select record);
currentStatuses.ConfiguredWindows.AddRange(from record in configuration.ConfiguredWindows where record.Name.StartsWith("Status") select record);
buildHistories.ConfiguredWindows.AddRange(from record in configuration.ConfiguredWindows where record.Name.StartsWith("History") select record);
packages.ConfiguredWindows.AddRange(from record in configuration.ConfiguredWindows where record.Name.StartsWith("Packages") select record);
properties.ConfiguredWindows.AddRange(from record in configuration.ConfiguredWindows where record.Name.StartsWith("Properties") select record);
// Load the visibility settings
monitorExplorerDisplay.Checked = !configuration.Monitor.ShowExplorer;
monitorExplorerDisplay_Click(null, null);
groupByServerMenu.Checked = !configuration.Monitor.GroupByServer;
groupByServerMenu_Click(null, null);
// Load the list views
allProjectsView.LoadFromConfig(configuration.Monitor.ListViews);
allQueuesSort = ListViewHelper.LoadListView(allQueuesList, configuration.Monitor.ListViews);
allQueueRequestsSort = ListViewHelper.LoadListView(allQueueRequestsList, configuration.Monitor.ListViews);
// Load the plugins
InitialisePlugins();
// Load the tabs
DisplayTabs();
}
}
#endregion
#region DisplayTabs()
///
/// Display the tabs in the correct order.
///
private void DisplayTabs()
{
using (Trace.Start("Displaying tabs"))
{
// The tabs have not been loaded - make sure they are all loaded.
if (configuration.Monitor.Tabs.Count == 0)
{
configuration.Monitor.Tabs.AddRange(new TabConfig[] {
new TabConfig { Key = "AllProjects", Text = "All Projects", Order = 0, Type = TabConfigType.System },
new TabConfig { Key = "AllQueues", Text = "All Queues", Order = 1, Type = TabConfigType.System },
new TabConfig { Key = "AllQueueRequests", Text = "All Queue Requests", Order = 2, Type = TabConfigType.System }
});
}
// Add all the tabs
monitorTabs.TabPages.Clear();
foreach (var tab in from record in configuration.Monitor.Tabs
orderby record.Order
select record)
{
// Initialise the tab
switch (tab.Type)
{
case TabConfigType.System:
// Add the system tabs
switch (tab.Key)
{
case "AllProjects":
monitorTabs.TabPages.Add(allProjectsPage);
break;
case "AllQueues":
monitorTabs.TabPages.Add(allQueuesPage);
break;
case "AllQueueRequests":
monitorTabs.TabPages.Add(allQueueRequestsPage);
break;
}
break;
case TabConfigType.Plugin:
if (pluginTabs.ContainsKey(tab.Key))
{
monitorTabs.TabPages.Add(pluginTabs[tab.Key]);
}
break;
}
}
}
}
#endregion
#region InitialisePlugins()
///
/// Initialise the plugins.
///
private void InitialisePlugins()
{
using (Trace.Start("Initialising plug-ins"))
{
// Make sure the plug-ins location exists
try
{
if (!Directory.Exists(configuration.DefaultPluginLocation)) Directory.CreateDirectory(configuration.DefaultPluginLocation);
}
catch
{
// This may fail because of security
}
// Initialise all the plugins
var invalidPlugins = new List();
foreach (var plugin in configuration.LoadedPlugins)
{
try
{
using (Trace.Start("Starting plug-in: " + plugin.Type))
{
var instance = Plugin.StartNew(plugin);
instance.Initialise(pluginHost, serverList);
plugins.Add(plugin.Key, instance);
}
}
catch (Exception error)
{
MessageBox.Show(
"Unable to load plug-in " + plugin.Type + ", plug-in will be removed" + Environment.NewLine + error.Message,
"Plug-in error",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
invalidPlugins.Add(plugin);
}
}
// Remove the invalid plugins
foreach (var plugin in invalidPlugins)
{
configuration.LoadedPlugins.Remove(plugin);
}
}
}
#endregion
#region ChangeWindowsProperties
///
/// Change the windows settings to use the settings from the configuration.
///
private void ChangeWindowsProperties()
{
ShowInTaskbar = configuration.Monitor.ShowInTaskBar;
TopMost = configuration.Monitor.AlwaysOnTop;
}
#endregion
#region AddServer()
///
/// Add a new server.
///
///
private void AddServer(Server server)
{
var serverConfig = server.Data.Get();
// Add the groups
server.DisplayName = serverConfig.Name;
var serverName = server.GetDisplayName(true);
allProjectsView.AddServer(server, serverConfig);
allQueuesList.Groups.Add(server.TargetAddress, serverName);
allQueueRequestsList.Groups.Add(server.TargetAddress, serverName);
var node = new ServerTreeNode(server, serverConfig);
monitorExplorer.Nodes.Add(node);
servers.Add(server, node);
// Add the queues
server.BuildQueueAdded += server_BuildQueueAdded;
server.BuildQueueRemoved += server_BuildQueueRemoved;
foreach (var queue in server.BuildQueues)
{
AddBuildQueue(queue);
}
}
#endregion
#region RemoveServer()
///
/// Remove an existing server.
///
///
private void RemoveServer(Server server)
{
if (servers.ContainsKey(server))
{
servers[server].Remove();
}
// Remove the queues
server.BuildQueueAdded -= server_BuildQueueAdded;
server.BuildQueueRemoved -= server_BuildQueueRemoved;
foreach (var queue in server.BuildQueues)
{
RemoveBuildQueue(queue);
}
// Remove the groups
allProjectsView.RemoveServer(server);
allQueuesList.Groups.Add(allQueuesList.Groups[server.TargetAddress]);
allQueueRequestsList.Groups.Add(allQueueRequestsList.Groups[server.TargetAddress]);
}
#endregion
#region AddBuildQueue()
///
/// Add a new buid queue.
///
///
private void AddBuildQueue(BuildQueue queue)
{
queue.BuildQueueRequestAdded += queue_BuildQueueRequestAdded;
queue.BuildQueueRequestRemoved += queue_BuildQueueRequestRemoved;
var item = new BuildQueueListViewItem(queue);
allQueuesList.Items.Add(item);
queues.Add(queue, item);
item.Group = allQueuesList.Groups[queue.Server.TargetAddress];
}
#endregion
#region RemoveBuildQueue
///
/// Remove an existing build queue.
///
///
private void RemoveBuildQueue(BuildQueue queue)
{
queue.BuildQueueRequestAdded -= queue_BuildQueueRequestAdded;
queue.BuildQueueRequestRemoved -= queue_BuildQueueRequestRemoved;
if (queues.ContainsKey(queue))
{
queues[queue].Remove();
}
foreach (var request in queue.Requests)
{
if (requests.ContainsKey(request))
{
requests[request].Remove();
}
}
}
#endregion
#region AddBuildQueueRequest()
///
/// Add a new build queue request.
///
///
private void AddBuildQueueRequest(BuildQueueRequest value)
{
if (!requests.ContainsKey(value))
{
var item = new BuildQueueRequestListViewItem(value);
allQueueRequestsList.Items.Add(item);
requests.Add(value, item);
item.Group = allQueueRequestsList.Groups[value.BuildQueue.Server.TargetAddress];
}
}
#endregion
#region ForceBuild()
///
/// Force a build for the currently selected projects.
///
private void ForceBuild()
{
var projects = GetSelectedProjects();
if (projects.Count() == 0)
{
MessageBox.Show("There were no projects selected");
}
else
{
using (Trace.Start("Sending force build commands"))
{
// Check for any parameters
var parameters = new Dictionary>();
foreach (var project in projects)
{
try
{
parameters.Add(project, project.RetrieveParameters());
}
catch (NotImplementedException)
{
// The underlying server does not have any parameters functionality
parameters.Add(project, new List());
}
}
// Count the number of parameters
var parameterCount = (from record in parameters.Values
select record.Count()).Sum();
if (parameterCount > 0)
{
// Prompt the user for the parameters first
var form = new BuildParametersForm(parameters, this);
form.ShowDialog(this);
}
else
{
// No parameters - just send the requests
foreach (var project in projects)
{
using (Trace.Start("Sending force build to " + project.Name))
{
SendRequest(p => p.ForceBuild(), project, project.Name);
}
}
DisplayStatus("Force build sent to {0} {1}", projects.Count(), "project", "projects");
}
}
}
}
#endregion
#region AbortBuild()
///
/// Abort a build for the currently selected projects.
///
private void AbortBuild()
{
var projects = GetSelectedProjects();
if (projects.Count() == 0)
{
MessageBox.Show("There were no projects selected");
}
else
{
using (Trace.Start("Sending abort build commands"))
{
foreach (var project in projects)
{
using (Trace.Start("Sending abort build to " + project.Name))
{
SendRequest(p => p.AbortBuild(), project, project.Name);
}
}
DisplayStatus("Abort build sent to {0} {1}", projects.Count(), "project", "projects");
}
}
}
#endregion
#region StartProject()
///
/// Start the currently selected projects
///
private void StartProject()
{
var projects = GetSelectedProjects();
if (projects.Count() == 0)
{
MessageBox.Show("There were no projects selected");
}
else
{
using (Trace.Start("Sending start project commands"))
{
foreach (var project in projects)
{
using (Trace.Start("Sending start project to " + project.Name))
{
SendRequest(p => p.Start(), project, project.Name);
}
}
DisplayStatus("Start project sent to {0} {1}", projects.Count(), "project", "projects");
}
}
}
#endregion
#region StopProject()
///
/// Stop the currently selected projects.
///
private void StopProject()
{
var projects = GetSelectedProjects();
if (projects.Count() == 0)
{
MessageBox.Show("There were no projects selected");
}
else
{
using (Trace.Start("Sending stop project commands"))
{
foreach (var project in projects)
{
using (Trace.Start("Sending stop project to " + project.Name))
{
SendRequest(p => p.Stop(), project, project.Name);
}
}
DisplayStatus("Stop project sent to {0} {1}", projects.Count(), "project", "projects");
}
}
}
#endregion
#region RefreshServers()
///
/// Refresh all the servers.
///
private void RefreshServers()
{
foreach (var server in serverList.Servers)
{
using (Trace.Start("Refreshing server: " + server.GetDisplayName(true)))
{
SendRequest(s => s.Refresh(), server, server.GetDisplayName());
}
}
}
#endregion
#region ChangeSettings()
///
/// Allow the user to change the configuration settings.
///
private void ChangeSettings()
{
// Need to change this otherwise the settings form will be underneath!
var topMost = TopMost;
TopMost = false;
var settingsForm = new SettingsForm(configuration);
settingsForm.OkClicked += (o, a) =>
{
this.SafeInvoke(() =>
{
topMost = ReloadAfterSettingsChange(settingsForm);
});
};
settingsForm.ShowDialog();
TopMost = topMost;
}
#endregion
#region ReloadAfterSettingsChange()
///
/// Reload the settings after they have been changed.
///
///
///
private bool ReloadAfterSettingsChange(SettingsForm settingsForm)
{
using (Trace.Start("Reloading configuration settings"))
{
var oldServers = configuration.Servers;
configuration.Servers = settingsForm.Configuration.Servers;
UpdateServers(oldServers);
RefreshServers();
// Set the windows properties
configuration.Monitor = settingsForm.Configuration.Monitor;
ChangeWindowsProperties();
var topMost = configuration.Monitor.AlwaysOnTop;
// Reload all the projects
allProjectsView.Clear();
foreach (var server in serverList.Servers)
{
var serverConfig = server.Data.Get();
serverConfig.Server.DisplayName = serverConfig.Name;
allProjectsView.AddServer(server, serverConfig);
}
// Copy the templates and plugins over
configuration.BuildTemplates = settingsForm.Configuration.BuildTemplates;
UpdatePlugins(settingsForm);
// Copy the tabs over
configuration.Monitor.Tabs = settingsForm.Configuration.Monitor.Tabs;
DisplayTabs();
// Save the configuration
configuration.Save();
BringToFront();
return topMost;
}
}
#endregion
#region UpdatePlugins()
///
/// Update all the plugins.
///
///
private void UpdatePlugins(SettingsForm settingsForm)
{
using (Trace.Start("Updating plugins"))
{
// Store the current list of plugins
var currentPlugins = (from key in plugins
select key.Key).ToList();
foreach (var plugin in settingsForm.Configuration.LoadedPlugins)
{
// Check if the plugin was previously loaded
if (currentPlugins.Contains(plugin.Key))
{
// If so, just update it
var current = configuration.FindPlugin(plugin.Key);
if (current.Data != plugin.Data)
{
current.Data = plugin.Data;
plugins[current.Key].UpdateConfiguration(current);
}
currentPlugins.Remove(current.Key);
}
else
{
// Otherwise the new plugin needs to be initialised
try
{
var newPlugin = Plugin.StartNew(plugin);
newPlugin.Initialise(pluginHost, serverList);
plugins.Add(plugin.Key, newPlugin);
configuration.LoadedPlugins.Add(plugin);
}
catch (Exception error)
{
MessageBox.Show(
"Unable to load plugin " + plugin.Type + ", plugin will be removed" + Environment.NewLine + error.Message,
"Plug-in error",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
}
// Terminate any old plugins
foreach (var plugin in currentPlugins)
{
plugins[plugin].Terminate();
plugins.Remove(plugin);
var current = configuration.FindPlugin(plugin);
configuration.LoadedPlugins.Remove(current);
}
}
}
#endregion
#region UpdateServers()
///
/// Update all the servers.
///
///
private void UpdateServers(List previousServers)
{
using (Trace.Start("Updating servers"))
{
var oldServers = new List();
oldServers.AddRange(from record in serverList.Servers
select record.Data.Get());
foreach (var server in configuration.Servers)
{
var oldServer = (from record in oldServers
where (record.Address == server.Address) && (record.TargetServer == server.TargetServer)
select record).SingleOrDefault();
if (oldServer != null)
{
var hasChanged = (oldServer.PollingInterval != server.PollingInterval) ||
(oldServer.UseEncryption != server.UseEncryption);
if (hasChanged)
{
serverList.UpdateServer(server);
}
if (oldServer.Server != null)
{
oldServer.Server.Data.Set(server);
oldServer.Server.DisplayName = server.Name;
}
oldServers.Remove(oldServer);
}
else
{
serverList.AddServer(server);
}
}
foreach (var oldServer in oldServers)
{
serverList.RemoveServer(oldServer);
}
}
}
#endregion
#region GetSelectedProjects()
///
/// Get all the currently selected projects.
///
///
private IEnumerable GetSelectedProjects()
{
var list = new List();
if (selectedControl is IProjectSelector)
{
list.AddRange((selectedControl as IProjectSelector).GetSelectedProjects());
}
else if (selectedControl is ListView)
{
foreach (var item in (selectedControl as ListView).SelectedItems)
{
var projectItem = item as ProjectListViewItem;
if (projectItem != null) list.Add(projectItem.Project);
}
}
else if (selectedControl is TreeView)
{
var projectNode = (selectedControl as TreeView).SelectedNode as ProjectTreeNode;
if (projectNode != null) list.Add(projectNode.Project);
}
return list;
}
#endregion
#region GetSelectedQueues()
///
/// Get all the currently selected build queues.
///
///
private IEnumerable GetSelectedQueues()
{
var list = new List();
if (selectedControl is ListView)
{
foreach (var item in (selectedControl as ListView).SelectedItems)
{
var queueItem = item as BuildQueueListViewItem;
if (queueItem != null) list.Add(queueItem.BuildQueue);
}
}
else if (selectedControl is TreeView)
{
var queueNode = (selectedControl as TreeView).SelectedNode as BuildQueueTreeNode;
if (queueNode != null) list.Add(queueNode.BuildQueue);
}
return list;
}
#endregion
#region GetSelectedServers()
///
/// Get all the currently selected servers.
///
///
private IEnumerable GetSelectedServers()
{
var list = new List();
if (selectedControl is TreeView)
{
var serverNode = (selectedControl as TreeView).SelectedNode as ServerTreeNode;
if (serverNode != null) list.Add(serverNode.Server);
}
return list;
}
#endregion
#region SendRequest()
///
/// Pool a request for a remote server to process.
///
///
///
///
private void SendRequest(Action request, T value, string source)
{
ThreadPool.QueueUserWorkItem(o =>
{
try
{
request((T)o);
}
catch (NotImplementedException)
{
LogErrorMessage(source, "This functionality is not allowed on the underlying client");
}
catch (Exception error)
{
error.SaveLog();
LogErrorMessage(source, error.Message);
}
}, value);
}
#endregion
#region ShowWebPage()
///
/// Display the web page for the selected projects.
///
private void ShowWebPage()
{
var projects = GetSelectedProjects();
ShowWebPage(projects);
}
///
/// Display the web page for some projects.
///
private void ShowWebPage(IEnumerable projects)
{
if (projects.Count() == 0)
{
MessageBox.Show(this, "There are no projects selected", "View web page", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
foreach (var project in projects)
{
using (Trace.Start("Displaying web page for " + project.Name))
{
webPages.Show(project, p => new WebPageForm(p, this), string.Format("WebPage:{0}:{1}", project.Server.TargetAddress, project.Name));
}
}
}
}
#endregion
#region ShowPackages
///
/// Display the packages for the selected projects.
///
private void ShowPackages()
{
var projects = GetSelectedProjects();
ShowPackages(projects);
}
///
/// Display the packages for the selected projects.
///
private void ShowPackages(IEnumerable projects)
{
if (projects.Count() == 0)
{
MessageBox.Show(this, "There are no projects selected", "View packages", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
foreach (var project in projects)
{
using (Trace.Start("Displaying packages for " + project.Name))
{
packages.Show(project, p => new PackagesForm(p, this), string.Format("Packages:{0}:{1}", project.Server.TargetAddress, project.Name));
}
}
}
}
#endregion
#region ShowCurrentStatus()
///
/// Display the current status for the selected projects.
///
private void ShowCurrentStatus()
{
var projects = GetSelectedProjects();
ShowCurrentStatus(projects);
}
///
/// Display the current status for the selected projects.
///
private void ShowCurrentStatus(IEnumerable projects)
{
if (projects.Count() == 0)
{
MessageBox.Show(this, "There are no projects selected", "View current project status", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
foreach (var project in projects)
{
using (Trace.Start("Displaying current status for " + project.Name))
{
currentStatuses.Show(project, p => new CurrentStatusForm(p, this), string.Format("Status:{0}:{1}", project.Server.TargetAddress, project.Name));
}
}
}
}
#endregion
#region ShowBuildHistory()
///
/// Display the build history for the selected projects.
///
private void ShowBuildHistory()
{
var projects = GetSelectedProjects();
ShowBuildHistory(projects);
}
///
/// Display the build history for some projects.
///
/// The projects to show the build history for.
private void ShowBuildHistory(IEnumerable projects)
{
if (projects.Count() == 0)
{
MessageBox.Show(this, "There are no projects selected", "View build history", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
foreach (var project in projects)
{
using (Trace.Start("Displaying build history for " + project.Name))
{
buildHistories.Show(project, p => new BuildHistoryForm(p, configuration, this), string.Format("History:{0}:{1}", project.Server.TargetAddress, project.Name));
}
}
}
}
#endregion
#region Login()
///
/// Login to a remote server.
///
private void Login()
{
if (serverList.Servers.Count() == 0)
{
MessageBox.Show(this,
"At least one server must be defined first",
"Unable to login",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
else
{
var login = new LoginForm(serverList);
login.ShowDialog(this);
}
}
#endregion
#region Logout()
///
/// Logout from a remote server.
///
private void Logout()
{
if (serverList.Servers.Count() == 0)
{
MessageBox.Show(this,
"At least one server must be defined first",
"Unable to login",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
else
{
var logoutForm = new LogoutForm(serverList);
logoutForm.ShowDialog(this);
}
}
#endregion
#region ShowProperties()
///
/// View the properties of the currently selected items.
///
private void ShowProperties()
{
var selectedItems = new List();
selectedItems.AddRange(from record in GetSelectedServers()
select new ServerProperties(record) as INotifyPropertyChanged);
selectedItems.AddRange(from record in GetSelectedProjects()
select new ProjectProperties(record) as INotifyPropertyChanged);
selectedItems.AddRange(from record in GetSelectedQueues()
select new BuildQueueProperties(record) as INotifyPropertyChanged);
if (selectedItems.Count() == 0)
{
MessageBox.Show("There is nothing selected");
}
else
{
foreach (INotifyPropertyChanged item in selectedItems)
{
using (Trace.Start("Displaying web page for " + item.GetType().Name))
{
properties.Show(item, o => new PropertiesForm(o, this), string.Format("Properties:{0}", item));
}
}
}
}
#endregion
#region PerformProjectDoubleClick()
///
/// Performs a double click action on a project.
///
///
private void PerformProjectDoubleClick(IEnumerable projects)
{
if (projects.Count() > 0)
{
switch (this.configuration.Monitor.AllProjectsDoubleClickAction)
{
case "View Build History":
ShowBuildHistory(projects);
break;
case "View Current Status":
ShowCurrentStatus(projects);
break;
case "View Packages":
ShowPackages(projects);
break;
case "View Properties":
ShowProperties();
break;
case "View Web Page":
ShowWebPage(projects);
break;
}
}
}
#endregion
#endregion
#region Event handlers
#region servers_ServerAdded()
///
/// A new server has been added.
///
///
///
private void servers_ServerAdded(object sender, ServerChangedArgs e)
{
this.SafeInvoke(() =>
{
AddServer(e.Server);
});
}
#endregion
#region servers_ServerRemoved()
///
/// An existing server has been removed.
///
///
///
private void servers_ServerRemoved(object sender, ServerChangedArgs e)
{
this.SafeInvoke(() =>
{
RemoveServer(e.Server);
});
}
#endregion
#region server_BuildQueueAdded()
///
/// A build queue has been added to a server.
///
///
///
private void server_BuildQueueAdded(object sender, BuildQueueChangedArgs e)
{
this.SafeInvoke(() =>
{
AddBuildQueue(e.BuildQueue);
});
}
#endregion
#region server_BuildQueueRemoved()
///
/// A build queue has been removed from a server.
///
///
///
private void server_BuildQueueRemoved(object sender, BuildQueueChangedArgs e)
{
this.SafeInvoke(() =>
{
RemoveBuildQueue(e.BuildQueue);
});
}
#endregion
#region queue_BuildQueueRequestAdded()
///
/// A request has been added to a build queue.
///
///
///
private void queue_BuildQueueRequestAdded(object sender, BuildQueueRequestChangedArgs e)
{
this.SafeInvoke(() =>
{
AddBuildQueueRequest(e.BuildQueueRequest);
});
}
#endregion
#region queue_BuildQueueRequestRemoved()
///
/// A request has been removed from a build queue.
///
///
///
private void queue_BuildQueueRequestRemoved(object sender, BuildQueueRequestChangedArgs e)
{
this.SafeInvoke(() =>
{
if (requests.ContainsKey(e.BuildQueueRequest))
{
requests[e.BuildQueueRequest].Remove();
}
});
}
#endregion
#region exitMenu_Click()
///
/// The user has clicked on the exit menu button.
///
///
///
private void exitMenu_Click(object sender, EventArgs e)
{
Application.Exit();
}
#endregion
#region aboutMenu_Click()
///
/// The user has clicked on the about menu button.
///
///
///
private void aboutMenu_Click(object sender, EventArgs e)
{
var about = new AboutForm();
about.ShowDialog(this);
}
#endregion
#region forceBuildButton_Click()
///
/// The user has clicked on the force build button.
///
///
///
private void forceBuildButton_Click(object sender, EventArgs e)
{
ForceBuild();
}
#endregion
#region abortBuildButton_Click()
///
/// The user has clicked on the abort build button.
///
///
///
private void abortBuildButton_Click(object sender, EventArgs e)
{
AbortBuild();
}
#endregion
#region startProjectButton_Click()
///
/// The user has clicked on the start project button.
///
///
///
private void startProjectButton_Click(object sender, EventArgs e)
{
StartProject();
}
#endregion
#region stopProjectButton_Click()
///
/// The user has clicked on the stop project button.
///
///
///
private void stopProjectButton_Click(object sender, EventArgs e)
{
StopProject();
}
#endregion
#region refreshButton_Click()
///
/// The user has clicked on the refresh all button.
///
///
///
private void refreshButton_Click(object sender, EventArgs e)
{
RefreshServers();
}
#endregion
#region forceBuildMenu_Click()
///
/// The user has clicked on the force build menu button.
///
///
///
private void forceBuildMenu_Click(object sender, EventArgs e)
{
ForceBuild();
}
#endregion
#region abortBuildMenu_Click()
///
/// The user has clicked on the abort build menu button.
///
///
///
private void abortBuildMenu_Click(object sender, EventArgs e)
{
AbortBuild();
}
#endregion
#region startProjectMenu_Click()
///
/// The user has clicked on the start project menu button.
///
///
///
private void startProjectMenu_Click(object sender, EventArgs e)
{
StartProject();
}
#endregion
#region stopProjectMenu_Click()
///
/// The user has clicked on the stop project menu button.
///
///
///
private void stopProjectMenu_Click(object sender, EventArgs e)
{
StopProject();
}
#endregion
#region settingsMenu_Click()
///
/// The user has clicked on the settings menu button.
///
///
///
private void settingsMenu_Click(object sender, EventArgs e)
{
ChangeSettings();
}
#endregion
#region refreshAllServersMenu_Click()
///
/// The user has clicked on the refresh all servers menu button.
///
///
///
private void refreshAllServersMenu_Click(object sender, EventArgs e)
{
RefreshServers();
}
#endregion
#region monitorExplorerDisplay_Click()
///
/// The user has clicked on the show/hide monitor explorer menu button.
///
///
///
private void monitorExplorerDisplay_Click(object sender, EventArgs e)
{
monitorExplorerDisplay.Checked = !monitorExplorerDisplay.Checked;
monitorContainer.Panel1Collapsed = !monitorExplorerDisplay.Checked;
}
#endregion
#region OnSelectionChanged()
///
/// The user has changed between project list controls.
///
///
///
private void OnSelectionChanged(object sender, EventArgs e)
{
selectedControl = sender;
}
#endregion
#region groupByServerMenu_Click()
///
/// The user has clicked on the show/hide server groups button.
///
///
///
private void groupByServerMenu_Click(object sender, EventArgs e)
{
groupByServerMenu.Checked = !groupByServerMenu.Checked;
allProjectsView.ShowGroups = groupByServerMenu.Checked;
allQueuesList.ShowGroups = groupByServerMenu.Checked;
allQueueRequestsList.ShowGroups = groupByServerMenu.Checked;
}
#endregion
#region MainForm_FormClosing()
///
/// This form is closing.
///
///
///
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// First check if the form can be closed
var canClose = true;
if (e.CloseReason == CloseReason.UserClosing)
{
// Check each plug-in
foreach (var plugin in this.plugins.Values)
{
if (plugin.CloseAction == HostCloseAction.Hide)
{
canClose = false;
break;
}
}
e.Cancel = !canClose;
}
if (canClose)
{
// Store the current positions
configuration.Monitor.State = WindowState;
if (WindowState == FormWindowState.Normal)
{
configuration.Monitor.Left = Left;
configuration.Monitor.Top = Top;
configuration.Monitor.Width = Width;
configuration.Monitor.Height = Height;
}
// Save all the window positions
configuration.ConfiguredWindows.Clear();
configuration.ConfiguredWindows.AddRange(webPages.ConfiguredWindows);
configuration.ConfiguredWindows.AddRange(currentStatuses.ConfiguredWindows);
configuration.ConfiguredWindows.AddRange(buildHistories.ConfiguredWindows);
configuration.ConfiguredWindows.AddRange(packages.ConfiguredWindows);
configuration.ConfiguredWindows.AddRange(properties.ConfiguredWindows);
// Store the visibility options
configuration.Monitor.ShowExplorer = monitorExplorerDisplay.Checked;
configuration.Monitor.GroupByServer = groupByServerMenu.Checked;
// Save the list views
allProjectsView.SaveToConfig(configuration.Monitor.ListViews);
ListViewHelper.SaveListView(allQueuesList, allQueuesSort, configuration.Monitor.ListViews);
ListViewHelper.SaveListView(allQueueRequestsList, allQueueRequestsSort, configuration.Monitor.ListViews);
// Terminate all the plugins
foreach (var plugin in plugins.Values)
{
plugin.Terminate();
}
}
else
{
Hide();
}
}
#endregion
#region allQueueRequestsList_ColumnClick()
///
/// Sort by a column for the queue requests list view.
///
///
///
private void allQueueRequestsList_ColumnClick(object sender, ColumnClickEventArgs e)
{
allQueueRequestsSort = ListViewHelper.SortListView(allQueueRequestsList, e.Column, allQueueRequestsSort);
}
#endregion
#region allQueuesList_ColumnClick()
///
/// Sort by a column for the queues list view.
///
///
///
private void allQueuesList_ColumnClick(object sender, ColumnClickEventArgs e)
{
allQueuesSort = ListViewHelper.SortListView(allQueuesList, e.Column, allQueuesSort);
}
#endregion
#region webpageMenu_Click()
///
/// The user has clicked on the view web page menu button.
///
///
///
private void webpageMenu_Click(object sender, EventArgs e)
{
ShowWebPage();
}
#endregion
#region packagesMenu_Click()
///
/// The user has clicked on the package menu button.
///
///
///
private void packagesMenu_Click(object sender, EventArgs e)
{
ShowPackages();
}
#endregion
#region currentStatusMenu_Click()
///
/// The user has clicked on the current status menu button.
///
///
///
private void currentStatusMenu_Click(object sender, EventArgs e)
{
ShowCurrentStatus();
}
#endregion
#region displayWebPageContextMenu_Click()
///
/// The user has clicked on the display web page menu button in the context menu.
///
///
///
private void displayWebPageContextMenu_Click(object sender, EventArgs e)
{
ShowWebPage();
}
#endregion
#region projectContextMenu_Opening()
///
/// The context menu us being displayed.
///
///
///
private void projectContextMenu_Opening(object sender, CancelEventArgs e)
{
var projects = GetSelectedProjects();
var canForce = false;
var canAbort = false;
var canStart = false;
var canStop = false;
foreach (var project in projects)
{
canForce |= project.Activity.IsSleeping();
canAbort |= !project.Activity.IsSleeping();
canStart |= project.Status == ProjectIntegratorState.Stopped;
canStop |= project.Status == ProjectIntegratorState.Running;
}
forceBuildContextMenu.Visible = canForce;
abortBuildContextMenu.Visible = canAbort;
startprojectContextMenu.Visible = canStart;
stopProjectContextMenu.Visible = canStop;
}
#endregion
#region forceBuildContextMenu_Click()
///
/// The user has clicked on force build in the context menu.
///
///
///
private void forceBuildContextMenu_Click(object sender, EventArgs e)
{
ForceBuild();
}
#endregion
#region abortBuildContextMenu_Click()
///
/// The user has clicked on abort build in the context menu.
///
///
///
private void abortBuildContextMenu_Click(object sender, EventArgs e)
{
AbortBuild();
}
#endregion
#region startprojectContextMenu_Click()
///
/// The user has clicked on start project in the context menu.
///
///
///
private void startprojectContextMenu_Click(object sender, EventArgs e)
{
StartProject();
}
#endregion
#region stopProjectContextMenu_Click()
///
/// The user has clicked on stop project in the context menu.
///
///
///
private void stopProjectContextMenu_Click(object sender, EventArgs e)
{
StopProject();
}
#endregion
#region currentStatusContextMenu_Click()
///
/// The user has clicked on current status in the context menu.
///
///
///
private void currentStatusContextMenu_Click(object sender, EventArgs e)
{
ShowCurrentStatus();
}
#endregion
#region packagesContextMenu_Click()
///
/// The user has clicked on packages in context menu.
///
///
///
private void packagesContextMenu_Click(object sender, EventArgs e)
{
ShowPackages();
}
#endregion
#region viewWebPageButton_Click()
///
/// The user has clicked on the view web page button.
///
///
///
private void viewWebPageButton_Click(object sender, EventArgs e)
{
ShowWebPage();
}
#endregion
#region viewCurrentStatusButton_Click()
///
/// The user has clicked on the current status button.
///
///
///
private void viewCurrentStatusButton_Click(object sender, EventArgs e)
{
ShowCurrentStatus();
}
#endregion
#region viewPackagesButton_Click()
///
/// The user has clicked on the packages button.
///
///
///
private void viewPackagesButton_Click(object sender, EventArgs e)
{
ShowPackages();
}
#endregion
#region buildHistoryButton_Click()
///
/// The user has clicked on the build history button.
///
///
///
private void buildHistoryButton_Click(object sender, EventArgs e)
{
ShowBuildHistory();
}
#endregion
#region buildHistoryMenu_Click()
///
/// The user has clicked on build history in the menu.
///
///
///
private void buildHistoryMenu_Click(object sender, EventArgs e)
{
ShowBuildHistory();
}
#endregion
#region buildHistoryContextMenu_Click
///
/// The user has clicked on build history in the context menu.
///
///
///
private void buildHistoryContextMenu_Click(object sender, EventArgs e)
{
ShowBuildHistory();
}
#endregion
#region loginMenu_Click()
///
/// The user has clicked on login in the menu.
///
///
///
private void loginMenu_Click(object sender, EventArgs e)
{
Login();
}
#endregion
#region logoutMenu_Click()
///
/// The user has clicked on logout in the menu.
///
///
///
private void logoutMenu_Click(object sender, EventArgs e)
{
Logout();
}
#endregion
#region monitorExplorer_BeforeSelect()
///
/// A node is being selected in the monitor explorer.
///
///
///
private void monitorExplorer_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
var pluginNode = monitorExplorer.SelectedNode as PluginServerNode;
if (pluginNode != null)
{
pluginNode.FireUnselected();
}
}
#endregion
#region monitorExplorer_AfterSelect()
///
/// A node has been selected from the monitor explorer.
///
///
///
private void monitorExplorer_AfterSelect(object sender, TreeViewEventArgs e)
{
var pluginNode = e.Node as PluginServerNode;
if (pluginNode != null)
{
pluginNode.FireSelected();
}
}
#endregion
#region monitorExplorer_NodeMouseClick()
///
/// Select the clicked node.
///
///
///
private void monitorExplorer_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
monitorExplorer.SelectedNode = e.Node;
explorerContextMenu.Show(monitorExplorer, e.X, e.Y);
}
}
#endregion
#region explorerContextMenu_Opening()
///
/// The explorer menu is opening.
///
///
///
private void explorerContextMenu_Opening(object sender, CancelEventArgs e)
{
explorerContextMenu.Items.Clear();
var currentNode = monitorExplorer.SelectedNode;
if (currentNode is PluginServerNode)
{
e.Cancel = !(currentNode as PluginServerNode).ContextMenuOpened(explorerContextMenu);
}
else if (currentNode is ProjectTreeNode)
{
var project = (currentNode as ProjectTreeNode).Project;
if (project.Activity.IsSleeping())
{
explorerContextMenu.Items.Add("Force Build", Resources.play_green, forceBuildContextMenu_Click);
}
else
{
explorerContextMenu.Items.Add("Abort Build", Resources.stop_red, abortBuildContextMenu_Click);
}
if (project.Status == ProjectIntegratorState.Running)
{
explorerContextMenu.Items.Add("Stop Project", Resources.cog_stop, stopProjectContextMenu_Click);
}
else
{
explorerContextMenu.Items.Add("Start project", Resources.cog_start, startprojectContextMenu_Click);
}
explorerContextMenu.Items.Add(new ToolStripSeparator());
explorerContextMenu.Items.Add("P&roperties", Resources.magnifier, OnPropertiesClick);
e.Cancel = false;
}
else if (currentNode is ServerTreeNode)
{
explorerContextMenu.Items.Add("P&roperties", Resources.magnifier, OnPropertiesClick);
e.Cancel = false;
}
else if (currentNode is BuildQueueTreeNode)
{
explorerContextMenu.Items.Add("P&roperties", Resources.magnifier, OnPropertiesClick);
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
#endregion
#region monitorTabs_SelectedIndexChanged()
///
/// The select tab has changed.
///
///
///
private void monitorTabs_SelectedIndexChanged(object sender, EventArgs e)
{
if (monitorTabs.SelectedTab is PluginTab)
{
(monitorTabs.SelectedTab as PluginTab).Activate();
}
}
#endregion
#region errorReport_DoubleClick()
///
/// The user has double clicked on the errors list.
///
///
///
private void errorReport_DoubleClick(object sender, EventArgs e)
{
if (allErrors.Count > 0)
{
var lastError = (from record in allErrors
orderby record.Key descending
select record.Value).First();
MessageBox.Show(this, "The last error was " + lastError, "Last Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
#endregion
#region OnPropertiesClick()
///
/// A properties button or menu has been clicked.
///
///
///
private void OnPropertiesClick(object sender, EventArgs e)
{
ShowProperties();
}
#endregion
#region allProjectsView_DoubleClick()
///
/// The all projects grid has been double-clicked.
///
/// The grid that fired the event.
/// The arguments for the event.
private void allProjectsView_DoubleClick(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(this.configuration.Monitor.AllProjectsDoubleClickAction))
{
var projects = allProjectsView.GetSelectedProjects();
this.PerformProjectDoubleClick(projects);
}
}
#endregion
#endregion
#region Private classes
#region MainFormPluginHost
///
/// Expose plugin host functionality for the main form.
///
private class MainFormPluginHost
: PluginHost
{
#region Private fields
private MainForm form;
#endregion
#region Constructors
///
/// Initialise a new .
///
///
public MainFormPluginHost(MainForm form)
{
this.form = form;
}
#endregion
#region Public methods
#region Show()
///
/// Show the host.
///
public override void Show()
{
if (form.Visible)
{
if (form.WindowState == FormWindowState.Minimized) form.WindowState = FormWindowState.Normal;
form.BringToFront();
}
else
{
form.Show();
}
}
#endregion
#region ShutDown()
///
/// Shut down the host.
///
public override void ShutDown()
{
Application.Exit();
}
#endregion
#region AddServerNode()
///
/// Adds a new node for a server.
///
/// The server the node is for.
/// The new node.
public override PluginServerNode AddServerNode(Server server)
{
var serverNode = form.servers[server];
var newNode = new PluginServerNode();
serverNode.Nodes.Add(newNode);
return newNode;
}
#endregion
#region AddTab()
///
/// Adds a new tab page.
///
/// The new tab.
public override PluginTab AddTab(Plugin plugin, string text)
{
var key = string.Format("{0}:{1}", plugin.Configuration.Key, text);
var newTab = new PluginTab();
newTab.Text = text;
form.monitorTabs.TabPages.Add(newTab);
newTab.Removed += (o, e) =>
{
form.monitorTabs.TabPages.Remove(newTab);
form.pluginTabs.Remove(key);
};
form.pluginTabs.Add(key, newTab);
return newTab;
}
#endregion
#region AddImage()
///
/// Adds a new image.
///
/// The image to add.
/// The identifier of the image.
public override string AddImage(Image image)
{
var key = Guid.NewGuid().ToString();
form.applicationImages.Images.Add(key, image);
return key;
}
#endregion
#region ChangeSelectedControl()
///
/// Change the currently selected control.
///
///
public override void ChangeSelectedControl(Control control)
{
form.selectedControl = control;
}
#endregion
#region ShowProjectContextMenu()
///
/// Display the project context menu.
///
///
///
///
public override void ShowProjectContextMenu(Control container, int x, int y)
{
form.projectContextMenu.Show(container, x, y);
}
#endregion
#region AddCommand()
///
/// Adds a new command.
///
/// The text of the command.
/// The icon of the command.
/// The type of the command.
/// The command to run.
/// The new instance.
public override PluginCommand AddCommand(string text, Image icon, PluginCommandType type, EventHandler command)
{
// Add the command to the main menu
var menuCommand = new ToolStripMenuItem(text, icon, command);
switch (type)
{
case PluginCommandType.Project:
form.projectMenu.DropDownItems.Add(menuCommand);
break;
}
// Add the command to the toolbar
var toolButton = new ToolStripButton(text, icon, command);
toolButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
form.mainToolbar.Items.Add(toolButton);
// Add the command to the context menu
var contextCommand = new ToolStripMenuItem(text, icon, command);
form.projectContextMenu.Items.Add(contextCommand);
// Generate the plug-in command
var result = new PluginCommand(text, icon, type, command);
result.Removed += (o, e) =>
{
form.projectMenu.DropDownItems.Remove(menuCommand);
form.mainToolbar.Items.Remove(toolButton);
form.projectContextMenu.Items.Remove(contextCommand);
};
result.PropertyChanged += (o, e) =>
{
switch (e.PropertyName)
{
case "Icon":
menuCommand.Image = result.Icon;
toolButton.Image = result.Icon;
contextCommand.Image = result.Icon;
break;
case "Text":
menuCommand.Text = result.Text;
toolButton.Text = result.Text;
contextCommand.Text = result.Text;
break;
case "Tooltip":
menuCommand.ToolTipText = result.Tooltip;
toolButton.ToolTipText = result.Tooltip;
contextCommand.ToolTipText = result.Tooltip;
break;
}
};
// Return the command
return result;
}
#endregion
#region GetSelectedProjects()
///
/// Gets the currently selected projects.
///
/// The selected projects.
public override IEnumerable GetSelectedProjects()
{
return form.GetSelectedProjects();
}
#endregion
#region PerformDefaultProjectAction()
///
/// Performs the default project action on a project.
///
/// The project to perform the action on.
public override void PerformDefaultProjectAction(Project value)
{
var projects = new List(){
value
};
form.PerformProjectDoubleClick(projects);
}
#endregion
#endregion
}
#endregion
#endregion
}
}