/* * 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.IO; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml; using System.Xml.Xsl; using ThoughtWorks.CruiseControl.Remote.Monitor; using FastForward.WinCore.Configuration; namespace FastForward.Monitor { /// /// Display the build history for a project. /// public partial class BuildHistoryForm : Form { #region Private fields private Project project; private ApplicationConfig configuration; private ProjectBuild currentBuild; private bool isLoaded; private Dictionary templates = new Dictionary(); #endregion #region Constructors /// /// Initialise a new . /// /// /// /// public BuildHistoryForm(Project project, ApplicationConfig configuration, Form owner) { InitializeComponent(); this.project = project; this.configuration = configuration; Text = "Build History: " + project.Name; LoadTemplates(); RefreshData(); Owner = owner; // Initialise the browser using (var templateStream = this.GetType().Assembly.GetManifestResourceStream("FastForward.Monitor.BuildTemplate.htm")) { using (var reader = new StreamReader(templateStream)) { var template = reader.ReadToEnd(); viewBrowser.DocumentText = template; } } } #endregion #region Private methods #region LoadTemplates() /// /// Load the available templates. /// private void LoadTemplates() { activeView.Items.Add(new BuildTemplateConfig { Name = "System", FileName = "FastForward.Monitor.BuildSystemTemplate.xsl", IsResource = true }); activeView.Items.AddRange(configuration.BuildTemplates.ToArray()); activeView.SelectedIndex = 0; activeView.SelectedIndexChanged += (o, e) => RefreshView(); } #endregion #region RefreshData() /// /// Refresh the list of builds. /// private void RefreshData() { buildsList.Items.Clear(); var orderedBuilds = (from record in project.Builds orderby record.BuildDate descending select record); foreach (var build in orderedBuilds) { var status = build.IsSuccessful ? "Success" : "Failure"; var item = new ListViewItem(new string[] { build.BuildDate.ToString(), build.Label ?? string.Empty, status }, status); item.Tag = build; buildsList.Items.Add(item); } if (orderedBuilds.Count() > 0) { currentBuild = orderedBuilds.First(); } RefreshView(); } #endregion #region RefreshView() /// /// Refreshes the current view. /// private void RefreshView() { if (isLoaded) viewBrowser.Document.Body.InnerHtml = GenerateView(); } #endregion #region GenerateView() /// /// Generates the view to display. /// /// private string GenerateView() { var currentTemplate = activeView.SelectedItem as BuildTemplateConfig; if (!templates.ContainsKey(currentTemplate.Name)) { // Load the XSL-T template var newXslt = new XslCompiledTransform(); if (currentTemplate.IsResource) { using (var templateStream = this.GetType().Assembly.GetManifestResourceStream(currentTemplate.FileName)) { using (var reader = XmlReader.Create(templateStream)) { newXslt.Load(reader); } } } else { newXslt.Load(currentTemplate.FileName); } templates.Add(currentTemplate.Name, newXslt); } // Generate the output var output = new StringBuilder(); try { using (var input = new StringReader(currentBuild.Log)) { using (var reader = XmlReader.Create(input)) { using (var writer = XmlWriter.Create(output)) { templates[currentTemplate.Name].Transform(reader, writer); } } } } catch (Exception error) { output.AppendFormat("Unable to read log: {0}", error.Message); } // Return the transformed view return output.ToString(); } #endregion #endregion #region Event handlers #region refreshButton_Click() /// /// The refresh button was clicked. /// /// /// private void refreshButton_Click(object sender, EventArgs e) { RefreshData(); } #endregion #region buildsList_ItemSelectionChanged() /// /// Handle an item being selected. /// /// /// private void buildsList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { if (buildsList.SelectedItems.Count == 1) { currentBuild = buildsList.SelectedItems[0].Tag as ProjectBuild; RefreshView(); } } #endregion #region viewBrowser_DocumentCompleted() /// /// The template has loaded, now we can load the actual data. /// /// /// private void viewBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { isLoaded = true; viewBrowser.Document.Body.InnerHtml = GenerateView(); } #endregion #region saveButton_Click() /// /// Allow the user to save the current report. /// /// /// private void saveButton_Click(object sender, EventArgs e) { viewBrowser.ShowSaveAsDialog(); } #endregion #region printButton_Click() /// /// Allow the user to print the current report. /// /// /// private void printButton_Click(object sender, EventArgs e) { viewBrowser.ShowPrintDialog(); } #endregion #endregion } }