Added Events in progress to the outlook-style status labels of the main window.

- Reordered the labels to reduce flickering for short actions.
- No need to fire action events in a try-catch block.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
Konstantina Chremmou 2020-10-25 13:01:56 +00:00
parent 8842e48b05
commit e5bee7be6a
10 changed files with 148 additions and 177 deletions

View File

@ -48,8 +48,6 @@ namespace XenAdmin.Dialogs
public Session elevatedSession;
public string elevatedPassword;
public string elevatedUsername;
public string originalUsername;
public string originalPassword;
private List<Role> authorizedRoles;
@ -72,8 +70,6 @@ namespace XenAdmin.Dialogs
labelRequiredRoleValue.Text = Role.FriendlyCSVRoleList(authorizedRoles);
labelServerValue.Text = Helpers.GetName(connection);
labelServer.Text = Helpers.IsPool(connection) ? Messages.POOL_COLON : Messages.SERVER_COLON;
originalUsername = session.Connection.Username;
originalPassword = session.Connection.Password;
if (string.IsNullOrEmpty(actionTitle))
{

View File

@ -1890,9 +1890,9 @@ namespace XenAdmin
this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statusProgressBar,
this.statusLabel,
this.statusLabelAlerts,
this.statusLabelErrors,
this.statusLabelUpdates,
this.statusLabelErrors});
this.statusLabelAlerts});
this.StatusStrip.Name = "StatusStrip";
this.StatusStrip.ShowItemToolTips = true;
//

View File

