2013-06-24 13:41:48 +02:00
/ * Copyright ( c ) Citrix Systems Inc .
* All rights reserved .
*
* Redistribution and use in source and binary forms ,
* with or without modification , are permitted provided
* that the following conditions are met :
*
* * Redistributions of source code must retain the above
* copyright notice , this list of conditions and the
* following disclaimer .
* * Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the
* following disclaimer in the documentation and / or other
* materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ,
* INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
* /
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Drawing ;
using System.Linq ;
using System.Text ;
using System.Windows.Forms ;
2013-07-18 14:56:40 +02:00
using XenAdmin.Controls ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Core ;
using XenAdmin.Network ;
using XenAPI ;
using XenAdmin.Alerts ;
using XenAdmin.Help ;
using System.Threading ;
using XenAdmin.Actions ;
using System.IO ;
namespace XenAdmin.Dialogs
{
public partial class AlertSummaryDialog : XenDialogBase
{
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
private static readonly int ALERT_CAP = 1000 ;
2013-07-03 14:00:24 +02:00
private readonly CollectionChangeEventHandler m_alertCollectionChangedWithInvoke ;
Dictionary < string , bool > expandedState = new Dictionary < string , bool > ( ) ;
private bool inAlertBuild ;
private bool retryAlertBuild ;
2013-06-24 13:41:48 +02:00
public AlertSummaryDialog ( )
{
InitializeComponent ( ) ;
GridViewAlerts . Sort ( ColumnDate , ListSortDirection . Descending ) ;
LabelCappingEntries . Text = String . Format ( Messages . ALERT_CAP_LABEL , ALERT_CAP ) ;
GridViewAlerts . ScrollBars = ScrollBars . Vertical ;
UpdateActionEnablement ( ) ;
2013-07-03 14:00:24 +02:00
m_alertCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( AlertsCollectionChanged ) ;
Alert . XenCenterAlerts . CollectionChanged + = m_alertCollectionChangedWithInvoke ;
2013-07-11 19:20:18 +02:00
toolStripSplitButtonDismiss . DefaultItem = tsmiDismissAll ;
toolStripSplitButtonDismiss . Text = tsmiDismissAll . Text ;
2013-06-24 13:41:48 +02:00
}
2013-07-15 07:41:54 +02:00
private void AlertSummaryDialog_Load ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-08-13 11:15:52 +02:00
toolStripDropDownButtonServerFilter . InitializeHostList ( ) ;
toolStripDropDownButtonServerFilter . BuildFilterList ( ) ;
2013-06-24 13:41:48 +02:00
Rebuild ( ) ;
}
2013-07-03 12:10:21 +02:00
private void SetFilterLabel ( )
{
2013-08-14 17:59:25 +02:00
toolStripLabelFiltersOnOff . Text = FilterIsOn
2013-07-03 12:10:21 +02:00
? Messages . FILTERS_ON
: Messages . FILTERS_OFF ;
}
2013-06-24 13:41:48 +02:00
2013-08-14 17:59:25 +02:00
private bool FilterIsOn
{
get
{
return toolStripDropDownButtonDateFilter . FilterIsOn
| | toolStripDropDownButtonServerFilter . FilterIsOn
| | toolStripDropDownSeveritiesFilter . FilterIsOn ;
}
}
2013-06-24 13:41:48 +02:00
#region AlertListCode
private void Rebuild ( )
{
log . Debug ( "Rebuilding alertList" ) ;
Thread t = new Thread ( _Rebuild ) ;
t . Name = "Building alert list" ;
t . IsBackground = true ;
t . Start ( ) ;
}
private void _Rebuild ( )
{
log . Debug ( "Rebuilding alertList: Starting background thread" ) ;
Program . AssertOffEventThread ( ) ;
lock ( GridViewAlerts )
{
if ( inAlertBuild )
{
// queue up a rebuild after the current one has completed
log . Debug ( "Rebuilding alertList: In build already, exiting" ) ;
retryAlertBuild = true ;
return ;
}
inAlertBuild = true ;
log . Debug ( "Rebuilding alertList: taking inAlertBuild lock" ) ;
}
try
{
// 1) Add all the alerts that have not been filtered out to an array
// 2) Create rows for each of these
// 3) Sort them
// 4) Take the top n as set by the filters
// 5) Add them to the control using the optimized AddRange()
2013-07-03 12:10:21 +02:00
Program . Invoke ( this , SetFilterLabel ) ;
2013-06-24 13:41:48 +02:00
List < Alert > alerts = Alert . NonDismissingAlerts ;
2013-07-12 12:07:10 +02:00
alerts . RemoveAll ( FilterAlert ) ;
2013-06-24 13:41:48 +02:00
log . DebugFormat ( "Rebuilding alertList: there are {0} alerts in total. After filtering we have {1}" ,
Alert . AlertCount ,
alerts . Count ) ;
if ( GridViewAlerts . SortedColumn ! = null )
{
2013-07-12 12:07:10 +02:00
if ( GridViewAlerts . SortedColumn . Index = = ColumnMessage . Index )
2013-06-24 13:41:48 +02:00
{
2013-07-03 13:00:00 +02:00
alerts . Sort ( Alert . CompareOnTitle ) ;
2013-06-24 13:41:48 +02:00
}
else if ( GridViewAlerts . SortedColumn . Index = = ColumnDate . Index )
{
2013-07-03 13:00:00 +02:00
alerts . Sort ( Alert . CompareOnDate ) ;
2013-06-24 13:41:48 +02:00
}
2013-07-12 12:07:10 +02:00
else if ( GridViewAlerts . SortedColumn . Index = = ColumnLocation . Index )
2013-06-24 13:41:48 +02:00
{
2013-07-03 13:00:00 +02:00
alerts . Sort ( Alert . CompareOnAppliesTo ) ;
2013-06-24 13:41:48 +02:00
}
2013-07-12 12:07:10 +02:00
else if ( GridViewAlerts . SortedColumn . Index = = ColumnSeverity . Index )
2013-06-24 13:41:48 +02:00
{
2013-07-03 13:00:00 +02:00
alerts . Sort ( Alert . CompareOnPriority ) ;
2013-06-24 13:41:48 +02:00
}
if ( GridViewAlerts . SortOrder = = SortOrder . Descending )
{
alerts . Reverse ( ) ;
}
}
int alertsFound = alerts . Count ;
if ( ALERT_CAP < alerts . Count )
{
log . DebugFormat ( "Rebuilding alertList: hit alert cap, hiding {0} alerts" , alerts . Count - ALERT_CAP ) ;
alerts . RemoveRange ( ALERT_CAP , alerts . Count - ALERT_CAP ) ;
}
Program . Invoke ( this , delegate
{
List < DataGridViewRow > gridRows = new List < DataGridViewRow > ( ) ;
log . Debug ( "Rebuilding alertList: Adding alert rows" ) ;
foreach ( Alert alert in alerts )
gridRows . Add ( NewAlertRow ( alert ) ) ;
log . DebugFormat ( "Rebuilding alertList: Added {0} rows" , gridRows . Count ) ;
List < string > selection = ( GridViewAlerts . SelectedRows . Cast < DataGridViewRow > ( ) . Select (
selectedRow = > ( ( Alert ) selectedRow . Tag ) . uuid ) ) . ToList ( ) ;
GridViewAlerts . Rows . Clear ( ) ;
log . Debug ( "Rebuilding alertList: Cleared rows" ) ;
GridViewAlerts . Rows . AddRange ( gridRows . ToArray ( ) ) ;
log . DebugFormat ( "Rebuilding alertList: Added {0} rows to the grid" , GridViewAlerts . Rows . Count ) ;
LabelCappingEntries . Visible = ( alertsFound > ALERT_CAP ) ;
//restore selection
if ( selection . Count > 0 )
{
log . Debug ( "Rebuilding alertList: Restoring alert selection" ) ;
foreach ( DataGridViewRow alertRow in GridViewAlerts . Rows )
{
alertRow . Selected = selection . Contains ( ( ( Alert ) alertRow . Tag ) . uuid ) ;
}
if ( GridViewAlerts . SelectedRows . Count = = 0 & & GridViewAlerts . Rows . Count > 0 )
{
GridViewAlerts . Rows [ 0 ] . Selected = true ;
}
log . DebugFormat ( "Rebuilding alertList: Selected {0} alerts" , selection . Count ) ;
}
UpdateActionEnablement ( ) ;
} ) ;
}
catch ( Exception e )
{
log . ErrorFormat ( "Encountered exception when building list: {0}" , e ) ;
}
finally
{
log . Debug ( "Rebuilding alertList: Waiting for lock to clear inAlertBuild" ) ;
lock ( GridViewAlerts )
{
inAlertBuild = false ;
log . Debug ( "Rebuilding alertList: cleared inAlertBuild" ) ;
if ( retryAlertBuild )
{
// we received a request to build while we were building, rebuild in case we missed something
retryAlertBuild = false ;
log . Debug ( "Rebuilding alertList: we received a request to build while we were building, rebuild in case we missed something" ) ;
_Rebuild ( ) ;
}
}
}
}
private DataGridViewRow NewAlertRow ( Alert alert )
{
2013-07-18 14:56:40 +02:00
var expanderCell = new DataGridViewImageCell ( ) ;
var imageCell = new DataGridViewImageCell ( ) ;
var appliesCell = new DataGridViewTextBoxCell ( ) ;
var detailCell = new DataGridViewTextBoxCell ( ) ;
var dateCell = new DataGridViewTextBoxCell ( ) ;
var actionItems = GetAlertActionItems ( alert ) ;
var actionCell = new DataGridViewDropDownSplitButtonCell ( actionItems . ToArray ( ) ) ;
var newRow = new DataGridViewRow { Tag = alert , MinimumHeight = DataGridViewDropDownSplitButtonCell . MIN_ROW_HEIGHT } ;
2013-06-24 13:41:48 +02:00
// Get the relevant image for the row depending on the type of the alert
Image typeImage = alert is MessageAlert & & ( ( MessageAlert ) alert ) . Message . ShowOnGraphs
? Images . GetImage16For ( ( ( MessageAlert ) alert ) . Message . Type )
: Images . GetImage16For ( alert . Priority ) ;
imageCell . Value = typeImage ;
// Set the detail cell content and expanding arrow
if ( expandedState . ContainsKey ( alert . uuid ) )
{
// show the expanded arrow and the body detail
expanderCell . Value = Properties . Resources . expanded_triangle ;
detailCell . Value = String . Format ( "{0}\n\n{1}" , alert . Title , alert . Description ) ;
}
else
{
// show the expand arrow and just the title
expanderCell . Value = Properties . Resources . contracted_triangle ;
detailCell . Value = alert . Title ;
}
appliesCell . Value = alert . AppliesTo ;
dateCell . Value = HelpersGUI . DateTimeToString ( alert . Timestamp . ToLocalTime ( ) , Messages . DATEFORMAT_DMY_HM , true ) ;
2013-07-18 14:56:40 +02:00
newRow . Cells . AddRange ( expanderCell , imageCell , detailCell , appliesCell , dateCell , actionCell ) ;
2013-06-24 13:41:48 +02:00
return newRow ;
}
/// <summary>
/// Runs all the current filters on the alert to determine if it should be shown in the list or not.
/// </summary>
/// <param name="alert"></param>
2013-07-12 12:07:10 +02:00
private bool FilterAlert ( Alert alert )
2013-06-24 13:41:48 +02:00
{
2013-07-02 20:06:11 +02:00
bool hide = false ;
Program . Invoke ( this , ( ) = >
hide = toolStripDropDownButtonDateFilter . HideByDate ( alert . Timestamp . ToLocalTime ( ) )
2013-07-03 14:00:24 +02:00
| | toolStripDropDownButtonServerFilter . HideByLocation ( alert . HostUuid )
| | toolStripDropDownSeveritiesFilter . HideBySeverity ( alert . Priority ) ) ;
return hide ;
2013-06-24 13:41:48 +02:00
}
private void RemoveAlertRow ( Alert a )
{
for ( int i = 0 ; i < GridViewAlerts . Rows . Count ; i + + )
{
if ( ( ( Alert ) GridViewAlerts . Rows [ i ] . Tag ) . uuid = = a . uuid )
GridViewAlerts . Rows . RemoveAt ( i ) ;
}
if ( GridViewAlerts . Rows . Count < ALERT_CAP )
LabelCappingEntries . Visible = false ;
}
2013-07-15 07:41:54 +02:00
private void GridViewAlerts_CellClick ( object sender , DataGridViewCellEventArgs e )
2013-06-24 13:41:48 +02:00
{
// If you click on the headers you can get -1 as the index.
if ( e . ColumnIndex < 0 | | e . RowIndex < 0 | | e . ColumnIndex ! = ColumnExpand . Index )
return ;
2013-07-18 14:56:40 +02:00
ToggleExpandedState ( e . RowIndex ) ;
2013-06-24 13:41:48 +02:00
}
2013-07-15 07:41:54 +02:00
private void GridViewAlerts_CellDoubleClick ( object sender , DataGridViewCellEventArgs e )
2013-06-24 13:41:48 +02:00
{
// If you click on the headers you can get -1 as the index.
if ( e . ColumnIndex < 0 | | e . RowIndex < 0 )
return ;
2013-07-18 14:56:40 +02:00
if ( e . ColumnIndex ! = ColumnActions . Index )
ToggleExpandedState ( e . RowIndex ) ;
2013-06-24 13:41:48 +02:00
}
2013-07-15 07:41:54 +02:00
private void GridViewAlerts_KeyDown ( object sender , KeyEventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-07-15 07:41:54 +02:00
if ( e . KeyCode = = Keys . Right ) // expand all selected rows
2013-06-24 13:41:48 +02:00
{
2013-07-15 07:41:54 +02:00
foreach ( DataGridViewBand row in GridViewAlerts . SelectedRows )
{
Alert alert = ( Alert ) GridViewAlerts . Rows [ row . Index ] . Tag ;
if ( ! expandedState . ContainsKey ( alert . uuid ) )
{
2013-07-18 14:56:40 +02:00
ToggleExpandedState ( row . Index ) ;
2013-07-15 07:41:54 +02:00
}
}
2013-06-24 13:41:48 +02:00
}
2013-07-15 07:41:54 +02:00
else if ( e . KeyCode = = Keys . Left ) // collapse all selected rows
2013-06-24 13:41:48 +02:00
{
2013-07-15 07:41:54 +02:00
foreach ( DataGridViewBand row in GridViewAlerts . SelectedRows )
{
Alert alert = ( Alert ) GridViewAlerts . Rows [ row . Index ] . Tag ;
if ( expandedState . ContainsKey ( alert . uuid ) )
{
2013-07-18 14:56:40 +02:00
ToggleExpandedState ( row . Index ) ;
2013-07-15 07:41:54 +02:00
}
}
}
else if ( e . KeyCode = = Keys . Enter ) // toggle expanded state for all selected rows
{
foreach ( DataGridViewBand row in GridViewAlerts . SelectedRows )
{
2013-07-18 14:56:40 +02:00
ToggleExpandedState ( row . Index ) ;
2013-07-15 07:41:54 +02:00
}
2013-06-24 13:41:48 +02:00
}
}
2013-07-15 07:41:54 +02:00
private void GridViewAlerts_ColumnHeaderMouseClick ( object sender , DataGridViewCellMouseEventArgs e )
{
if ( GridViewAlerts . Columns [ e . ColumnIndex ] . SortMode = = DataGridViewColumnSortMode . Automatic )
{
Rebuild ( ) ;
}
}
private void GridViewAlerts_SelectionChanged ( object sender , EventArgs e )
{
// stop the buttons getting enabled/disabled during refresh, the rebuild will set them once it's finished
if ( inAlertBuild )
return ;
UpdateActionEnablement ( ) ;
}
2013-06-24 13:41:48 +02:00
/// <summary>
/// Handles the automatic sorting of the AlertsGridView for the non-string columns
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2013-07-15 07:41:54 +02:00
private void GridViewAlerts_SortCompare ( object sender , DataGridViewSortCompareEventArgs e )
2013-06-24 13:41:48 +02:00
{
Alert alert1 = ( Alert ) GridViewAlerts . Rows [ e . RowIndex1 ] . Tag ;
Alert alert2 = ( Alert ) GridViewAlerts . Rows [ e . RowIndex2 ] . Tag ;
if ( e . Column . Index = = ColumnDate . Index )
{
int SortResult = DateTime . Compare ( alert1 . Timestamp , alert2 . Timestamp ) ;
e . SortResult = ( GridViewAlerts . SortOrder = = SortOrder . Descending ) ? SortResult * = - 1 : SortResult ;
e . Handled = true ;
}
2013-07-12 12:07:10 +02:00
else if ( e . Column . Index = = ColumnSeverity . Index )
2013-06-24 13:41:48 +02:00
{
2013-07-03 13:00:00 +02:00
e . SortResult = Alert . CompareOnPriority ( alert1 , alert2 ) ;
2013-06-24 13:41:48 +02:00
e . Handled = true ;
}
}
2013-07-18 14:56:40 +02:00
private void ToggleExpandedState ( int rowIndex )
2013-07-15 07:41:54 +02:00
{
2013-07-18 14:56:40 +02:00
var row = GridViewAlerts . Rows [ rowIndex ] ;
Alert alert = row . Tag as Alert ;
if ( alert = = null )
return ;
2013-07-15 07:41:54 +02:00
if ( expandedState . ContainsKey ( alert . uuid ) )
{
expandedState . Remove ( alert . uuid ) ;
2013-07-18 14:56:40 +02:00
row . Cells [ ColumnExpand . Index ] . Value = Properties . Resources . contracted_triangle ;
row . Cells [ ColumnMessage . Index ] . Value = alert . Title ;
2013-07-15 07:41:54 +02:00
}
else
{
expandedState . Add ( alert . uuid , true ) ;
2013-07-18 14:56:40 +02:00
row . Cells [ ColumnExpand . Index ] . Value = Properties . Resources . expanded_triangle ;
row . Cells [ ColumnMessage . Index ] . Value = string . Format ( "{0}\n\n{1}" , alert . Title , alert . Description ) ;
2013-07-15 07:41:54 +02:00
}
}
2013-06-24 13:41:48 +02:00
#endregion
2013-07-18 14:56:40 +02:00
private void ToolStripMenuItemHelp_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
// We should only be here if one item is selected, we dont do multi-help
if ( GridViewAlerts . SelectedRows . Count ! = 1 )
log . ErrorFormat ( "Can only launch help for 1 alert at a time (Attempted to launch {0}). Launching for the first one in the list)" , GridViewAlerts . SelectedRows . Count ) ;
Alert alert = ( Alert ) GridViewAlerts . SelectedRows [ 0 ] . Tag ;
if ( alert . HelpID = = null )
{
log . ErrorFormat ( "Attempted to launch help for alert {0} ({1}) but no helpID available. Not launching." , alert . Title , alert . uuid ) ;
return ;
}
HelpManager . Launch ( alert . HelpID ) ;
}
2013-07-18 14:56:40 +02:00
private void ToolStripMenuItemFix_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
// We should only be here if one item is selected, we dont do multi-fix
if ( GridViewAlerts . SelectedRows . Count = = 0 )
{
log . ErrorFormat ( "Attempted to fix alert with no alert selected." ) ;
return ;
}
if ( GridViewAlerts . SelectedRows . Count ! = 1 )
log . ErrorFormat ( "Only 1 alert can be fixed at a time (Attempted to fix {0}). Fixing the first one in the list." , GridViewAlerts . SelectedRows . Count ) ;
Alert alert = ( Alert ) GridViewAlerts . SelectedRows [ 0 ] . Tag ;
if ( alert . FixLinkAction = = null )
{
log . ErrorFormat ( "Attempted to fix alert {0} ({1}) but no fix link action available. Not fixing." , alert . Title , alert . uuid ) ;
return ;
}
alert . FixLinkAction . Invoke ( ) ;
}
2013-07-18 14:56:40 +02:00
private void ToolStripMenuItemDismiss_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
if ( new ThreeButtonDialog (
new ThreeButtonDialog . Details ( null , Messages . ALERT_DISMISS_CONFIRM , Messages . XENCENTER ) ,
ThreeButtonDialog . ButtonYes ,
ThreeButtonDialog . ButtonNo ) . ShowDialog ( this ) ! = DialogResult . Yes )
return ;
Alert [ ] selectedAlerts = new Alert [ GridViewAlerts . SelectedRows . Count ] ;
for ( int i = 0 ; i < selectedAlerts . Length ; i + + )
selectedAlerts [ i ] = ( Alert ) GridViewAlerts . SelectedRows [ i ] . Tag ;
DismissAlerts ( selectedAlerts ) ;
}
2013-07-11 19:20:18 +02:00
private void tsmiDismissAll_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
DialogResult result ;
2013-08-14 17:59:25 +02:00
if ( ! FilterIsOn )
{
using ( var dlog = new ThreeButtonDialog (
2013-06-24 13:41:48 +02:00
new ThreeButtonDialog . Details ( null , Messages . ALERT_DISMISS_ALL_NO_FILTER_CONTINUE ) ,
new ThreeButtonDialog . TBDButton ( Messages . DISMISS_ALL_YES_CONFIRM_BUTTON , DialogResult . Yes ) ,
2013-08-14 17:59:25 +02:00
ThreeButtonDialog . ButtonCancel ) )
{
result = dlog . ShowDialog ( this ) ;
}
}
2013-06-24 13:41:48 +02:00
else
2013-08-14 17:59:25 +02:00
{
using ( var dlog = new ThreeButtonDialog (
2013-06-24 13:41:48 +02:00
new ThreeButtonDialog . Details ( null , Messages . ALERT_DISMISS_ALL_CONTINUE ) ,
new ThreeButtonDialog . TBDButton ( Messages . DISMISS_ALL_CONFIRM_BUTTON , DialogResult . Yes ) ,
new ThreeButtonDialog . TBDButton ( Messages . DISMISS_FILTERED_CONFIRM_BUTTON , DialogResult . No , ThreeButtonDialog . ButtonType . NONE ) ,
2013-08-14 17:59:25 +02:00
ThreeButtonDialog . ButtonCancel ) )
{
result = dlog . ShowDialog ( this ) ;
}
}
2013-06-24 13:41:48 +02:00
if ( result = = DialogResult . Cancel )
return ;
List < Alert > dismissingAlerts = new List < Alert > ( ) ;
if ( result = = DialogResult . No )
{
//Dismiss Filtered
for ( int i = 0 ; i < GridViewAlerts . Rows . Count ; i + + )
dismissingAlerts . Add ( ( Alert ) GridViewAlerts . Rows [ i ] . Tag ) ;
}
else
{
//Dismiss All
dismissingAlerts . AddRange ( Alert . Alerts ) ;
}
2013-07-11 19:20:18 +02:00
dismissingAlerts . RemoveAll ( a = > ! AllowedToDismiss ( a . Connection ) ) ;
2013-06-24 13:41:48 +02:00
DismissAlerts ( dismissingAlerts . ToArray ( ) ) ;
}
private void DismissAlerts ( Alert [ ] alerts )
{
List < Alert > local_alerts = new List < Alert > ( ) ;
// we group the alerts by connection ready for dismissal
Dictionary < IXenConnection , List < Alert > > alertGroups = new Dictionary < IXenConnection , List < Alert > > ( ) ;
foreach ( Alert a in alerts )
{
if ( a . Dismissing )
continue ;
IXenConnection c = a . Connection ;
if ( c = = null )
{
local_alerts . Add ( a ) ;
}
else
{
if ( ! alertGroups . ContainsKey ( c ) )
alertGroups [ c ] = new List < Alert > ( ) ;
List < Alert > l = alertGroups [ c ] ;
l . Add ( a ) ;
}
a . Dismissing = true ;
}
// When we refresh now the alerts we are dismissing will be removed from the GridViewAlerts control as their dismissing flag
// is set. This also updates the numbers in the filter list correctly.
2013-07-02 20:06:11 +02:00
toolStripDropDownButtonServerFilter . RefreshLists ( ) ;
2013-06-24 13:41:48 +02:00
foreach ( IXenConnection c in alertGroups . Keys )
{
_DismissAlerts ( c , alertGroups [ c ] ) ;
}
if ( local_alerts . Count > 0 )
_DismissAlerts ( null , local_alerts ) ;
}
2013-07-03 14:00:24 +02:00
/// <param name="connection">
/// May be null, in which case this is expected to be for client-side alerts.
/// </param>
2013-06-24 13:41:48 +02:00
private static void _DismissAlerts ( IXenConnection connection , List < Alert > alerts )
{
new DeleteAllAlertsAction ( connection , alerts ) . RunAsync ( ) ;
}
2013-07-03 14:00:24 +02:00
private void AlertsCollectionChanged ( object sender , CollectionChangeEventArgs e )
2013-06-24 13:41:48 +02:00
{
Program . AssertOnEventThread ( ) ;
if ( e . Element = = null )
{
// We take the null element to mean there has been a batch remove
Rebuild ( ) ;
return ;
}
Alert a = e . Element as Alert ;
switch ( e . Action )
{
case CollectionChangeAction . Add :
Rebuild ( ) ; // rebuild entire alert list to ensure filtering and sorting
break ;
case CollectionChangeAction . Remove :
RemoveAlertRow ( a ) ;
break ;
}
}
private void closeButton_Click ( object sender , EventArgs e )
{
this . Close ( ) ;
}
protected override void OnFormClosing ( FormClosingEventArgs e )
{
2013-07-03 14:00:24 +02:00
Alert . XenCenterAlerts . CollectionChanged - = m_alertCollectionChangedWithInvoke ;
2013-06-24 13:41:48 +02:00
base . OnFormClosing ( e ) ;
}
private void UpdateActionEnablement ( )
{
toolStripButtonExportAll . Enabled = GridViewAlerts . Rows . Count > 0 ;
2013-07-11 19:20:18 +02:00
// We use the nondismissing alert count here because we dont wan't to
// offer people the chance to dismiss alerts which are already being
// dismissed... they aren't even shown in the datagridview
tsmiDismissAll . Enabled = AllowedToDismissAtLeastOne ( ) ;
tsmiDismissAll . AutoToolTip = ! tsmiDismissAll . Enabled ;
tsmiDismissAll . ToolTipText = tsmiDismissAll . Enabled
? string . Empty
: Alert . NonDismissingAlertCount > 0
? Messages . DELETE_ANY_MESSAGE_RBAC_BLOCKED
: Messages . NO_MESSAGES_TO_DISMISS ;
tsmiDismissSelected . Enabled = AllowedToDismissSelected ( ) ;
tsmiDismissSelected . AutoToolTip = ! tsmiDismissSelected . Enabled ;
tsmiDismissSelected . ToolTipText = tsmiDismissSelected . Enabled
? string . Empty
: Messages . DELETE_MESSAGE_RBAC_BLOCKED ;
2013-08-14 17:59:25 +02:00
toolStripSplitButtonDismiss . Enabled = tsmiDismissAll . Enabled & & tsmiDismissSelected . Enabled ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Check that there exists a non dismissing alert that can be dismissed.
/// </summary>
/// <returns></returns>
private bool AllowedToDismissAtLeastOne ( )
{
Dictionary < IXenConnection , bool > connectionsChecked = new Dictionary < IXenConnection , bool > ( ) ;
foreach ( Alert a in Alert . Alerts )
{
if ( a . Connection ! = null & & connectionsChecked . ContainsKey ( a . Connection ) )
continue ;
if ( a . Dismissing )
continue ;
if ( AllowedToDismiss ( a . Connection ) )
return true ;
// we can't dismiss from this connection, so don't bother checking in future
connectionsChecked . Add ( a . Connection , true ) ;
}
return false ;
}
/// <summary>
/// Checks that each alert which is currently selected comes from a connection where the user has sufficient RBAC
/// privileges to clear the alert.
/// </summary>
/// <returns></returns>
private bool AllowedToDismissSelected ( )
{
List < IXenConnection > selectedAlertConnections = new List < IXenConnection > ( ) ;
foreach ( DataGridViewRow r in GridViewAlerts . SelectedRows )
{
2013-08-14 17:59:25 +02:00
Alert alert = r . Tag as Alert ;
if ( alert ! = null & & alert . Connection ! = null & &
! selectedAlertConnections . Contains ( alert . Connection ) )
2013-06-24 13:41:48 +02:00
{
selectedAlertConnections . Add ( alert . Connection ) ;
}
}
2013-08-14 17:59:25 +02:00
if ( selectedAlertConnections . Count = = 0 )
return false ;
2013-06-24 13:41:48 +02:00
foreach ( IXenConnection c in selectedAlertConnections )
{
if ( ! AllowedToDismiss ( c ) )
return false ;
}
return true ;
}
private bool AllowedToDismiss ( IXenConnection c )
{
// check if local alert
if ( c = = null )
return true ;
// have we disconnected? Alert will dissapear soon, but for now block dismissal.
if ( c . Session = = null )
return false ;
if ( c . Session . IsLocalSuperuser | | ! Helpers . MidnightRideOrGreater ( c ) )
return true ;
List < Role > rolesAbleToCompleteAction = Role . ValidRoleList ( "Message.destroy" , c ) ;
foreach ( Role possibleRole in rolesAbleToCompleteAction )
{
if ( c . Session . Roles . Contains ( possibleRole ) )
{
return true ;
}
}
return false ;
}
2013-07-18 14:56:40 +02:00
private List < ToolStripItem > GetAlertActionItems ( Alert alert )
2013-06-24 13:41:48 +02:00
{
2013-07-18 14:56:40 +02:00
var items = new List < ToolStripItem > ( ) ;
2013-06-24 13:41:48 +02:00
2013-07-18 14:56:40 +02:00
if ( AllowedToDismissSelected ( ) )
{
var dismiss = new ToolStripMenuItem ( Messages . ALERT_DISMISS ) ;
dismiss . Click + = ToolStripMenuItemDismiss_Click ;
items . Add ( dismiss ) ;
}
2013-06-24 13:41:48 +02:00
2013-07-18 14:56:40 +02:00
if ( ! string . IsNullOrEmpty ( alert . FixLinkText ) & & alert . FixLinkAction ! = null )
2013-06-24 13:41:48 +02:00
{
2013-07-18 14:56:40 +02:00
var fix = new ToolStripMenuItem ( alert . FixLinkText ) ;
fix . Click + = ToolStripMenuItemFix_Click ;
items . Add ( fix ) ;
}
2013-07-15 07:41:54 +02:00
2013-07-18 14:56:40 +02:00
if ( ! string . IsNullOrEmpty ( alert . HelpID ) )
{
var help = new ToolStripMenuItem ( alert . HelpLinkText ) ;
help . Click + = ToolStripMenuItemHelp_Click ;
items . Add ( help ) ;
}
2013-07-15 07:41:54 +02:00
2013-07-18 14:56:40 +02:00
if ( items . Count > 0 )
items . Add ( new ToolStripSeparator ( ) ) ;
2013-07-15 07:41:54 +02:00
2013-07-18 14:56:40 +02:00
var copy = new ToolStripMenuItem ( Messages . COPY ) ;
copy . Click + = copyToolStripMenuItem_Click ;
items . Add ( copy ) ;
2013-06-24 13:41:48 +02:00
2013-07-18 14:56:40 +02:00
return items ;
2013-06-24 13:41:48 +02:00
}
2013-07-11 19:20:18 +02:00
#region Top ToolStrip event handlers
2013-07-02 18:36:02 +02:00
private void toolStripDropDownButtonDateFilter_FilterChanged ( )
2013-06-24 13:41:48 +02:00
{
Rebuild ( ) ;
}
2013-07-02 20:06:11 +02:00
private void toolStripDropDownButtonServerFilter_FilterChanged ( )
{
Rebuild ( ) ;
}
2013-07-15 07:41:54 +02:00
private void toolStripDropDownSeveritiesFilter_FilterChanged ( )
{
Rebuild ( ) ;
}
2013-06-24 13:41:48 +02:00
2013-07-15 07:41:54 +02:00
private void toolStripButtonRefresh_Click ( object sender , EventArgs e )
{
Rebuild ( ) ;
}
2013-07-11 19:20:18 +02:00
2013-06-24 13:41:48 +02:00
private void toolStripButtonExportAll_Click ( object sender , EventArgs e )
{
2013-08-14 18:12:39 +02:00
bool exportAll = true ;
if ( FilterIsOn )
{
using ( var dlog = new ThreeButtonDialog (
new ThreeButtonDialog . Details ( null , Messages . ALERT_EXPORT_ALL_OR_FILTERED ) ,
new ThreeButtonDialog . TBDButton ( Messages . ALERT_EXPORT_ALL_BUTTON , DialogResult . Yes ) ,
new ThreeButtonDialog . TBDButton ( Messages . ALERT_EXPORT_FILTERED_BUTTON , DialogResult . No , ThreeButtonDialog . ButtonType . NONE ) ,
ThreeButtonDialog . ButtonCancel ) )
{
var result = dlog . ShowDialog ( this ) ;
if ( result = = DialogResult . No )
exportAll = false ;
else if ( result = = DialogResult . Cancel )
return ;
}
}
string fileName ;
using ( SaveFileDialog dialog = new SaveFileDialog
{
AddExtension = true ,
Filter = string . Format ( "{0} (*.csv)|*.csv|{1} (*.*)|*.*" ,
Messages . CSV_DESCRIPTION , Messages . ALL_FILES ) ,
FilterIndex = 0 ,
Title = Messages . EXPORT_ALL ,
RestoreDirectory = true ,
DefaultExt = "csv" ,
CheckPathExists = false ,
OverwritePrompt = true
} )
{
if ( dialog . ShowDialog ( this ) ! = DialogResult . OK )
return ;
fileName = dialog . FileName ;
}
2013-06-24 13:41:48 +02:00
new DelegatedAsyncAction ( null ,
2013-08-14 18:12:39 +02:00
string . Format ( Messages . EXPORT_SYSTEM_ALERTS , fileName ) ,
string . Format ( Messages . EXPORTING_SYSTEM_ALERTS , fileName ) ,
string . Format ( Messages . EXPORTED_SYSTEM_ALERTS , fileName ) ,
2013-07-18 14:56:40 +02:00
delegate
2013-06-24 13:41:48 +02:00
{
2013-08-14 18:12:39 +02:00
using ( StreamWriter stream = new StreamWriter ( fileName , false , UTF8Encoding . UTF8 ) )
2013-06-24 13:41:48 +02:00
{
2013-07-12 12:07:10 +02:00
stream . WriteLine ( "{0},{1},{2},{3},{4}" , Messages . TITLE ,
2013-08-14 18:12:39 +02:00
Messages . SEVERITY , Messages . DESCRIPTION ,
Messages . APPLIES_TO , Messages . TIMESTAMP ) ;
if ( exportAll )
2013-06-24 13:41:48 +02:00
{
2013-08-14 18:12:39 +02:00
foreach ( Alert a in Alert . Alerts )
stream . WriteLine ( GetAlertDetailsCSVQuotes ( a ) ) ;
}
else
{
foreach ( DataGridViewRow row in GridViewAlerts . Rows )
{
var a = row . Tag as Alert ;
if ( a ! = null )
stream . WriteLine ( GetAlertDetailsCSVQuotes ( a ) ) ;
}
2013-06-24 13:41:48 +02:00
}
}
} ) . RunAsync ( ) ;
}
2013-07-11 19:20:18 +02:00
private void toolStripSplitButtonDismiss_DropDownItemClicked ( object sender , ToolStripItemClickedEventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-07-11 19:20:18 +02:00
toolStripSplitButtonDismiss . DefaultItem = e . ClickedItem ;
toolStripSplitButtonDismiss . Text = toolStripSplitButtonDismiss . DefaultItem . Text ;
2013-06-24 13:41:48 +02:00
}
private void copyToolStripMenuItem_Click ( object sender , EventArgs e )
{
2013-07-12 12:07:10 +02:00
// We should only be here if one item is selected, we don't do multi-fix
2013-06-24 13:41:48 +02:00
if ( GridViewAlerts . SelectedRows . Count = = 0 )
{
log . ErrorFormat ( "Attempted to copy alert with no alert selected." ) ;
return ;
}
StringBuilder sb = new StringBuilder ( ) ;
foreach ( DataGridViewRow r in GridViewAlerts . SelectedRows )
{
2013-07-12 12:07:10 +02:00
Alert alert = ( Alert ) r . Tag ;
2013-06-24 13:41:48 +02:00
sb . AppendLine ( GetAlertDetailsCSVQuotes ( alert ) ) ;
}
2013-07-12 12:07:10 +02:00
2013-06-24 13:41:48 +02:00
try
{
Clipboard . SetText ( sb . ToString ( ) ) ;
}
catch ( Exception ex )
{
log . Error ( "Exception while trying to set clipboard text." , ex ) ;
log . Error ( ex , ex ) ;
}
}
private string GetAlertDetailsCSVQuotes ( Alert a )
{
string date = String . Empty ;
string description = String . Empty ;
Program . Invoke ( Program . MainWindow , delegate
{
date = HelpersGUI . DateTimeToString (
a . Timestamp . ToLocalTime ( ) ,
Messages . DATEFORMAT_DMY_HM , true ) ;
description = a . Description ;
} ) ;
return String . Format ( "\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\"" ,
EscapeQuotes ( a . Title ) ,
EscapeQuotes ( a . Priority . GetString ( ) ) ,
EscapeQuotes ( description ) ,
EscapeQuotes ( a . AppliesTo ) ,
EscapeQuotes ( date ) ) ;
}
2013-07-11 19:20:18 +02:00
private string EscapeQuotes ( string s )
2013-06-24 13:41:48 +02:00
{
2013-07-11 19:20:18 +02:00
return s = = null ? null : s . Replace ( "\"" , "\"\"" ) ;
2013-06-24 13:41:48 +02:00
}
2013-07-18 14:56:40 +02:00
#endregion
2013-06-24 13:41:48 +02:00
}
}