/*
* 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.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using FastForward.WinCore;
using ThoughtWorks.CruiseControl.Remote.Monitor;
using FastForward.WinCore.Configuration;
using System.Speech.Synthesis;
using ThoughtWorks.CruiseControl.Remote;
using System.Windows.Forms;
namespace FastForward.WpfPlugins
{
///
/// A plug-in that will speak any notifications.
///
[DisplayName("Speech Notifications")]
[Description("Speak notifications of project changes.")]
public class SpeechPlugin
: StatusChangePlugin, IDisposable
{
#region Private fields
private SpeechSynthesizer speechSynthesizer;
private List activeProjects = new List();
#endregion
#region Constructors
///
/// Initialise a new .
///
///
public SpeechPlugin(PluginConfig configuration)
: base(configuration)
{
LoadSwitches();
}
#endregion
#region Public properties
#region SpeakOnSuccess
///
/// Speak a notification if a build is successful.
///
public bool SpeakOnSuccess = true;
#endregion
#region SpeakOnFailure
///
/// Speak a notificaton if a build has failed.
///
public bool SpeakOnFailure = true;
#endregion
#region SpeakOnBuildStart
///
/// Speak a notificaton if a build has started.
///
public bool SpeakOnBuildStart = true;
#endregion
#region Voice
///
/// The voice to use.
///
public string Voice { get; set; }
#endregion
#endregion
#region Public methods
#region Dispose()
///
/// Clean up.
///
public override void Dispose()
{
base.Dispose();
if (speechSynthesizer != null)
{
// Clean up the synthesizer
speechSynthesizer.Dispose();
speechSynthesizer = null;
}
}
#endregion
#endregion
#region Protected methods
#region OnInitialise()
///
/// Initialise the actual implementation of this plugin.
///
protected override void OnInitialise()
{
// Initialise the sythesizer
speechSynthesizer = new SpeechSynthesizer();
if (!string.IsNullOrEmpty(Voice))
{
speechSynthesizer.SelectVoice(Voice);
}
base.OnInitialise();
}
#endregion
#region OnConfigure()
///
/// Configure the plugin.
///
///
protected override PluginConfig OnConfigure()
{
PluginConfig newConfig = null;
var form = new SpeechSettingsForm(this);
if (form.ShowDialog() == DialogResult.OK)
{
// Generate the new configuration and set the data
newConfig = Configuration.Clone();
newConfig.Data = (SpeakOnSuccess ? "1" : "0") +
(SpeakOnFailure ? "1" : "0") +
(SpeakOnBuildStart ? "1" : "0") +
":" + Voice;
}
return newConfig;
}
#endregion
#region OnConfigurationUpdated()
///
/// Update any changed configuration settings.
///
protected override void OnConfigurationUpdated()
{
LoadSwitches();
}
#endregion
#region OnStatusChange()
///
/// The status of a project has changed.
///
///
///
///
protected override void OnStatusChange(Project project, IntegrationStatus oldStatus, ProjectActivity oldActivity)
{
if (project.Activity.IsBuilding())
{
if (SpeakOnBuildStart)
{
speechSynthesizer.SpeakAsync(string.Format("{0} has started building", project.Name));
}
if (!activeProjects.Contains(project)) activeProjects.Add(project);
}
else if (project.Activity.IsSleeping())
{
if (oldActivity.IsBuilding() || (project.BuildStatus != oldStatus))
{
string message = string.Empty;
// Determine the message to display
switch (project.BuildStatus)
{
case IntegrationStatus.Cancelled:
message = string.Format("The build for {0} was cancelled", project.Name);
break;
case IntegrationStatus.Exception:
message = string.Format("There was an exception during the build for {0}", project.Name);
break;
case IntegrationStatus.Failure:
if (oldStatus == IntegrationStatus.Failure)
{
message = string.Format("The build for {0} is still broken", project.Name);
}
else
{
message = string.Format("The build for {0} has been broken", project.Name);
}
break;
case IntegrationStatus.Success:
if (oldStatus == IntegrationStatus.Failure)
{
message = string.Format("The build for {0} has been fixed", project.Name);
}
else
{
message = string.Format("The build for {0} was successful", project.Name);
}
break;
default:
message = string.Format("An unknown status was received from the build for {0}", project.Name);
break;
}
if ((SpeakOnSuccess && (project.BuildStatus == IntegrationStatus.Success)) ||
(SpeakOnFailure && (project.BuildStatus != IntegrationStatus.Success)))
{
speechSynthesizer.SpeakAsync(message);
}
activeProjects.Remove(project);
}
}
}
#endregion
#endregion
#region Private methods
#region LoadSwitches()
///
/// Load the configuration switches.
///
///
private void LoadSwitches()
{
var parts = (Configuration.Data ?? string.Empty).Split(':');
var switches = parts[0] + new string('1', 3 - parts[0].Length);
SpeakOnSuccess = (switches[0] == '1');
SpeakOnFailure = (switches[1] == '1');
SpeakOnBuildStart = (switches[2] == '1');
if (parts.Length > 1)
{
Voice = parts[1];
}
}
#endregion
#endregion
}
}