@ -408,84 +408,60 @@ namespace XenAdmin
TabPage.Controls.Add(contents);
}
void History_CollectionChanged(object sender, CollectionChangeEventArgs e)
private void History_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
if (Program.Exiting)
return;
Program.BeginInvoke(Program.MainWindow, () =>
switch (e.Action)
{
ActionBase action = e.Element as ActionBase;
switch (e.Action)
{
case CollectionChangeAction.Add:
case CollectionChangeAction.Add:
if (e.Element is ActionBase action)
{
if (!(action is MeddlingAction))
{
if (action == null)
return;
var meddlingAction = action as MeddlingAction;
if (meddlingAction == null)
Program.Invoke(this, () =>
{
SetStatusBar(null, null);
if (statusBarAction != null)
{
statusBarAction.Changed -= actionChanged;
statusBarAction.Completed -= actionCompleted;
}
statusBarAction = action;
}
action.Changed += actionChanged;
action.Completed += actionCompleted;
actionChanged(action);
break;
});
}
case CollectionChangeAction.Remove:
action.Changed += actionChanged;
action.Completed += actionCompleted;
actionChanged(action);
}
break;
case CollectionChangeAction.Remove:
if (e.Element is ActionBase actionB)
{
actionB.Changed -= actionChanged;
actionB.Completed -= actionCompleted;
}
else if (e.Element is List<ActionBase> range)
{
foreach (var a in range)
{
if (action != null)
{
action.Changed -= actionChanged;
action.Completed -= actionCompleted;
}
else
{
var range = e.Element as List<ActionBase>;
if (range != null)
{
foreach (var a in range)
{
a.Changed -= actionChanged;
a.Completed -= actionCompleted;
}
}
else
{
return;
}
}
int errorCount = ConnectionsManager.History.Count(a => a.IsCompleted && !a.Succeeded);
navigationPane.UpdateNotificationsButton(NotificationsSubMode.Events, errorCount);
statusLabelErrors.Text = errorCount == 1
? Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ONE
: string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_MANY, errorCount);
statusLabelErrors.Visible = errorCount > 0;
if (eventsPage.Visible)
{
TitleLabel.Text = NotificationsSubModeItem.GetText(NotificationsSubMode.Events, errorCount);
TitleIcon.Image = NotificationsSubModeItem.GetImage(NotificationsSubMode.Events, errorCount);
}
break;
a.Changed -= actionChanged;
a.Completed -= actionCompleted;
}
}
});
}
else
return;
UpdateErrorStatusLabel();
break;
}
}
private void actionCompleted(ActionBase action)
{
action.Changed -= actionChanged;
action.Completed -= actionCompleted;
actionChanged(action);
if (action is SrAction)
Program.Invoke(this, UpdateToolbars);
}
@ -495,55 +471,70 @@ namespace XenAdmin
if (Program.Exiting)
return;
Program.Invoke(this, () => actionChanged_(action));
Program.Invoke(this, () =>
{
UpdateStatusProgressBar(action);
UpdateErrorStatusLabel();
});
}
private void actionChanged_(ActionBase action)
private void UpdateStatusProgressBar(ActionBase action)
{
// suppress updates when the PureAsyncAction runs the action to populate the ApiMethodsToRoleCheck
if (action.SuppressProgressReport)
if (statusBarAction != action)
return;
statusProgressBar.Visible = action.ShowProgress && !action.IsCompleted;
var percentage = action.PercentComplete;
Debug.Assert(0 <= percentage && percentage <= 100,
"PercentComplete is out of range, the reporting action needs to be fixed."); //CA-8517
var meddlingAction = action as MeddlingAction;
if (meddlingAction == null)
if (percentage < 0)
percentage = 0;
else if (percentage > 100)
percentage = 100;
statusProgressBar.Value = percentage;
// Don't show cancelled exception
if (action.Exception != null && !(action.Exception is CancelledException))
{
statusProgressBar.Visible = action.ShowProgress && !action.IsCompleted;
if (percentage < 0)
percentage = 0;
else if (percentage > 100)
percentage = 100;
statusProgressBar.Value = percentage;
// Don't show cancelled exception
if (action.Exception != null && !(action.Exception is CancelledException))
{
SetStatusBar(Images.StaticImages._000_error_h32bit_16, action.Exception.Message);
}
else
{
SetStatusBar(null, action.IsCompleted
? null
: !string.IsNullOrEmpty(action.Description)
? action.Description
: !string.IsNullOrEmpty(action.Title)
? action.Title
: null);
}
SetStatusBar(Images.StaticImages._000_error_h32bit_16, action.Exception.Message);
}
else
{
SetStatusBar(null, action.IsCompleted
? null
: !string.IsNullOrEmpty(action.Description)
? action.Description
: !string.IsNullOrEmpty(action.Title)
? action.Title
: null);
}
}
int errorCount = ConnectionsManager.History.Count(a => a.IsCompleted && !a.Succeeded && !(a is CancellingAction && ((CancellingAction)a).Cancelled));
private void UpdateErrorStatusLabel()
{
int errorCount = ConnectionsManager.History.Count(a =>
a.IsCompleted && !a.Succeeded && !(a is CancellingAction ca && ca.Cancelled));
navigationPane.UpdateNotificationsButton(NotificationsSubMode.Events, errorCount);
statusLabelErrors.Text = errorCount == 1
? Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ONE
: string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_MANY, errorCount);
statusLabelErrors.Visible = errorCount > 0;
var errorText = errorCount == 1
? Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERROR
: string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERRORS, errorCount);
int progressCount = ConnectionsManager.History.Count(a => !a.IsCompleted);
var progressText = string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS_IN_PROGRESS, progressCount);
if (errorCount > 0 && progressCount > 0)
statusLabelErrors.Text = string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS,
string.Format(Messages.STRING_COMMA_SPACE_STRING, errorText, progressText));
else if (errorCount > 0)
statusLabelErrors.Text = string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS, errorText);
else if (progressCount > 0)
statusLabelErrors.Text = string.Format(Messages.NOTIFICATIONS_SUBMODE_EVENTS_STATUS, progressText);
statusLabelErrors.Visible = errorCount > 0 || progressCount > 0;
if (eventsPage.Visible)
{

View File

@ -53,7 +53,7 @@ namespace XenAdmin.SettingsPanels
{
get
{
return string.Format(Messages.SIZE_LOCATION_SUB,
return string.Format(Messages.STRING_COMMA_SPACE_STRING,
Util.DiskSizeString(diskSpinner1.CanResize ? diskSpinner1.SelectedSize : vdi.virtual_size, 2),
vdi.Connection.Resolve<SR>(vdi.SR));
}

View File

@ -124,7 +124,7 @@ namespace XenAdmin.Wizards.NewVMWizard
var disk = new VDI
{
name_label = string.Format(Messages.NEWVMWIZARD_STORAGEPAGE_VDINAME, SelectedName, device.userdevice),
name_label = string.Format(Messages.STRING_SPACE_STRING, SelectedName, device.userdevice),
name_description = Messages.NEWVMWIZARD_STORAGEPAGE_DISK_DESCRIPTION,
virtual_size = diskSize,
type = (vdi_type)Enum.Parse(typeof(vdi_type), diskNode.Attributes["type"].Value),

View File

@ -255,8 +255,9 @@ namespace XenAdmin.Actions
_percentComplete = 100;
_isCompleted = true;
}
if (NewAction != null && !suppressHistory)
NewAction(this);
if (!suppressHistory)
NewAction?.Invoke(this);
}
public string Description
@ -309,7 +310,7 @@ namespace XenAdmin.Actions
}
}
public bool SuppressProgressReport { get; set; }
protected bool SuppressProgressReport { get; set; }
public void Tick(int percent, string description)
{
@ -380,31 +381,13 @@ namespace XenAdmin.Actions
protected void OnChanged()
{
if (Changed != null)
try
{
if (!SuppressProgressReport)
Changed(this);
}
catch (Exception e)
{
log.Debug($"Exception firing OnChanged for Action {Title}.", e);
}
if (!SuppressProgressReport)
Changed?.Invoke(this);
}
protected virtual void OnCompleted()
{
if (Completed != null)
{
try
{
Completed(this);
}
catch (Exception ex)
{
log.Debug($"Exception firing OnCompleted for Action {Title}.", ex);
}
}
Completed?.Invoke(this);
}
protected void MarkCompleted(Exception e = null)

View File

@ -75,12 +75,13 @@ namespace XenAdmin.Actions
RbacMethodList rbacMethods = new RbacMethodList();
var session = Session;
Session = new Session(RbacCollectorProxy.GetProxy(rbacMethods), Connection);
base.SuppressProgressReport = true;
var startDescription = Description;
SuppressProgressReport = true;
Run();
base.SuppressProgressReport = false;
Session = session; // reset Session
Description = startDescription; // reset Description;
Description = startDescription; // reset Description
//reset SuppressProgressReport after the Description to avoid firing unnecessarily the Changed event
SuppressProgressReport = false;
return rbacMethods;
}
}

