Source

TrafficLight / src / UI / TrafficLightApplicationContext.cs

Full commit
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using RossCode.TrafficLight.Core;
using RossCode.TrafficLight.Core.Domain;
using RossCode.TrafficLight.Core.Eventing;
using RossCode.TrafficLight.Core.Eventing.Events;
using RossCode.TrafficLight.Core.Presenters;
using RossCode.TrafficLight.Core.Presenters.Views;
using RossCode.TrafficLight.Core.Services;
using RossCode.TrafficLight.Core.Services.Indicators;
using RossCode.TrafficLight.UI.Properties;

namespace RossCode.TrafficLight.UI
{
    public class TrafficLightApplicationContext : ApplicationContext
    {
        private readonly IProjectMonitorService projectMonitorService;
        private readonly IBuildIndicatorService buildIndicatorService;

        private System.ComponentModel.IContainer components;
		private NotifyIcon trafficLightNotifyIcon;
		private ContextMenu trafficLightNotifyIconContextMenu;
		private MenuItem exitContextMenuItem;
		private MenuItem showProjectsContextMenuItem;
		private MenuItem showBuildStatusMenuItem;
		private MenuItem showSettingsMenuItem;

        private readonly IDictionary<BuildStatus, Action> setBuildIcon;
        private readonly IDictionary<BuildStatus, Action> showToolTip;
        private BuildStatus currentBuildStatus;

        public TrafficLightApplicationContext(IProjectMonitorService projectMonitorService, IBuildIndicatorService buildIndicatorService) 
		{
			InitializeContext();
            this.projectMonitorService = projectMonitorService;
            this.buildIndicatorService = buildIndicatorService;

            buildIndicatorService.StartIndicators();

            setBuildIcon = new Dictionary<BuildStatus, Action>
                {
                    { BuildStatus.Unknown, () => trafficLightNotifyIcon.Icon = Resources.DefaultTrafficLightIcon },
                    { BuildStatus.Building, () => trafficLightNotifyIcon.Icon = Resources.YellowTrafficLightIcon },
                    { BuildStatus.Failing, () => trafficLightNotifyIcon.Icon = Resources.RedTrafficLightIcon },
                    { BuildStatus.Success, () => trafficLightNotifyIcon.Icon = Resources.GreenTrafficLightIcon }
                };

            showToolTip = new Dictionary<BuildStatus, Action>
                {
                    { BuildStatus.Unknown, () => { } },
                    { BuildStatus.Building, ShowBuildingTooltip },
                    { BuildStatus.Failing, ShowFailureTooltip },
                    { BuildStatus.Success, ShowSuccessTooltip }
                };

            DomainEvents.Register<BuildStatusChanged>(ChangeBuildStatus);
            DomainEvents.Register<EditProjectRequested>(EditProject);

            this.projectMonitorService.StartMonitoring();
		}

        private void EditProject(EditProjectRequested args)
        {
            ActivateForm<EditProjectPresenter, IEditProjectView>(p => p.SetProject(args.Project));
        }

        private void InitializeContext() 
		{
			components = new System.ComponentModel.Container();
			
			InitializeNotifyIcon();
		    InitializeNotifyIconContextMenu();
		}

        private void InitializeNotifyIconContextMenu()
        {
            showProjectsContextMenuItem = new MenuItem();
            showBuildStatusMenuItem = new MenuItem();
            exitContextMenuItem = new MenuItem();
            showSettingsMenuItem = new MenuItem();

            trafficLightNotifyIconContextMenu.MenuItems.AddRange(new[] { showBuildStatusMenuItem, showProjectsContextMenuItem, showSettingsMenuItem, exitContextMenuItem });

            var menuIndex = 0;
            showBuildStatusMenuItem.Index = menuIndex;
            showBuildStatusMenuItem.Text = "Show &Status";
            showBuildStatusMenuItem.DefaultItem = true;
            showBuildStatusMenuItem.Click += (sender, e) => ShowBuildStatusView();
            menuIndex++;

            showProjectsContextMenuItem.Index = menuIndex;
            showProjectsContextMenuItem.Text = "Show &Projects";
            showProjectsContextMenuItem.Click += (sender, e) => ActivateForm<ProjectsPresenter, IProjectsView>();
            menuIndex++;

            showSettingsMenuItem.Index = menuIndex;
            showSettingsMenuItem.Text = "Show Se&ttings";
            showSettingsMenuItem.Click += (sender, args) => ActivateForm<SettingsPresenter, ISettingsView>();
            menuIndex++;

            exitContextMenuItem.Index = menuIndex;
            exitContextMenuItem.Text = "&Exit";
            exitContextMenuItem.Click += (sender, e) => ExitThread();
        }

        private void ShowBuildStatusView()
        {
            ActivateForm<BuildStatusPresenter, IBuildStatusView>();
        }

        private void InitializeNotifyIcon()
        {
            trafficLightNotifyIcon = new NotifyIcon(components);
            trafficLightNotifyIconContextMenu = new ContextMenu();
			
            trafficLightNotifyIcon.ContextMenu = trafficLightNotifyIconContextMenu;
            trafficLightNotifyIcon.DoubleClick += (sender, e) => ShowBuildStatusView();
            trafficLightNotifyIcon.Icon = Resources.DefaultTrafficLightIcon;
            trafficLightNotifyIcon.Text = "Traffic Light";
            trafficLightNotifyIcon.Visible = true;
        }

        protected override void Dispose( bool disposing )
		{
			if(disposing)
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}		
		}

        private void ActivateForm<TPresenter, TView>(Action<TPresenter> setDataOn = null) where TPresenter : PresenterBase<TView> where TView : IView
        {
            var presenter = IoC.Resolve<TPresenter>();
            var view = presenter.View;
            if (setDataOn != null) setDataOn(presenter);
            view.Show();
            presenter.UpdateBuildStatus(currentBuildStatus);
            view.Closed += (sender, e) =>
                {
                    DisposeView(view);
                    view = default(TView);
                    presenter = default(TPresenter);
                };
        }

        protected override void ExitThreadCore()
        {
            buildIndicatorService.ShutDownIndicators();
            base.ExitThreadCore();
        }

        private void DisposeView(IDisposable view)
        {
            if (view != null)
            {
                view.Dispose();
            } 
        }

        private void ChangeBuildStatus(BuildStatusChanged arg)
        {
            currentBuildStatus = arg.Status;
            setBuildIcon[arg.Status]();
            showToolTip[arg.Status]();
        }

        private void ShowSuccessTooltip()
        {
            trafficLightNotifyIcon.ShowBalloonTip(5000, "Success!", "All builds are successful", ToolTipIcon.None);
        }

        private void ShowBuildingTooltip()
        {
            trafficLightNotifyIcon.ShowBalloonTip(5000, "Building", "A project is currently building", ToolTipIcon.Info);
        }

        private void ShowFailureTooltip()
        {
            trafficLightNotifyIcon.ShowBalloonTip(5000, "Failure!", "The build is broken!", ToolTipIcon.Error);
        }
    }
}