diff --git a/XenAdmin/Controls/DataGridViewDropDownSplitButtonCell.cs b/XenAdmin/Controls/DataGridViewDropDownSplitButtonCell.cs index 4d4172e81..7d6828710 100644 --- a/XenAdmin/Controls/DataGridViewDropDownSplitButtonCell.cs +++ b/XenAdmin/Controls/DataGridViewDropDownSplitButtonCell.cs @@ -31,12 +31,14 @@ using System; using System.Drawing; +using System.Drawing.Drawing2D; using System.Windows.Forms; namespace XenAdmin.Controls { public class DataGridViewDropDownSplitButtonCell : DataGridViewTextBoxCell { + private bool active; private bool disposed; private ToolStripItem _defaultItem; @@ -56,7 +58,12 @@ namespace XenAdmin.Controls /// public const int MIN_ROW_HEIGHT = 22; - private bool active; + private static readonly Color BUTTON_BORDER_OUTER = Color.FromArgb(112, 112, 112); + private static readonly Color BUTTON_BORDER_INNER = Color.FromArgb(252, 252, 252); + private static readonly Color BUTTON_FACE_TOP = Color.FromArgb(242, 242, 242); + private static readonly Color BUTTON_FACE_MIDDLE_TOP = Color.FromArgb(235, 235, 235); + private static readonly Color BUTTON_FACE_MIDDLE_BOTTOM = Color.FromArgb(221, 221, 221); + private static readonly Color BUTTON_FACE_BOTTOM = Color.FromArgb(207, 207, 207); public DataGridViewDropDownSplitButtonCell() { @@ -123,28 +130,95 @@ namespace XenAdmin.Controls cellStyle.Alignment = DataGridViewContentAlignment.TopLeft; base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); - + if (active) - using (Pen pen = new Pen(SystemColors.ControlDarkDark, 1)) + { + var mode = graphics.SmoothingMode; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + + var rec = new Rectangle(cellBounds.Left + cellStyle.Padding.Left, + cellBounds.Top + cellStyle.Padding.Top, + cellBounds.Width - cellStyle.Padding.Left - cellStyle.Padding.Right, + CELL_HEIGHT); + + var innerRec = new Rectangle(rec.Location, rec.Size); + innerRec.Inflate(-1, -1); + + using (GraphicsPath path = new GraphicsPath()) { - var rec = new Rectangle(cellBounds.Left + cellStyle.Padding.Left, - cellBounds.Top + cellStyle.Padding.Top, - cellBounds.Width - cellStyle.Padding.Left - cellStyle.Padding.Right, - CELL_HEIGHT); + int diameter = 4; + var arc = new Rectangle(rec.Location, new Size(diameter, diameter)); - graphics.FillRectangle(SystemBrushes.Control, rec); - graphics.DrawRectangle(pen, rec); + //top left corner + path.AddArc(arc, 180, 90); - using (var font = new Font(DataGridView.DefaultCellStyle.Font, FontStyle.Regular)) - graphics.DrawString(value as string, font, SystemBrushes.ControlText, cellBounds); + // top right corner + arc.X = rec.Right - diameter; + path.AddArc(arc, 270, 90); - graphics.DrawLine(pen, - cellBounds.Right - cellStyle.Padding.Right - SPLITTER_FROM_RIGHT, - cellBounds.Top + cellStyle.Padding.Top, - cellBounds.Right - cellStyle.Padding.Right - SPLITTER_FROM_RIGHT, - cellBounds.Top + cellStyle.Padding.Top + CELL_HEIGHT); + // bottom right corner + arc.Y = rec.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // bottom left corner + arc.X = rec.Left; + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + + using (var brush = new LinearGradientBrush(rec, BUTTON_FACE_TOP, BUTTON_FACE_BOTTOM, LinearGradientMode.Vertical)) + { + ColorBlend cb = new ColorBlend(); + cb.Positions = new[] { 0, 1 / 2f, 1 / 2f, 1 }; + cb.Colors = new[] { BUTTON_FACE_TOP, BUTTON_FACE_MIDDLE_TOP, BUTTON_FACE_MIDDLE_BOTTOM, BUTTON_FACE_BOTTOM }; + brush.InterpolationColors = cb; + graphics.FillPath(brush, path); + } + + using (Pen pen = new Pen(BUTTON_BORDER_OUTER, 1)) + graphics.DrawPath(pen, path); } + using (GraphicsPath path = new GraphicsPath()) + { + int diameter = 4; + var arc = new Rectangle(innerRec.Location, new Size(diameter, diameter)); + + //top left corner + path.AddArc(arc, 180, 90); + + // top right corner + arc.X = innerRec.Right - diameter; + path.AddArc(arc, 270, 90); + + // bottom right corner + arc.Y = innerRec.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // bottom left corner + arc.X = innerRec.Left; + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + + using (Pen pen = new Pen(BUTTON_BORDER_INNER, 1)) + graphics.DrawPath(pen, path); + } + + using (var font = new Font(DataGridView.DefaultCellStyle.Font, FontStyle.Regular)) + graphics.DrawString(value as string, font, SystemBrushes.ControlText, cellBounds); + + using (Pen pen = new Pen(BUTTON_BORDER_OUTER, 1)) + graphics.DrawLine(pen, + cellBounds.Right - cellStyle.Padding.Right - SPLITTER_FROM_RIGHT, + cellBounds.Top + cellStyle.Padding.Top + 2, + cellBounds.Right - cellStyle.Padding.Right - SPLITTER_FROM_RIGHT, + cellBounds.Top + cellStyle.Padding.Top + CELL_HEIGHT - 2); + + //reset graphics mode + graphics.SmoothingMode = mode; + } + var img = Properties.Resources.expanded_triangle; graphics.DrawImage(img, cellBounds.Right - cellStyle.Padding.Right - img.Width - (SPLITTER_FROM_RIGHT - img.Width) / 2, diff --git a/XenAdmin/Core/ActionBaseExtensions.cs b/XenAdmin/Core/ActionBaseExtensions.cs index da9bbe0bd..7bc3fd1e6 100644 --- a/XenAdmin/Core/ActionBaseExtensions.cs +++ b/XenAdmin/Core/ActionBaseExtensions.cs @@ -54,26 +54,28 @@ namespace XenAdmin.Core ? Properties.Resources.tempCancel : Properties.Resources._000_error_h32bit_16; - if (action.PercentComplete < 10) + if (action.PercentComplete < 9) return Properties.Resources.usagebar_0; - if (action.PercentComplete < 20) + if (action.PercentComplete < 18) return Properties.Resources.usagebar_1; - if (action.PercentComplete < 30) + if (action.PercentComplete < 27) return Properties.Resources.usagebar_2; - if (action.PercentComplete < 40) + if (action.PercentComplete < 36) return Properties.Resources.usagebar_3; - if (action.PercentComplete < 50) + if (action.PercentComplete < 45) return Properties.Resources.usagebar_4; - if (action.PercentComplete < 60) + if (action.PercentComplete < 54) return Properties.Resources.usagebar_5; - if (action.PercentComplete < 70) + if (action.PercentComplete < 63) return Properties.Resources.usagebar_6; - if (action.PercentComplete < 80) + if (action.PercentComplete < 72) return Properties.Resources.usagebar_7; - if (action.PercentComplete < 90) + if (action.PercentComplete < 81) return Properties.Resources.usagebar_8; + if (action.PercentComplete < 90) + return Properties.Resources.usagebar_9; - return Properties.Resources.usagebar_9; + return Properties.Resources.usagebar_10; } internal static string GetDetails(this ActionBase action) @@ -172,6 +174,18 @@ namespace XenAdmin.Core return hostUuids; } + internal static string GetStatusString(this ActionBase action) + { + if (action.IsCompleted) + return action.Succeeded + ? Messages.ACTION_STATUS_SUCCEEDED + : action.Exception is CancelledException + ? Messages.ACTION_SYSTEM_STATUS_CANCELLED + : Messages.ACTION_STATUS_FAILED; + + return Messages.ACTION_STATUS_IN_PROGRESS; + } + #region Comparison (just static non-extension) methods /// diff --git a/XenAdmin/TabPages/HistoryPage.cs b/XenAdmin/TabPages/HistoryPage.cs index ac2854808..375b4ebc5 100644 --- a/XenAdmin/TabPages/HistoryPage.cs +++ b/XenAdmin/TabPages/HistoryPage.cs @@ -34,6 +34,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; +using System.Text; using System.Windows.Forms; using XenAdmin.Actions; @@ -400,6 +401,8 @@ namespace XenAdmin.TabPages private ToolStripMenuItem cancelItem = new ToolStripMenuItem(Messages.CANCEL); private ToolStripMenuItem dismissItem = new ToolStripMenuItem(Messages.ALERT_DISMISS); private ToolStripMenuItem goToItem = new ToolStripMenuItem(Messages.HISTORYPAGE_GOTO); + private ToolStripSeparator separatorItem = new ToolStripSeparator(); + private ToolStripMenuItem copyItem = new ToolStripMenuItem(Messages.COPY); public event Action DismissalRequested; public event Action GoToXenObjectRequested; @@ -414,6 +417,7 @@ namespace XenAdmin.TabPages cancelItem.Click += ToolStripMenuItemCancel_Click; dismissItem.Click += ToolStripMenuItemDismiss_Click; goToItem.Click += ToolStripMenuItemGoTo_Click; + copyItem.Click += ToolStripMenuItemCopy_Click; MinimumHeight = DataGridViewDropDownSplitButtonCell.MIN_ROW_HEIGHT; Cells.AddRange(expanderCell, statusCell, messageCell, locationCell, dateCell, actionCell); @@ -433,6 +437,11 @@ namespace XenAdmin.TabPages if (obj != null) actionItems.Add(goToItem); + if (actionItems.Count > 0) + actionItems.Add(separatorItem); + + actionItems.Add(copyItem); + actionCell.RefreshItems(actionItems.ToArray()); statusCell.Value = Action.GetImage(); @@ -467,6 +476,23 @@ namespace XenAdmin.TabPages if (GoToXenObjectRequested != null) GoToXenObjectRequested(Action.GetRelevantXenObject()); } + + private void ToolStripMenuItemCopy_Click(object sender, EventArgs e) + { + string text = string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\"", + Action.GetStatusString(), messageCell.Value, + locationCell.Value, dateCell.Value); + + try + { + Clipboard.SetText(text); + } + catch (Exception ex) + { + log.Error("Exception while trying to set clipboard text.", ex); + log.Error(ex, ex); + } + } } private class CustomToolStripRenderer : ToolStripProfessionalRenderer diff --git a/XenModel/Messages.Designer.cs b/XenModel/Messages.Designer.cs index c42700104..84792db51 100644 --- a/XenModel/Messages.Designer.cs +++ b/XenModel/Messages.Designer.cs @@ -1797,6 +1797,42 @@ namespace XenAdmin { } } + /// + /// Looks up a localized string similar to Canceled. + /// + public static string ACTION_STATUS_CANCELLED { + get { + return ResourceManager.GetString("ACTION_STATUS_CANCELLED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed. + /// + public static string ACTION_STATUS_FAILED { + get { + return ResourceManager.GetString("ACTION_STATUS_FAILED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In Progress. + /// + public static string ACTION_STATUS_IN_PROGRESS { + get { + return ResourceManager.GetString("ACTION_STATUS_IN_PROGRESS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Succeeded. + /// + public static string ACTION_STATUS_SUCCEEDED { + get { + return ResourceManager.GetString("ACTION_STATUS_SUCCEEDED", resourceCulture); + } + } + /// /// Looks up a localized string similar to Getting system status canceled. /// diff --git a/XenModel/Messages.resx b/XenModel/Messages.resx index 38a7d41d8..23ebea73d 100644 --- a/XenModel/Messages.resx +++ b/XenModel/Messages.resx @@ -696,6 +696,18 @@ Start VMs and vApps + + Canceled + + + Failed + + + In Progress + + + Succeeded + Getting system status canceled