View File

@ -24695,15 +24695,6 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to {0} {1}.
/// </summary>
public static string NAME_WITH_LOCATION {
get {
return ResourceManager.GetString("NAME_WITH_LOCATION", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Select the SR to reattach or create a new SR.
/// </summary>
@ -27363,15 +27354,6 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to {0} {1}.
/// </summary>
public static string NEWVMWIZARD_STORAGEPAGE_VDINAME {
get {
return ResourceManager.GetString("NEWVMWIZARD_STORAGEPAGE_VDINAME", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [XenCenter] has selected a different SR for you..
/// </summary>
@ -28236,20 +28218,38 @@ namespace XenAdmin {
}
/// <summary>
/// Looks up a localized string similar to Events: {0} errors.
/// Looks up a localized string similar to Events: {0}.
/// </summary>
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS_MANY {
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS {
get {
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS_MANY", resourceCulture);
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Events: 1 error.
/// Looks up a localized string similar to 1 error.
/// </summary>
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ONE {
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERROR {
get {
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ONE", resourceCulture);
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERROR", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} errors.
/// </summary>
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERRORS {
get {
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERRORS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} in progress.
/// </summary>
public static string NOTIFICATIONS_SUBMODE_EVENTS_STATUS_IN_PROGRESS {
get {
return ResourceManager.GetString("NOTIFICATIONS_SUBMODE_EVENTS_STATUS_IN_PROGRESS", resourceCulture);
}
}
@ -34017,15 +34017,6 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to {0}, {1}.
/// </summary>
public static string SIZE_LOCATION_SUB {
get {
return ResourceManager.GetString("SIZE_LOCATION_SUB", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Negligible.
/// </summary>
@ -35357,6 +35348,15 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to {0}, {1}.
/// </summary>
public static string STRING_COMMA_SPACE_STRING {
get {
return ResourceManager.GetString("STRING_COMMA_SPACE_STRING", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} {1}.
/// </summary>

View File

@ -8578,9 +8578,6 @@ To ensure system stability, it is strongly recommended that you use multipathing
<data name="NAME_DESCRIPTION_TAGS" xml:space="preserve">
<value>General</value>
</data>
<data name="NAME_WITH_LOCATION" xml:space="preserve">
<value>{0} {1}</value>
</data>
<data name="NETAPP_EQUAL_PAGE_TITLE" xml:space="preserve">
<value>Select the SR to reattach or create a new SR</value>
</data>
@ -9336,9 +9333,6 @@ Review these settings, then click Previous if you need to change anything. Other
<data name="NEWVMWIZARD_STORAGEPAGE_TITLE" xml:space="preserve">
<value>Configure storage for the new VM</value>
</data>
<data name="NEWVMWIZARD_STORAGEPAGE_VDINAME" xml:space="preserve">
<value>{0} {1}</value>
</data>
<data name="NEWVMWIZARD_STORAGEPAGE_XC_SELECTION" xml:space="preserve">
<value>[XenCenter] has selected a different SR for you.</value>
</data>
@ -9662,11 +9656,17 @@ It is strongly recommended that you Cancel and apply the latest version of the p
<data name="NOTIFICATIONS_SUBMODE_EVENTS_READ" xml:space="preserve">
<value>Events</value>
</data>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS_MANY" xml:space="preserve">
<value>Events: {0} errors</value>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS" xml:space="preserve">
<value>Events: {0}</value>
</data>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ONE" xml:space="preserve">
<value>Events: 1 error</value>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS_IN_PROGRESS" xml:space="preserve">
<value>{0} in progress</value>
</data>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERRORS" xml:space="preserve">
<value>{0} errors</value>
</data>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_STATUS_ERROR" xml:space="preserve">
<value>1 error</value>
</data>
<data name="NOTIFICATIONS_SUBMODE_EVENTS_UNREAD_MANY" xml:space="preserve">
<value>Events ({0} errors)</value>
@ -11782,9 +11782,6 @@ The master must be upgraded first, so if you skip the master, the rolling pool u
<data name="SIZE_IS" xml:space="preserve">
<value>size is</value>
</data>
<data name="SIZE_LOCATION_SUB" xml:space="preserve">
<value>{0}, {1}</value>
</data>
<data name="SIZE_NEGLIGIBLE" xml:space="preserve">
<value>Negligible</value>
</data>
@ -12240,6 +12237,9 @@ The upper limit: SR size / {2}</value>
<data name="STRINGIFY_LIST_LASTSEP" xml:space="preserve">
<value> and </value>
</data>
<data name="STRING_COMMA_SPACE_STRING" xml:space="preserve">
<value>{0}, {1}</value>
</data>
<data name="STRING_SPACE_STRING" xml:space="preserve">
<value>{0} {1}</value>
</data>

View File

@ -308,7 +308,7 @@ namespace XenAPI
public virtual string NameWithLocation()
{
return string.Format(Messages.NAME_WITH_LOCATION, Name(), LocationString());
return string.Format(Messages.STRING_SPACE_STRING, Name(), LocationString());
}
internal virtual string LocationString()