2017-01-16 20:59:50 +01:00
/ * Copyright ( c ) Citrix Systems , Inc .
2013-06-24 13:41:48 +02:00
* 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.Diagnostics ;
using System.Drawing ;
using System.IO ;
using System.Linq ;
2013-12-05 13:46:39 +01:00
using System.Text ;
2013-06-24 13:41:48 +02:00
using System.Windows.Forms ;
2013-12-05 13:46:39 +01:00
using XenAdmin.Actions ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Alerts ;
2013-12-05 13:46:39 +01:00
using XenAdmin.Controls ;
2017-08-08 13:25:18 +02:00
using XenAdmin.Controls.DataGridViewEx ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Core ;
2013-08-30 16:19:59 +02:00
using XenAdmin.Dialogs ;
2017-08-08 13:25:18 +02:00
using XenAdmin.Network ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Wizards.PatchingWizard ;
2017-11-17 02:04:45 +01:00
using XenCenterLib ;
2017-08-08 13:25:18 +02:00
using XenAPI ;
2013-06-24 13:41:48 +02:00
using Timer = System . Windows . Forms . Timer ;
2013-12-05 13:46:39 +01:00
2013-06-24 13:41:48 +02:00
2013-08-30 16:19:59 +02:00
namespace XenAdmin.TabPages
2013-06-24 13:41:48 +02:00
{
2018-08-10 10:38:55 +02:00
public partial class ManageUpdatesPage : NotificationsBasePage
2013-06-24 13:41:48 +02:00
{
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2013-12-05 13:46:39 +01:00
private int currentSpinningFrame ;
2013-06-24 13:41:48 +02:00
private Timer spinningTimer = new Timer ( ) ;
private ImageList imageList = new ImageList ( ) ;
2018-12-11 14:04:58 +01:00
private Dictionary < string , bool > expandedState = new Dictionary < string , bool > ( ) ;
2013-12-05 13:46:39 +01:00
private List < string > selectedUpdates = new List < string > ( ) ;
2017-08-29 15:36:29 +02:00
private List < string > collapsedPoolRowsList = new List < string > ( ) ;
2013-12-05 13:46:39 +01:00
private int checksQueue ;
2016-08-08 15:37:47 +02:00
private bool CheckForUpdatesInProgress ;
2017-06-07 02:16:32 +02:00
private readonly CollectionChangeEventHandler m_updateCollectionChangedWithInvoke ;
2013-06-24 13:41:48 +02:00
2013-08-30 16:19:59 +02:00
public ManageUpdatesPage ( )
2013-06-24 13:41:48 +02:00
{
InitializeComponent ( ) ;
InitializeProgressControls ( ) ;
2013-11-23 15:04:15 +01:00
tableLayoutPanel1 . Visible = false ;
2013-12-05 13:46:39 +01:00
UpdateButtonEnablement ( ) ;
2017-06-07 02:16:32 +02:00
m_updateCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( UpdatesCollectionChanged ) ;
2016-11-17 16:35:27 +01:00
toolStripSplitButtonDismiss . DefaultItem = dismissAllToolStripMenuItem ;
toolStripSplitButtonDismiss . Text = dismissAllToolStripMenuItem . Text ;
2018-12-11 14:04:58 +01:00
try
{
//ensure we won't try to rebuild the list while setting the initial view
checksQueue + + ;
byHostToolStripMenuItem . Checked = Properties . Settings . Default . ShowUpdatesByServer ;
byUpdateToolStripMenuItem . Checked = ! Properties . Settings . Default . ShowUpdatesByServer ;
}
finally
{
checksQueue - - ;
}
2013-08-30 16:19:59 +02:00
}
2018-08-10 10:38:55 +02:00
#region NotificationPage overrides
protected override void RefreshPage ( )
2013-08-30 16:19:59 +02:00
{
2013-12-05 13:46:39 +01:00
toolStripDropDownButtonServerFilter . InitializeHostList ( ) ;
toolStripDropDownButtonServerFilter . BuildFilterList ( ) ;
2018-08-10 10:38:55 +02:00
Rebuild ( ) ;
}
protected override void RegisterEventHandlers ( )
{
Updates . RegisterCollectionChanged ( m_updateCollectionChangedWithInvoke ) ;
Updates . RestoreDismissedUpdatesStarted + = Updates_RestoreDismissedUpdatesStarted ;
Updates . CheckForUpdatesStarted + = CheckForUpdates_CheckForUpdatesStarted ;
Updates . CheckForUpdatesCompleted + = CheckForUpdates_CheckForUpdatesCompleted ;
}
protected override void DeregisterEventHandlers ( )
{
Updates . DeregisterCollectionChanged ( m_updateCollectionChangedWithInvoke ) ;
Updates . RestoreDismissedUpdatesStarted - = Updates_RestoreDismissedUpdatesStarted ;
Updates . CheckForUpdatesStarted - = CheckForUpdates_CheckForUpdatesStarted ;
Updates . CheckForUpdatesCompleted - = CheckForUpdates_CheckForUpdatesCompleted ;
2013-06-24 13:41:48 +02:00
}
2018-08-10 10:38:55 +02:00
#endregion
2013-06-24 13:41:48 +02:00
2017-06-07 02:16:32 +02:00
private void UpdatesCollectionChanged ( object sender , CollectionChangeEventArgs e )
2013-06-24 13:41:48 +02:00
{
2017-06-07 02:16:32 +02:00
Program . AssertOnEventThread ( ) ;
2017-07-14 19:08:54 +02:00
2017-06-07 02:16:32 +02:00
switch ( e . Action )
{
case CollectionChangeAction . Add :
Rebuild ( ) ; // rebuild entire alert list to ensure filtering and sorting
break ;
case CollectionChangeAction . Remove :
2017-07-14 19:08:54 +02:00
Alert a = e . Element as Alert ;
if ( a ! = null )
{
RemoveUpdateRow ( a ) ;
}
else
{
var range = e . Element as List < Alert > ;
if ( range ! = null )
Rebuild ( ) ;
}
2017-06-07 02:16:32 +02:00
break ;
}
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void CheckForUpdates_CheckForUpdatesStarted ( )
2013-06-24 13:41:48 +02:00
{
2016-08-08 15:37:47 +02:00
Program . Invoke ( Program . MainWindow , StartCheckForUpdates ) ;
}
2013-12-05 13:46:39 +01:00
2016-08-08 15:37:47 +02:00
private void Updates_RestoreDismissedUpdatesStarted ( )
{
Program . Invoke ( Program . MainWindow , StartCheckForUpdates ) ;
}
2015-07-31 15:43:14 +02:00
2016-08-08 15:37:47 +02:00
private void StartCheckForUpdates ( )
{
if ( CheckForUpdatesInProgress )
return ;
2015-07-31 15:43:14 +02:00
2016-08-08 15:37:47 +02:00
CheckForUpdatesInProgress = true ;
checksQueue + + ;
if ( checksQueue > 1 )
return ;
toolStripButtonRefresh . Enabled = false ;
toolStripButtonRestoreDismissed . Enabled = false ;
2017-08-29 15:36:29 +02:00
StoreStateOfRows ( ) ;
2016-08-08 15:37:47 +02:00
dataGridViewUpdates . Rows . Clear ( ) ;
dataGridViewUpdates . Refresh ( ) ;
2017-08-08 13:25:18 +02:00
dataGridViewHosts . Rows . Clear ( ) ;
dataGridViewHosts . Refresh ( ) ;
2016-08-08 15:37:47 +02:00
2017-06-11 11:49:25 +02:00
checkForUpdatesNowLink . Enabled = false ;
checkForUpdatesNowButton . Visible = false ;
2016-08-08 15:37:47 +02:00
spinningTimer . Start ( ) ;
labelProgress . Text = Messages . AVAILABLE_UPDATES_SEARCHING ;
2017-06-11 11:49:25 +02:00
tableLayoutPanel3 . Visible = true ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void CheckForUpdates_CheckForUpdatesCompleted ( bool succeeded , string errorMessage )
2013-06-24 13:41:48 +02:00
{
CA-147941: Fixed the RPU wizard hang in "Reconnecting Storage" and connecting action stuck in progress state
In some cases calling Control.Invoke() from a background thread causes that thread to go in a "sleep, wait, or join" mode, while waiting for Invoke to happen, although the UI thread is running normally.
If the Control is the MainWindow, it works as expected, but we've seen it happening while connecting or disconnecting from a large pool, on calling Invoke on controls like NavigationView, AlertSummaryPage, HistoryPage, etc.
To fix this, we call the Invoke on the MainWindow in all the places where we've seen the issue.
With this changes, the previous fix for CA-148245 (call RequestRefreshTreeView on CacheClearing event) is not needed anymore, so I removed that call.
Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
2014-10-10 14:16:50 +02:00
Program . Invoke ( Program . MainWindow , delegate
2013-12-05 13:46:39 +01:00
{
checksQueue - - ;
toolStripButtonRefresh . Enabled = true ;
2015-07-30 15:58:23 +02:00
toolStripButtonRestoreDismissed . Enabled = true ;
2017-06-11 11:49:25 +02:00
checkForUpdatesNowLink . Enabled = true ;
checkForUpdatesNowButton . Visible = true ;
2013-12-05 13:46:39 +01:00
spinningTimer . Stop ( ) ;
2013-11-21 09:30:24 +01:00
2013-12-05 13:46:39 +01:00
if ( succeeded )
{
Rebuild ( ) ;
}
else
{
pictureBoxProgress . Image = SystemIcons . Error . ToBitmap ( ) ;
labelProgress . Text = string . IsNullOrEmpty ( errorMessage )
? Messages . AVAILABLE_UPDATES_NOT_FOUND
: errorMessage ;
}
2016-08-08 15:37:47 +02:00
CheckForUpdatesInProgress = false ;
2013-12-05 13:46:39 +01:00
} ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void InitializeProgressControls ( )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
imageList . ColorDepth = ColorDepth . Depth32Bit ;
imageList . ImageSize = new Size ( 32 , 32 ) ;
imageList . Images . AddRange ( new Image [ ]
{
Properties . Resources . SpinningFrame0 ,
Properties . Resources . SpinningFrame1 ,
Properties . Resources . SpinningFrame2 ,
Properties . Resources . SpinningFrame3 ,
Properties . Resources . SpinningFrame4 ,
Properties . Resources . SpinningFrame5 ,
Properties . Resources . SpinningFrame6 ,
Properties . Resources . SpinningFrame7
} ) ;
spinningTimer . Tick + = timer_Tick ;
spinningTimer . Interval = 150 ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void timer_Tick ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
int imageIndex = + + currentSpinningFrame < = 7 ? currentSpinningFrame : currentSpinningFrame = 0 ;
pictureBoxProgress . Image = imageList . Images [ imageIndex ] ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void SetFilterLabel ( )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
toolStripLabelFiltersOnOff . Text = FilterIsOn
? Messages . FILTERS_ON
: Messages . FILTERS_OFF ;
}
private bool FilterIsOn
{
get
{
return toolStripDropDownButtonDateFilter . FilterIsOn | |
toolStripDropDownButtonServerFilter . FilterIsOn ;
}
2013-06-24 13:41:48 +02:00
}
private void Rebuild ( )
2017-08-08 13:25:18 +02:00
{
2018-12-11 13:52:59 +01:00
Program . AssertOnEventThread ( ) ;
if ( ! Visible | | checksQueue > 0 )
return ;
SetFilterLabel ( ) ;
ToggleTopWarningVisibility ( ) ;
if ( byUpdateToolStripMenuItem . Checked )
2017-08-08 13:25:18 +02:00
RebuildUpdateView ( ) ;
2018-12-11 13:52:59 +01:00
else
2017-08-08 13:25:18 +02:00
RebuildHostView ( ) ;
}
2017-08-10 14:46:59 +02:00
private class UpdatePageByHostDataGridView : CollapsingPoolHostDataGridView
{
2017-08-22 13:41:00 +02:00
protected override void OnCellPainting ( DataGridViewCellPaintingEventArgs e )
{
base . OnCellPainting ( e ) ;
2017-09-28 18:35:51 +02:00
if ( e . RowIndex > = 0 )
2017-08-22 13:41:00 +02:00
{
UpdatePageDataGridViewRow row = ( UpdatePageDataGridViewRow ) Rows [ e . RowIndex ] ;
2017-10-03 16:32:57 +02:00
if ( ! row . IsFullyPopulated & & e . ColumnIndex = = row . PatchingStatusCellIndex
| | ( row . Tag is Host & & ( e . ColumnIndex = = row . ExpansionCellIndex
| | ( row . HasPool & & ( e . ColumnIndex = = row . IconCellIndex | | e . ColumnIndex = = row . PatchingStatusCellIndex ) ) ) ) )
2017-08-22 13:41:00 +02:00
{
e . PaintBackground ( e . ClipBounds , true ) ;
e . Handled = true ;
}
}
}
2017-08-16 12:46:00 +02:00
protected override void SortColumns ( )
2017-08-10 14:46:59 +02:00
{
UpdatePageDataGridViewRow firstRow = Rows [ 0 ] as UpdatePageDataGridViewRow ;
if ( firstRow = = null )
return ;
2017-08-16 12:46:00 +02:00
if ( columnToBeSortedIndex = = firstRow . NameCellIndex | |
columnToBeSortedIndex = = firstRow . VersionCellIndex | |
2017-08-10 14:46:59 +02:00
columnToBeSortedIndex = = firstRow . StatusCellIndex )
2017-08-16 12:46:00 +02:00
SortAndRebuildTree ( new CollapsingPoolHostRowSorter < UpdatePageDataGridViewRow > ( direction , columnToBeSortedIndex ) ) ;
2017-08-10 14:46:59 +02:00
}
}
2017-08-08 13:25:18 +02:00
private class UpdatePageDataGridViewRow : CollapsingPoolHostDataGridViewRow
{
2018-12-10 18:15:23 +01:00
private readonly DataGridViewImageCell _poolIconCell = new DataGridViewImageCell ( ) ;
private readonly DataGridViewTextBoxCell _versionCell = new DataGridViewTextBoxCell ( ) ;
private readonly DataGridViewImageCell _patchingStatusCell = new DataGridViewImageCell ( ) ;
private readonly DataGridViewTextBoxCell _statusCell = new DataGridViewTextBoxCell ( ) ;
private readonly DataGridViewTextBoxCell _requiredUpdateCell = new DataGridViewTextBoxCell ( ) ;
private readonly DataGridViewTextBoxCell _installedUpdateCell = new DataGridViewTextBoxCell ( ) ;
2017-08-08 13:25:18 +02:00
2017-09-28 18:35:51 +02:00
public UpdatePageDataGridViewRow ( Pool pool , bool isFullyPopulated )
2017-08-08 13:25:18 +02:00
: base ( pool )
{
2017-09-28 18:35:51 +02:00
IsFullyPopulated = isFullyPopulated ;
2017-08-08 13:25:18 +02:00
SetupCells ( ) ;
}
2017-09-28 18:35:51 +02:00
public UpdatePageDataGridViewRow ( Host host , bool hasPool , bool isFullyPopulated )
2017-08-08 13:25:18 +02:00
: base ( host , hasPool )
{
2017-09-28 18:35:51 +02:00
IsFullyPopulated = isFullyPopulated ;
2017-08-08 13:25:18 +02:00
SetupCells ( ) ;
}
2017-08-22 13:41:00 +02:00
public int IconCellIndex
{
get { return Cells . IndexOf ( _poolIconCell ) ; }
}
2017-08-10 14:46:59 +02:00
public int VersionCellIndex
{
get { return Cells . IndexOf ( _versionCell ) ; }
}
2017-08-22 13:41:00 +02:00
public int PatchingStatusCellIndex
{
get { return Cells . IndexOf ( _patchingStatusCell ) ; }
}
2017-08-10 14:46:59 +02:00
public int StatusCellIndex
{
get { return Cells . IndexOf ( _statusCell ) ; }
}
2017-08-22 13:41:00 +02:00
public override bool IsCheckable
2017-08-08 13:25:18 +02:00
{
2017-08-22 13:41:00 +02:00
get { return IsPoolOrStandaloneHost ; }
}
2017-08-08 13:25:18 +02:00
2017-09-28 18:35:51 +02:00
public bool IsFullyPopulated { get ; private set ; }
2017-08-22 13:41:00 +02:00
private void SetupCells ( )
{
2017-08-08 13:25:18 +02:00
_nameCell = new DataGridViewTextAndImageCell ( ) ;
2018-12-10 18:15:23 +01:00
Cells . AddRange ( _expansionCell , _poolIconCell , _nameCell , _versionCell , _patchingStatusCell , _statusCell , _requiredUpdateCell , _installedUpdateCell ) ;
2017-08-08 13:25:18 +02:00
2018-12-10 18:15:23 +01:00
UpdateDetails ( ) ;
2017-08-08 13:25:18 +02:00
}
// fill data into row
private void UpdateDetails ( )
{
Pool pool = Tag as Pool ;
if ( pool ! = null )
{
Host master = pool . Connection . Resolve ( pool . master ) ;
2017-08-22 13:41:00 +02:00
SetCollapseIcon ( ) ;
2017-08-08 13:25:18 +02:00
_poolIconCell . Value = Images . GetImage16For ( pool ) ;
DataGridViewTextAndImageCell nc = _nameCell as DataGridViewTextAndImageCell ;
if ( nc ! = null )
nc . Image = null ;
_nameCell . Value = pool . Name ( ) ;
_versionCell . Value = master . ProductVersionTextShort ( ) ;
2017-09-28 18:35:51 +02:00
_requiredUpdateCell . Value = String . Empty ;
_installedUpdateCell . Value = String . Empty ;
if ( IsFullyPopulated )
{
var outOfDate = pool . Connection . Cache . Hosts . Any ( h = > RequiredUpdatesForHost ( h ) . Length > 0 ) ;
_patchingStatusCell . Value = outOfDate
? Properties . Resources . _000_error_h32bit_16
: Properties . Resources . _000_Tick_h32bit_16 ;
_statusCell . Value = outOfDate ? Messages . NOT_UPDATED : Messages . UPDATED ;
}
else
{
_statusCell . Value = String . Empty ;
}
2017-08-08 13:25:18 +02:00
}
else
{
Host host = Tag as Host ;
if ( host ! = null )
{
2017-08-24 12:54:16 +02:00
var hostRequired = RequiredUpdatesForHost ( host ) ;
var hostInstalled = InstalledUpdatesForHost ( host ) ;
var outOfDate = hostRequired . Length > 0 ;
2017-08-08 13:25:18 +02:00
DataGridViewTextAndImageCell nc = _nameCell as DataGridViewTextAndImageCell ;
if ( _hasPool & & nc ! = null ) // host in pool
{
nc . Image = Images . GetImage16For ( host ) ;
2017-09-28 18:35:51 +02:00
_statusCell . Value = String . Empty ;
2017-08-08 13:25:18 +02:00
}
else if ( ! _hasPool & & nc ! = null ) // standalone host
{
_poolIconCell . Value = Images . GetImage16For ( host ) ;
nc . Image = null ;
2017-09-28 18:35:51 +02:00
if ( IsFullyPopulated )
{
_patchingStatusCell . Value = outOfDate
? Properties . Resources . _000_error_h32bit_16
: Properties . Resources . _000_Tick_h32bit_16 ;
_statusCell . Value = outOfDate ? Messages . NOT_UPDATED : Messages . UPDATED ;
}
else
{
_statusCell . Value = String . Empty ;
}
2017-08-08 13:25:18 +02:00
}
_nameCell . Value = host . Name ( ) ;
_versionCell . Value = host . ProductVersionTextShort ( ) ;
_installedUpdateCell . Value = hostInstalled ;
2017-09-28 18:35:51 +02:00
if ( IsFullyPopulated )
_requiredUpdateCell . Value = hostRequired ;
else
_requiredUpdateCell . Value = String . Empty ;
2017-08-08 13:25:18 +02:00
}
}
}
2017-08-08 14:37:12 +02:00
}
2017-08-24 12:54:16 +02:00
private static string RequiredUpdatesForHost ( Host host )
2017-08-08 14:37:12 +02:00
{
2017-08-24 12:54:16 +02:00
var requiredUpdates = Updates . RecommendedPatchesForHost ( host ) ;
2017-08-08 13:25:18 +02:00
2017-08-24 12:54:16 +02:00
if ( requiredUpdates = = null )
{
// versions with no minimum patches
var updatesList = new List < string > ( ) ;
var alerts = new List < Alert > ( Updates . UpdateAlerts ) ;
if ( alerts . Count = = 0 )
return String . Empty ;
foreach ( Alert alert in alerts )
{
2017-09-11 16:44:55 +02:00
var patchAlert = alert as XenServerPatchAlert ;
if ( patchAlert = = null )
2017-08-24 12:54:16 +02:00
continue ;
2017-09-11 16:44:55 +02:00
if ( patchAlert . DistinctHosts . Contains ( host ) )
updatesList . Add ( patchAlert . Name ) ;
2017-08-24 12:54:16 +02:00
}
updatesList . Sort ( StringUtility . NaturalCompare ) ;
return string . Join ( ", " , updatesList . ToArray ( ) ) ;
}
else
{
// versions with minimum patches
var result = new List < string > ( ) ;
foreach ( var patch in requiredUpdates )
result . Add ( patch . Name ) ;
return string . Join ( ", " , result . ToArray ( ) ) ;
}
}
private static string InstalledUpdatesForHost ( Host host )
{
List < string > result = new List < string > ( ) ;
2018-06-28 16:33:08 +02:00
result . AddRange ( Helpers . ElyOrGreater ( host )
? host . AppliedUpdates ( ) . Select ( u = > u . Name ( ) )
: host . AppliedPatches ( ) . Select ( p = > p . Name ( ) ) ) ;
2017-08-08 13:25:18 +02:00
2017-08-24 12:54:16 +02:00
result . Sort ( StringUtility . NaturalCompare ) ;
2017-08-08 14:37:12 +02:00
return string . Join ( ", " , result . ToArray ( ) ) ;
2017-08-08 13:25:18 +02:00
}
2017-10-03 16:32:57 +02:00
private bool VersionFoundInUpdatesXml ( IXenConnection connection )
{
2017-10-03 16:32:57 +02:00
return connection . Cache . Hosts . All ( h = > Updates . GetServerVersions ( h , Updates . XenServerVersions ) . Count > 0 ) ;
2017-10-03 16:32:57 +02:00
}
2018-07-11 14:29:41 +02:00
private bool VersionFoundInUpdatesXml ( Host host )
{
return Updates . GetServerVersions ( host , Updates . XenServerVersions ) . Count > 0 ;
}
2017-08-08 13:25:18 +02:00
private void RebuildHostView ( )
{
try
{
dataGridViewHosts . SuspendLayout ( ) ;
if ( dataGridViewHosts . RowCount > 0 )
{
2017-08-29 15:36:29 +02:00
StoreStateOfRows ( ) ;
2017-08-08 13:25:18 +02:00
dataGridViewHosts . Rows . Clear ( ) ;
dataGridViewHosts . Refresh ( ) ;
}
ToggleCentreWarningVisibility ( ) ;
List < IXenConnection > xenConnections = ConnectionsManager . XenConnectionsCopy ;
xenConnections . Sort ( ) ;
var rowList = new List < DataGridViewRow > ( ) ;
foreach ( IXenConnection c in xenConnections )
{
Pool pool = Helpers . GetPool ( c ) ;
if ( pool ! = null ) // pool row
{
2018-12-11 13:52:59 +01:00
var row = new UpdatePageDataGridViewRow ( pool , VersionFoundInUpdatesXml ( c ) ) ;
2017-08-08 13:25:18 +02:00
var hostUuidList = new List < string > ( ) ;
foreach ( Host h in c . Cache . Hosts )
hostUuidList . Add ( h . uuid ) ;
// add row based on server filter status
if ( ! toolStripDropDownButtonServerFilter . HideByLocation ( hostUuidList ) )
rowList . Add ( row ) ;
}
Host [ ] hosts = c . Cache . Hosts ;
Array . Sort ( hosts ) ;
foreach ( Host h in hosts ) // host row
{
2018-12-11 13:52:59 +01:00
var row = new UpdatePageDataGridViewRow ( h , pool ! = null , VersionFoundInUpdatesXml ( h ) ) ;
2017-08-08 13:25:18 +02:00
// add row based on server filter status
if ( ! toolStripDropDownButtonServerFilter . HideByLocation ( h . uuid ) )
rowList . Add ( row ) ;
}
}
dataGridViewHosts . Rows . AddRange ( rowList . ToArray ( ) ) ;
2017-08-29 15:36:29 +02:00
// restore selected state and pool collapsed state
bool checkHostRow = false ;
foreach ( UpdatePageDataGridViewRow row in dataGridViewHosts . Rows )
2017-08-08 13:25:18 +02:00
{
2017-08-29 15:36:29 +02:00
if ( checkHostRow )
{
if ( ! row . IsPoolOrStandaloneHost )
{
row . Visible = ! row . Visible ;
continue ;
}
else
checkHostRow = false ;
}
2017-08-08 13:25:18 +02:00
2017-08-29 15:36:29 +02:00
Pool pool = row . Tag as Pool ;
2017-08-08 13:25:18 +02:00
if ( pool ! = null )
2017-08-29 15:36:29 +02:00
{
2017-08-08 13:25:18 +02:00
row . Selected = selectedUpdates . Contains ( pool . uuid ) ;
2017-08-29 15:36:29 +02:00
if ( collapsedPoolRowsList . Contains ( pool . uuid ) )
{
row . SetExpandIcon ( ) ;
checkHostRow = true ;
}
}
2017-08-08 13:25:18 +02:00
else
{
Host host = row . Tag as Host ;
if ( host ! = null )
row . Selected = selectedUpdates . Contains ( host . uuid ) ;
}
}
if ( dataGridViewHosts . SelectedRows . Count = = 0 & & dataGridViewHosts . Rows . Count > 0 )
dataGridViewHosts . Rows [ 0 ] . Selected = true ;
}
finally
{
dataGridViewHosts . ResumeLayout ( ) ;
UpdateButtonEnablement ( ) ;
}
}
private void RebuildUpdateView ( )
2013-06-24 13:41:48 +02:00
{
try
{
2013-12-05 13:46:39 +01:00
dataGridViewUpdates . SuspendLayout ( ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
if ( dataGridViewUpdates . RowCount > 0 )
{
2017-08-29 15:36:29 +02:00
StoreStateOfRows ( ) ;
2013-12-05 13:46:39 +01:00
dataGridViewUpdates . Rows . Clear ( ) ;
2015-07-30 19:00:06 +02:00
dataGridViewUpdates . Refresh ( ) ;
2013-12-05 13:46:39 +01:00
}
2013-06-24 13:41:48 +02:00
2017-06-11 11:49:25 +02:00
ToggleCentreWarningVisibility ( ) ;
2018-12-11 13:52:59 +01:00
2017-06-11 11:49:25 +02:00
var updates = new List < Alert > ( Updates . UpdateAlerts ) ;
2013-12-05 13:46:39 +01:00
if ( updates . Count = = 0 )
2013-06-24 13:41:48 +02:00
return ;
2015-07-23 14:48:30 +02:00
updates . RemoveAll ( FilterAlert ) ;
2017-05-26 13:54:46 +02:00
sortUpdates ( updates ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
var rowList = new List < DataGridViewRow > ( ) ;
foreach ( var myAlert in updates )
rowList . Add ( NewUpdateRow ( myAlert ) ) ;
dataGridViewUpdates . Rows . AddRange ( rowList . ToArray ( ) ) ;
foreach ( DataGridViewRow row in dataGridViewUpdates . Rows )
row . Selected = selectedUpdates . Contains ( ( ( Alert ) row . Tag ) . uuid ) ;
if ( dataGridViewUpdates . SelectedRows . Count = = 0 & & dataGridViewUpdates . Rows . Count > 0 )
dataGridViewUpdates . Rows [ 0 ] . Selected = true ;
2013-06-24 13:41:48 +02:00
}
finally
{
dataGridViewUpdates . ResumeLayout ( ) ;
2013-12-05 13:46:39 +01:00
UpdateButtonEnablement ( ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
}
2013-06-24 13:41:48 +02:00
2017-06-11 11:49:25 +02:00
private void ToggleCentreWarningVisibility ( )
{
2018-12-11 13:52:59 +01:00
if ( byUpdateToolStripMenuItem . Checked & & Updates . UpdateAlertsCount = = 0 )
2017-06-11 11:49:25 +02:00
{
pictureBoxProgress . Image = SystemIcons . Information . ToBitmap ( ) ;
2018-12-11 13:52:59 +01:00
labelProgress . Text = Messages . AVAILABLE_UPDATES_NOT_FOUND ;
tableLayoutPanel3 . Visible = true ;
}
else
{
tableLayoutPanel3 . Visible = false ;
2017-06-11 11:49:25 +02:00
}
}
2015-07-29 12:34:39 +02:00
/// <summary>
2018-12-11 13:52:59 +01:00
/// Toggles the visibility of the warning that appears above the grid saying:
2017-06-07 02:16:56 +02:00
/// "Automatic checking for updates is disabled for some types of updates".
2015-07-29 12:34:39 +02:00
/// </summary>
2018-12-11 13:52:59 +01:00
private void ToggleTopWarningVisibility ( )
2015-07-29 12:34:39 +02:00
{
2018-12-11 13:52:59 +01:00
bool visible = ! Properties . Settings . Default . AllowPatchesUpdates | |
! Properties . Settings . Default . AllowXenCenterUpdates | |
! Properties . Settings . Default . AllowXenServerUpdates ;
2017-06-07 02:16:56 +02:00
pictureBox1 . Visible = visible ;
AutoCheckForUpdatesDisabledLabel . Visible = visible ;
2017-06-11 11:49:25 +02:00
checkForUpdatesNowLink . Visible = visible ;
2015-07-29 12:34:39 +02:00
}
2013-12-05 13:46:39 +01:00
/// <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>
private bool FilterAlert ( Alert alert )
{
2014-01-03 12:27:11 +01:00
var hosts = new List < string > ( ) ;
var serverUpdate = alert as XenServerUpdateAlert ;
if ( serverUpdate ! = null )
hosts = serverUpdate . DistinctHosts . Select ( h = > h . uuid ) . ToList ( ) ;
2015-07-23 14:48:30 +02:00
bool hide = false ;
2015-07-23 12:48:14 +02:00
CA-147941: Fixed the RPU wizard hang in "Reconnecting Storage" and connecting action stuck in progress state
In some cases calling Control.Invoke() from a background thread causes that thread to go in a "sleep, wait, or join" mode, while waiting for Invoke to happen, although the UI thread is running normally.
If the Control is the MainWindow, it works as expected, but we've seen it happening while connecting or disconnecting from a large pool, on calling Invoke on controls like NavigationView, AlertSummaryPage, HistoryPage, etc.
To fix this, we call the Invoke on the MainWindow in all the places where we've seen the issue.
With this changes, the previous fix for CA-148245 (call RequestRefreshTreeView on CacheClearing event) is not needed anymore, so I removed that call.
Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
2014-10-10 14:16:50 +02:00
Program . Invoke ( Program . MainWindow , ( ) = >
2013-12-05 13:46:39 +01:00
hide = toolStripDropDownButtonDateFilter . HideByDate ( alert . Timestamp . ToLocalTime ( ) )
2015-07-23 14:48:30 +02:00
| | toolStripDropDownButtonServerFilter . HideByLocation ( hosts ) | | alert . IsDismissed ( ) ) ;
2013-12-05 13:46:39 +01:00
return hide ;
2013-06-24 13:41:48 +02:00
}
2017-08-29 15:36:29 +02:00
private void StoreStateOfRows ( )
2013-06-24 13:41:48 +02:00
{
2017-08-08 13:25:18 +02:00
selectedUpdates . Clear ( ) ;
2017-08-29 15:36:29 +02:00
if ( byUpdateToolStripMenuItem . Checked ) // by update view
2017-08-08 13:25:18 +02:00
{
selectedUpdates = ( dataGridViewUpdates . SelectedRows . Cast < DataGridViewRow > ( ) . Select (
selectedRow = > ( ( Alert ) selectedRow . Tag ) . uuid ) ) . ToList ( ) ;
}
2017-08-29 15:36:29 +02:00
else // by host view
2017-08-08 13:25:18 +02:00
{
2017-08-29 15:36:29 +02:00
collapsedPoolRowsList . Clear ( ) ;
foreach ( UpdatePageDataGridViewRow row in dataGridViewHosts . Rows )
2017-08-08 13:25:18 +02:00
{
Pool pool = row . Tag as Pool ;
if ( pool ! = null )
2017-08-29 15:36:29 +02:00
{
if ( row . Selected )
selectedUpdates . Add ( pool . uuid ) ;
if ( row . IsACollapsedRow )
collapsedPoolRowsList . Add ( pool . uuid ) ;
}
2017-08-08 13:25:18 +02:00
else
{
Host host = row . Tag as Host ;
2017-08-29 15:36:29 +02:00
if ( host ! = null & & row . Selected )
2017-08-08 13:25:18 +02:00
selectedUpdates . Add ( host . uuid ) ;
}
}
}
2013-12-05 13:46:39 +01:00
}
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
private void UpdateButtonEnablement ( )
{
2017-09-14 14:50:33 +02:00
if ( byUpdateToolStripMenuItem . Checked )
2018-12-11 13:52:59 +01:00
{
2017-09-14 14:50:33 +02:00
toolStripButtonExportAll . Enabled = toolStripSplitButtonDismiss . Enabled = Updates . UpdateAlertsCount > 0 ;
2018-12-11 13:52:59 +01:00
}
2017-09-14 14:50:33 +02:00
else
2017-08-15 15:35:20 +02:00
{
2017-09-14 14:50:33 +02:00
var connectionList = ConnectionsManager . XenConnectionsCopy ;
2018-12-11 13:52:59 +01:00
toolStripButtonUpdate . Enabled = toolStripButtonExportAll . Enabled = connectionList . Any ( xenConnection = > xenConnection . IsConnected ) ;
2017-09-14 14:50:33 +02:00
}
2013-06-24 13:41:48 +02:00
}
2013-11-23 15:04:15 +01:00
private void ShowInformationHelper ( string reason )
2013-06-24 13:41:48 +02:00
{
2013-11-23 15:04:15 +01:00
if ( string . IsNullOrEmpty ( reason ) )
{
tableLayoutPanel1 . Visible = false ;
2013-06-24 13:41:48 +02:00
}
2013-11-23 15:04:15 +01:00
else
2013-06-24 13:41:48 +02:00
{
2013-11-23 15:04:15 +01:00
informationLabel . Text = reason ;
2016-04-06 08:33:18 +02:00
tableLayoutPanel1 . Visible = ! HiddenFeatures . LinkLabelHidden ;
2013-06-24 13:41:48 +02:00
}
}
private DataGridViewRow NewUpdateRow ( Alert alert )
{
2013-12-05 13:46:39 +01:00
var expanderCell = 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
2013-07-11 20:09:29 +02:00
// 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 ;
2013-12-05 13:46:39 +01:00
detailCell . Value = String . Format ( "{0}\n\n{1}" , alert . Title , alert . Description ) ;
2013-07-11 20:09:29 +02:00
}
else
{
// show the expand arrow and just the title
expanderCell . Value = Properties . Resources . contracted_triangle ;
2013-12-05 13:46:39 +01:00
detailCell . Value = alert . Title ;
2013-07-11 20:09:29 +02:00
}
2013-12-05 13:46:39 +01:00
appliesCell . Value = alert . AppliesTo ;
2015-01-20 19:05:21 +01:00
dateCell . Value = HelpersGUI . DateTimeToString ( alert . Timestamp . ToLocalTime ( ) , Messages . DATEFORMAT_DMY , true ) ;
2013-12-05 13:46:39 +01:00
newRow . Cells . AddRange ( expanderCell , detailCell , appliesCell , dateCell , actionCell ) ;
2013-06-24 13:41:48 +02:00
return newRow ;
}
2017-06-07 02:16:32 +02:00
private void RemoveUpdateRow ( Alert a )
{
for ( int i = 0 ; i < dataGridViewUpdates . Rows . Count ; i + + )
{
if ( ( ( Alert ) dataGridViewUpdates . Rows [ i ] . Tag ) . uuid = = a . uuid )
dataGridViewUpdates . Rows . RemoveAt ( i ) ;
}
}
2013-12-05 13:46:39 +01:00
private List < ToolStripItem > GetAlertActionItems ( Alert alert )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
var items = new List < ToolStripItem > ( ) ;
2013-07-11 20:09:29 +02:00
2013-12-05 13:46:39 +01:00
var patchAlert = alert as XenServerPatchAlert ;
2015-07-23 12:48:14 +02:00
if ( Alert . AllowedToDismiss ( alert ) )
{
var dismiss = new ToolStripMenuItem ( Messages . ALERT_DISMISS ) ;
dismiss . Click + = ToolStripMenuItemDismiss_Click ;
items . Add ( dismiss ) ;
}
2017-03-22 11:59:32 +01:00
if ( patchAlert ! = null & & patchAlert . CanApply & & ! string . IsNullOrEmpty ( patchAlert . Patch . PatchUrl ) & & patchAlert . RequiredXenCenterVersion = = null )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
var download = new ToolStripMenuItem ( Messages . UPDATES_DOWNLOAD_AND_INSTALL ) ;
download . Click + = ToolStripMenuItemDownload_Click ;
items . Add ( download ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
2017-03-22 11:59:32 +01:00
var updateAlert = alert as XenServerUpdateAlert ;
if ( updateAlert ! = null & & updateAlert . RequiredXenCenterVersion ! = null )
{
var downloadNewXenCenter = new ToolStripMenuItem ( Messages . UPDATES_DOWNLOAD_REQUIRED_XENCENTER ) ;
downloadNewXenCenter . Click + = ToolStripMenuItemDownloadNewXenCenter_Click ;
items . Add ( downloadNewXenCenter ) ;
}
2013-12-05 13:46:39 +01:00
if ( ! string . IsNullOrEmpty ( alert . WebPageLabel ) )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
var fix = new ToolStripMenuItem ( alert . FixLinkText ) ;
fix . Click + = ToolStripMenuItemGoToWebPage_Click ;
items . Add ( fix ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
if ( items . Count > 0 )
items . Add ( new ToolStripSeparator ( ) ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
var copy = new ToolStripMenuItem ( Messages . COPY ) ;
copy . Click + = ToolStripMenuItemCopy_Click ;
items . Add ( copy ) ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
return items ;
2013-06-24 13:41:48 +02:00
}
2015-07-23 12:48:14 +02:00
#region Update dismissal
2017-06-07 02:16:32 +02:00
private void DismissUpdates ( IEnumerable < Alert > alerts )
2015-07-23 12:48:14 +02:00
{
var groups = from Alert alert in alerts
where alert ! = null & & ! alert . Dismissing
group alert by alert . Connection
2015-07-29 14:43:47 +02:00
into g
select new { Connection = g . Key , Alerts = g } ;
2015-07-23 12:48:14 +02:00
foreach ( var g in groups )
{
if ( Alert . AllowedToDismiss ( g . Connection ) )
{
foreach ( Alert alert in g . Alerts )
{
alert . Dismissing = true ;
}
2015-07-29 14:43:47 +02:00
toolStripButtonRestoreDismissed . Enabled = false ;
2015-07-23 12:48:14 +02:00
DeleteAllAlertsAction action = new DeleteAllAlertsAction ( g . Connection , g . Alerts ) ;
2018-12-11 13:52:59 +01:00
action . Completed + = DeleteAllAlertsAction_Completed ;
2015-07-23 12:48:14 +02:00
action . RunAsync ( ) ;
}
}
}
2015-07-29 14:43:47 +02:00
/// <summary>
/// After the Delete action is completed the page is refreshed and the restore dismissed
/// button is enabled again.
/// </summary>
/// <param name="sender"></param>
2018-12-11 13:52:59 +01:00
private void DeleteAllAlertsAction_Completed ( ActionBase sender )
2015-07-23 12:48:14 +02:00
{
Program . Invoke ( Program . MainWindow , ( ) = >
2017-06-07 02:16:32 +02:00
{
2015-07-29 14:43:47 +02:00
toolStripButtonRestoreDismissed . Enabled = true ;
2017-06-11 11:49:25 +02:00
ToggleCentreWarningVisibility ( ) ;
2018-12-11 13:52:59 +01:00
ToggleTopWarningVisibility ( ) ;
2015-07-23 12:48:14 +02:00
} ) ;
}
#endregion
2013-12-05 13:46:39 +01:00
#region Actions DropDown event handlers
2013-06-24 13:41:48 +02:00
2015-07-29 14:43:47 +02:00
private void toolStripSplitButtonDismiss_DropDownItemClicked ( object sender , ToolStripItemClickedEventArgs e )
{
toolStripSplitButtonDismiss . DefaultItem = e . ClickedItem ;
toolStripSplitButtonDismiss . Text = toolStripSplitButtonDismiss . DefaultItem . Text ;
}
/// <summary>
/// If the answer of the user to the dialog is YES, then make a list with all the updates and call
/// DismissUpdates on that list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dismissAllToolStripMenuItem_Click ( object sender , EventArgs e )
{
2016-11-17 14:35:31 +01:00
DialogResult result = DialogResult . Yes ;
2015-07-29 14:43:47 +02:00
2016-11-17 14:35:31 +01:00
if ( FilterIsOn )
2015-07-29 14:43:47 +02:00
{
using ( var dlog = new ThreeButtonDialog (
2016-11-17 14:35:31 +01:00
new ThreeButtonDialog . Details ( null , Messages . UPDATE_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 ) ,
2015-07-29 14:43:47 +02:00
ThreeButtonDialog . ButtonCancel ) )
{
result = dlog . ShowDialog ( this ) ;
}
}
2016-11-17 14:35:31 +01:00
else if ( ! Properties . Settings . Default . DoNotConfirmDismissUpdates )
2015-07-29 14:43:47 +02:00
{
using ( var dlog = new ThreeButtonDialog (
2016-11-17 14:35:31 +01:00
new ThreeButtonDialog . Details ( null , Messages . UPDATE_DISMISS_ALL_NO_FILTER_CONTINUE ) ,
new ThreeButtonDialog . TBDButton ( Messages . DISMISS_ALL_YES_CONFIRM_BUTTON , DialogResult . Yes ) ,
ThreeButtonDialog . ButtonCancel )
{
ShowCheckbox = true ,
CheckboxCaption = Messages . DO_NOT_SHOW_THIS_MESSAGE
} )
2015-07-29 14:43:47 +02:00
{
result = dlog . ShowDialog ( this ) ;
2016-11-17 14:35:31 +01:00
Properties . Settings . Default . DoNotConfirmDismissUpdates = dlog . IsCheckBoxChecked ;
Settings . TrySaveSettings ( ) ;
2015-07-29 14:43:47 +02:00
}
}
if ( result = = DialogResult . Cancel )
return ;
var alerts = result = = DialogResult . No
? from DataGridViewRow row in dataGridViewUpdates . Rows select row . Tag as Alert
: Updates . UpdateAlerts ;
DismissUpdates ( alerts ) ;
}
/// <summary>
/// If the answer of the user to the dialog is YES, then make a list of all the selected rows
/// and call DismissUpdates on that list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dismissSelectedToolStripMenuItem_Click ( object sender , EventArgs e )
{
2016-11-17 14:35:31 +01:00
if ( ! Properties . Settings . Default . DoNotConfirmDismissUpdates )
2015-07-29 14:43:47 +02:00
{
2016-11-17 14:35:31 +01:00
using ( var dlog = new ThreeButtonDialog (
new ThreeButtonDialog . Details ( null , Messages . UPDATE_DISMISS_SELECTED_CONFIRM , Messages . XENCENTER ) ,
ThreeButtonDialog . ButtonYes , ThreeButtonDialog . ButtonNo )
{
ShowCheckbox = true ,
CheckboxCaption = Messages . DO_NOT_SHOW_THIS_MESSAGE
} )
{
var result = dlog . ShowDialog ( this ) ;
Properties . Settings . Default . DoNotConfirmDismissUpdates = dlog . IsCheckBoxChecked ;
Settings . TrySaveSettings ( ) ;
if ( result ! = DialogResult . Yes )
return ;
}
2015-07-29 14:43:47 +02:00
}
if ( dataGridViewUpdates . SelectedRows . Count > 0 )
{
var selectedAlerts = from DataGridViewRow row in dataGridViewUpdates . SelectedRows select row . Tag as Alert ;
DismissUpdates ( selectedAlerts ) ;
}
}
private void ToolStripMenuItemDismiss_Click ( object sender , EventArgs e )
{
if ( dataGridViewUpdates . SelectedRows . Count ! = 1 )
log . DebugFormat ( "Only 1 update can be dismissed at a time (Attempted to dismiss {0}). Dismissing the clicked item." , dataGridViewUpdates . SelectedRows . Count ) ;
DataGridViewRow clickedRow = FindAlertRow ( sender as ToolStripMenuItem ) ;
if ( clickedRow = = null )
{
log . Debug ( "Attempted to dismiss update with no update selected." ) ;
return ;
}
Alert alert = ( Alert ) clickedRow . Tag ;
if ( alert = = null )
return ;
2016-11-17 14:35:31 +01:00
if ( ! Properties . Settings . Default . DoNotConfirmDismissUpdates )
{
using ( var dlog = new ThreeButtonDialog (
2015-07-29 14:43:47 +02:00
new ThreeButtonDialog . Details ( null , Messages . UPDATE_DISMISS_CONFIRM , Messages . XENCENTER ) ,
ThreeButtonDialog . ButtonYes ,
2016-11-17 14:35:31 +01:00
ThreeButtonDialog . ButtonNo )
{
ShowCheckbox = true ,
CheckboxCaption = Messages . DO_NOT_SHOW_THIS_MESSAGE
} )
{
var result = dlog . ShowDialog ( this ) ;
Properties . Settings . Default . DoNotConfirmDismissUpdates = dlog . IsCheckBoxChecked ;
Settings . TrySaveSettings ( ) ;
if ( result ! = DialogResult . Yes )
return ;
}
2015-07-29 14:43:47 +02:00
}
DismissUpdates ( new List < Alert > { ( Alert ) clickedRow . Tag } ) ;
}
2015-07-23 12:48:14 +02:00
2014-06-30 15:49:16 +02:00
private DataGridViewRow FindAlertRow ( ToolStripMenuItem toolStripMenuItem )
{
if ( toolStripMenuItem = = null )
return null ;
return ( from DataGridViewRow row in dataGridViewUpdates . Rows
where row . Cells . Count > 0
let actionCell = row . Cells [ row . Cells . Count - 1 ] as DataGridViewDropDownSplitButtonCell
where actionCell ! = null & & actionCell . ContextMenu . Items . Cast < object > ( ) . Any ( item = > item is ToolStripMenuItem & & item = = toolStripMenuItem )
select row ) . FirstOrDefault ( ) ;
}
2013-12-05 13:46:39 +01:00
private void ToolStripMenuItemGoToWebPage_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
2014-06-30 15:49:16 +02:00
DataGridViewRow clickedRow = FindAlertRow ( sender as ToolStripMenuItem ) ;
if ( clickedRow = = null )
return ;
Alert alert = ( Alert ) clickedRow . Tag ;
if ( alert ! = null & & alert . FixLinkAction ! = null )
alert . FixLinkAction . Invoke ( ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void ToolStripMenuItemDownload_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
2014-06-30 15:49:16 +02:00
DataGridViewRow clickedRow = FindAlertRow ( sender as ToolStripMenuItem ) ;
if ( clickedRow = = null )
2013-06-24 13:41:48 +02:00
return ;
2014-06-30 15:49:16 +02:00
XenServerPatchAlert patchAlert = ( XenServerPatchAlert ) clickedRow . Tag ;
2013-06-24 13:41:48 +02:00
if ( patchAlert = = null )
return ;
string patchUri = patchAlert . Patch . PatchUrl ;
if ( string . IsNullOrEmpty ( patchUri ) )
return ;
2018-08-06 13:55:25 +02:00
PatchingWizard wizard = ( PatchingWizard ) Program . MainWindow . ShowForm ( typeof ( PatchingWizard ) ) ;
if ( ! wizard . IsFirstPage ( ) )
return ;
2017-08-15 15:35:20 +02:00
wizard . NextStep ( ) ;
wizard . AddAlert ( patchAlert ) ;
wizard . NextStep ( ) ;
var hosts = patchAlert . DistinctHosts ;
if ( hosts . Count > 0 )
{
wizard . SelectServers ( hosts ) ;
}
else
2013-06-24 13:41:48 +02:00
{
2017-08-15 15:35:20 +02:00
string disconnectedServerNames =
clickedRow . Cells [ ColumnLocation . Index ] . Value . ToString ( ) ;
using ( var dlg = new ThreeButtonDialog (
new ThreeButtonDialog . Details ( SystemIcons . Warning ,
string . Format ( Messages . UPDATES_WIZARD_DISCONNECTED_SERVER ,
disconnectedServerNames ) ,
Messages . UPDATES_WIZARD ) ) )
2015-07-20 15:28:44 +02:00
{
2017-08-15 15:35:20 +02:00
dlg . ShowDialog ( this ) ;
}
}
2013-06-24 13:41:48 +02:00
}
2017-03-22 11:59:32 +01:00
private void ToolStripMenuItemDownloadNewXenCenter_Click ( object sender , EventArgs e )
{
DataGridViewRow clickedRow = FindAlertRow ( sender as ToolStripMenuItem ) ;
if ( clickedRow = = null )
return ;
XenServerUpdateAlert updateAlert = ( XenServerUpdateAlert ) clickedRow . Tag ;
if ( updateAlert = = null | | updateAlert . RequiredXenCenterVersion = = null )
return ;
string xenCenterUrl = updateAlert . RequiredXenCenterVersion . Url ;
if ( string . IsNullOrEmpty ( xenCenterUrl ) )
return ;
Program . Invoke ( Program . MainWindow , ( ) = > Program . OpenURL ( xenCenterUrl ) ) ;
}
2013-12-05 13:46:39 +01:00
private void ToolStripMenuItemCopy_Click ( object sender , EventArgs e )
2013-06-24 13:41:48 +02:00
{
2014-06-30 15:49:16 +02:00
DataGridViewRow clickedRow = FindAlertRow ( sender as ToolStripMenuItem ) ;
if ( clickedRow = = null )
2013-12-05 13:46:39 +01:00
return ;
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
StringBuilder sb = new StringBuilder ( ) ;
2014-06-30 15:49:16 +02:00
if ( dataGridViewUpdates . SelectedRows . Count > 1 & & dataGridViewUpdates . SelectedRows . Contains ( clickedRow ) )
{
foreach ( DataGridViewRow r in dataGridViewUpdates . SelectedRows )
{
Alert alert = ( Alert ) r . Tag ;
sb . AppendLine ( alert . GetUpdateDetailsCSVQuotes ( ) ) ;
}
}
else
2013-06-24 13:41:48 +02:00
{
2014-06-30 15:49:16 +02:00
Alert alert = ( Alert ) clickedRow . Tag ;
if ( alert ! = null )
sb . AppendLine ( alert . GetUpdateDetailsCSVQuotes ( ) ) ;
2013-06-24 13:41:48 +02:00
}
2016-10-13 17:16:16 +02:00
Clip . SetClipboardText ( sb . ToString ( ) ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
#endregion
2013-06-24 13:41:48 +02:00
2013-12-05 13:46:39 +01:00
#region DataGridView event handlers
2013-06-24 13:41:48 +02:00
private void dataGridViewUpdates_SelectionChanged ( object sender , EventArgs e )
{
2013-12-05 13:46:39 +01:00
string reason = null ;
if ( dataGridViewUpdates . SelectedRows . Count > 0 )
{
var alert = dataGridViewUpdates . SelectedRows [ 0 ] . Tag as XenServerPatchAlert ;
if ( alert ! = null )
reason = alert . CannotApplyReason ;
}
ShowInformationHelper ( reason ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
private void dataGridViewUpdates_ColumnHeaderMouseClick ( object sender , DataGridViewCellMouseEventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
if ( dataGridViewUpdates . Columns [ e . ColumnIndex ] . SortMode = = DataGridViewColumnSortMode . Automatic )
Rebuild ( ) ;
2013-06-24 13:41:48 +02:00
}
2013-12-05 13:46:39 +01:00
/// <summary>
/// Handles the automatic sorting of the AlertsGridView for the non-string columns
/// </summary>
private void dataGridViewUpdates_SortCompare ( object sender , DataGridViewSortCompareEventArgs e )
2013-06-24 13:41:48 +02:00
{
2013-12-05 13:46:39 +01:00
Alert alert1 = ( Alert ) dataGridViewUpdates . Rows [ e . RowIndex1 ] . Tag ;
Alert alert2 = ( Alert ) dataGridViewUpdates . Rows [ e . RowIndex2 ] . Tag ;
if ( e . Column . Index = = ColumnDate . Index )
{
int sortResult = DateTime . Compare ( alert1 . Timestamp , alert2 . Timestamp ) ;
e . SortResult = ( dataGridViewUpdates . SortOrder = = SortOrder . Descending ) ? sortResult * = - 1 : sortResult ;
e . Handled = true ;
}
2013-06-24 13:41:48 +02:00
}
2013-07-11 20:09:29 +02:00
private void dataGridViewUpdates_CellClick ( object sender , DataGridViewCellEventArgs e )
{
// If you click on the headers you can get -1 as the index.
2013-07-12 12:07:10 +02:00
if ( e . ColumnIndex < 0 | | e . RowIndex < 0 | | e . ColumnIndex ! = ColumnExpand . Index )
2013-07-11 20:09:29 +02:00
return ;
2013-12-05 13:46:39 +01:00
ToggleExpandedState ( e . RowIndex ) ;
2013-07-11 20:09:29 +02:00
}
private void dataGridViewUpdates_CellDoubleClick ( object sender , DataGridViewCellEventArgs e )
{
// If you click on the headers you can get -1 as the index.
if ( e . ColumnIndex < 0 | | e . RowIndex < 0 )
return ;
2013-12-05 13:46:39 +01:00
ToggleExpandedState ( e . RowIndex ) ;
2013-07-11 20:09:29 +02:00
}
private void dataGridViewUpdates_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . KeyCode = = Keys . Right ) // expand all selected rows
{
foreach ( DataGridViewBand row in dataGridViewUpdates . SelectedRows )
{
Alert alert = ( Alert ) dataGridViewUpdates . Rows [ row . Index ] . Tag ;
2013-12-05 13:46:39 +01:00
2013-07-11 20:09:29 +02:00
if ( ! expandedState . ContainsKey ( alert . uuid ) )
2013-12-05 13:46:39 +01:00
ToggleExpandedState ( row . Index ) ;
2013-07-11 20:09:29 +02:00
}
}
else if ( e . KeyCode = = Keys . Left ) // collapse all selected rows
{
foreach ( DataGridViewBand row in dataGridViewUpdates . SelectedRows )
{
Alert alert = ( Alert ) dataGridViewUpdates . Rows [ row . Index ] . Tag ;
2013-12-05 13:46:39 +01:00
2013-07-11 20:09:29 +02:00
if ( expandedState . ContainsKey ( alert . uuid ) )
2013-12-05 13:46:39 +01:00
ToggleExpandedState ( row . Index ) ;
2013-07-11 20:09:29 +02:00
}
}
else if ( e . KeyCode = = Keys . Enter ) // toggle expanded state for all selected rows
{
foreach ( DataGridViewBand row in dataGridViewUpdates . SelectedRows )
2013-12-05 13:46:39 +01:00
ToggleExpandedState ( row . Index ) ;
2013-07-11 20:09:29 +02:00
}
}
/// <summary>
/// Toggles the row specified between the expanded and contracted state
/// </summary>
2013-12-05 13:46:39 +01:00
private void ToggleExpandedState ( int rowIndex )
2013-07-11 20:09:29 +02:00
{
2013-12-05 13:46:39 +01:00
Alert alert = ( Alert ) dataGridViewUpdates . Rows [ rowIndex ] . Tag ;
2013-07-11 20:09:29 +02:00
if ( expandedState . ContainsKey ( alert . uuid ) )
{
expandedState . Remove ( alert . uuid ) ;
2013-12-05 13:46:39 +01:00
dataGridViewUpdates . Rows [ rowIndex ] . Cells [ ColumnMessage . Index ] . Value = alert . Title ;
dataGridViewUpdates . Rows [ rowIndex ] . Cells [ ColumnExpand . Index ] . Value = Properties . Resources . contracted_triangle ;
2013-07-11 20:09:29 +02:00
}
else
{
expandedState . Add ( alert . uuid , true ) ;
2013-12-05 13:46:39 +01:00
dataGridViewUpdates . Rows [ rowIndex ] . Cells [ ColumnMessage . Index ] . Value
= string . Format ( "{0}\n\n{1}" , alert . Title , alert . Description ) ;
dataGridViewUpdates . Rows [ rowIndex ] . Cells [ ColumnExpand . Index ] . Value = Properties . Resources . expanded_triangle ;
}
}
#endregion
#region Top ToolStripButtons event handlers
private void toolStripDropDownButtonDateFilter_FilterChanged ( )
{
Rebuild ( ) ;
}
private void toolStripDropDownButtonServerFilter_FilterChanged ( )
{
Rebuild ( ) ;
}
private void toolStripButtonRefresh_Click ( object sender , EventArgs e )
{
Updates . CheckForUpdates ( true ) ;
}
private void toolStripButtonExportAll_Click ( object sender , EventArgs e )
{
bool exportAll = true ;
if ( FilterIsOn )
{
using ( var dlog = new ThreeButtonDialog (
new ThreeButtonDialog . Details ( null , Messages . UPDATE_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 ;
}
new DelegatedAsyncAction ( null ,
string . Format ( Messages . EXPORT_UPDATES , fileName ) ,
string . Format ( Messages . EXPORTING_UPDATES , fileName ) ,
string . Format ( Messages . EXPORTED_UPDATES , fileName ) ,
delegate
{
using ( StreamWriter stream = new StreamWriter ( fileName , false , UTF8Encoding . UTF8 ) )
{
2017-08-08 14:37:12 +02:00
if ( byUpdateToolStripMenuItem . Checked ) // update view
2013-12-05 13:46:39 +01:00
{
2017-08-08 14:37:12 +02:00
stream . WriteLine ( "{0},{1},{2},{3},{4}" , Messages . TITLE ,
Messages . DESCRIPTION , Messages . APPLIES_TO ,
Messages . TIMESTAMP , Messages . WEB_PAGE ) ;
if ( exportAll )
{
foreach ( Alert a in Updates . UpdateAlerts )
stream . WriteLine ( a . GetUpdateDetailsCSVQuotes ( ) ) ;
}
else
{
foreach ( DataGridViewRow row in dataGridViewUpdates . Rows )
{
var a = row . Tag as Alert ;
if ( a ! = null )
stream . WriteLine ( a . GetUpdateDetailsCSVQuotes ( ) ) ;
}
}
2013-12-05 13:46:39 +01:00
}
2017-08-08 14:37:12 +02:00
else // host view
2013-12-05 13:46:39 +01:00
{
2017-08-08 14:37:12 +02:00
stream . WriteLine ( "{0},{1},{2},{3},{4},{5}" , Messages . POOL ,
2017-09-27 16:14:15 +02:00
Messages . SERVER , Messages . VERSION , Messages . STATUS ,
2017-08-08 14:37:12 +02:00
Messages . REQUIRED_UPDATES , Messages . INSTALLED_UPDATES ) ;
if ( exportAll )
2013-12-05 13:46:39 +01:00
{
2017-08-08 14:37:12 +02:00
List < IXenConnection > xenConnections = ConnectionsManager . XenConnectionsCopy ;
xenConnections . Sort ( ) ;
foreach ( IXenConnection xenConnection in xenConnections )
{
Pool pool = Helpers . GetPool ( xenConnection ) ;
var hasPool = ( pool ! = null ) ;
Host [ ] hosts = xenConnection . Cache . Hosts ;
Array . Sort ( hosts ) ;
foreach ( Host host in hosts )
stream . WriteLine ( GetHostUpdateDetailsCsvQuotes ( xenConnection , host , hasPool ) ) ;
}
}
else
{
foreach ( UpdatePageDataGridViewRow row in dataGridViewHosts . Rows )
{
Host host = row . Tag as Host ;
if ( host ! = null )
stream . WriteLine ( GetHostUpdateDetailsCsvQuotes ( host . Connection , host , row . HasPool ) ) ;
}
2013-12-05 13:46:39 +01:00
}
}
}
} ) . RunAsync ( ) ;
}
2017-08-08 14:37:12 +02:00
private string GetHostUpdateDetailsCsvQuotes ( IXenConnection xenConnection , Host host , bool hasPool )
{
string pool = String . Empty ;
string patchingStatus = String . Empty ;
string requiredUpdates = String . Empty ;
string installedUpdates = String . Empty ;
2018-07-11 14:29:41 +02:00
var versionIsFound = VersionFoundInUpdatesXml ( host ) ;
2017-10-03 16:32:57 +02:00
pool = hasPool ? Helpers . GetPool ( xenConnection ) . Name ( ) : String . Empty ;
2018-12-11 13:52:59 +01:00
requiredUpdates = versionIsFound ? RequiredUpdatesForHost ( host ) : String . Empty ;
2017-10-03 16:32:57 +02:00
installedUpdates = InstalledUpdatesForHost ( host ) ;
2018-12-11 13:52:59 +01:00
patchingStatus = versionIsFound
2017-10-03 16:32:57 +02:00
? ( requiredUpdates . Length > 0 ? Messages . NOT_UPDATED : Messages . UPDATED )
: String . Empty ;
2017-08-08 14:37:12 +02:00
return String . Format ( "\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\"" ,
pool . EscapeQuotes ( ) ,
2017-09-18 18:11:43 +02:00
host . Name ( ) . EscapeQuotes ( ) ,
host . ProductVersionTextShort ( ) . EscapeQuotes ( ) ,
2017-08-08 14:37:12 +02:00
patchingStatus . EscapeQuotes ( ) ,
requiredUpdates . EscapeQuotes ( ) ,
installedUpdates . EscapeQuotes ( ) ) ;
}
2013-12-05 13:46:39 +01:00
#endregion
private void informationLabel_Click ( object sender , EventArgs e )
{
try
{
Process . Start ( InvisibleMessages . UPSELL_SA ) ;
}
catch ( Exception )
{
2016-06-20 11:49:12 +02:00
using ( var dlg = new ThreeButtonDialog (
2013-12-05 13:46:39 +01:00
new ThreeButtonDialog . Details (
SystemIcons . Error ,
string . Format ( Messages . LICENSE_SERVER_COULD_NOT_OPEN_LINK , InvisibleMessages . LICENSE_SERVER_DOWNLOAD_LINK ) ,
2016-06-20 11:49:12 +02:00
Messages . XENCENTER ) ) )
{
dlg . ShowDialog ( this ) ;
}
2013-07-11 20:09:29 +02:00
}
}
2017-05-26 13:54:46 +02:00
private void sortUpdates ( List < Alert > updatesList )
{
if ( dataGridViewUpdates . SortedColumn ! = null )
{
if ( dataGridViewUpdates . SortedColumn . Index = = ColumnMessage . Index )
updatesList . Sort ( Alert . CompareOnTitle ) ;
else if ( dataGridViewUpdates . SortedColumn . Index = = ColumnDate . Index )
updatesList . Sort ( Alert . CompareOnDate ) ;
else if ( dataGridViewUpdates . SortedColumn . Index = = ColumnLocation . Index )
updatesList . Sort ( Alert . CompareOnAppliesTo ) ;
if ( dataGridViewUpdates . SortOrder = = SortOrder . Descending )
updatesList . Reverse ( ) ;
}
else
{
updatesList . Sort ( new NewVersionPriorityAlertComparer ( ) ) ;
}
}
2015-07-29 12:34:39 +02:00
private void checkForUpdatesNowButton_Click ( object sender , EventArgs e )
2015-07-23 14:37:14 +02:00
{
2015-07-29 12:34:39 +02:00
Updates . CheckForUpdates ( true ) ;
}
2015-07-23 14:37:14 +02:00
2015-07-29 12:34:39 +02:00
private void toolStripButtonRestoreDismissed_Click ( object sender , EventArgs e )
{
2015-07-23 14:37:14 +02:00
Updates . RestoreDismissedUpdates ( ) ;
2017-06-11 11:49:25 +02:00
}
2016-11-17 14:35:31 +01:00
2017-06-11 11:49:25 +02:00
private void checkForUpdatesNowLink_Click ( object sender , EventArgs e )
{
2015-07-29 14:43:47 +02:00
Updates . CheckForUpdates ( true ) ;
2015-07-29 12:34:39 +02:00
}
2016-04-05 09:21:14 +02:00
private void tableLayoutPanel3_Resize ( object sender , EventArgs e )
{
labelProgress . MaximumSize = new Size ( tableLayoutPanel3 . Width - 60 , tableLayoutPanel3 . Size . Height ) ;
}
2017-07-26 10:54:51 +02:00
2018-12-11 14:04:58 +01:00
private void byUpdateToolStripMenuItem_CheckedChanged ( object sender , EventArgs e )
2017-07-26 10:54:51 +02:00
{
2018-12-11 14:04:58 +01:00
if ( byUpdateToolStripMenuItem . Checked )
{
byHostToolStripMenuItem . Checked = false ;
ToggleView ( ) ;
}
}
2017-08-08 13:25:18 +02:00
2018-12-11 14:04:58 +01:00
private void byHostToolStripMenuItem_CheckedChanged ( object sender , EventArgs e )
{
if ( byHostToolStripMenuItem . Checked )
{
byUpdateToolStripMenuItem . Checked = false ;
ToggleView ( ) ;
}
2017-07-26 10:54:51 +02:00
}
2018-12-11 14:04:58 +01:00
private void ToggleView ( )
2017-07-26 10:54:51 +02:00
{
2018-12-11 14:04:58 +01:00
//store the view
Properties . Settings . Default . ShowUpdatesByServer = byHostToolStripMenuItem . Checked ;
2017-07-26 10:54:51 +02:00
2017-08-15 15:35:20 +02:00
// buttons
2018-12-11 14:04:58 +01:00
toolStripDropDownButtonDateFilter . Visible = byUpdateToolStripMenuItem . Checked ;
toolStripSplitButtonDismiss . Visible = byUpdateToolStripMenuItem . Checked ;
toolStripButtonRestoreDismissed . Visible = byUpdateToolStripMenuItem . Checked ;
toolStripButtonUpdate . Visible = byHostToolStripMenuItem . Checked ;
2017-08-08 13:25:18 +02:00
// Switch the grid view
2018-12-11 14:04:58 +01:00
dataGridViewUpdates . Visible = byUpdateToolStripMenuItem . Checked ;
dataGridViewHosts . Visible = byHostToolStripMenuItem . Checked ;
// Turn off Date Filter for the updates-by-server view
if ( byHostToolStripMenuItem . Checked )
toolStripDropDownButtonDateFilter . ResetFilterDates ( ) ;
2017-08-08 13:25:18 +02:00
Rebuild ( ) ;
2017-07-26 10:54:51 +02:00
}
2017-08-15 15:35:20 +02:00
private void toolStripButtonUpdate_Click ( object sender , EventArgs e )
{
2018-08-06 13:55:25 +02:00
PatchingWizard wizard = ( PatchingWizard ) Program . MainWindow . ShowForm ( typeof ( PatchingWizard ) ) ;
if ( wizard . IsFirstPage ( ) )
wizard . NextStep ( ) ;
2017-08-15 15:35:20 +02:00
}
2013-06-24 13:41:48 +02:00
}
}