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 ;
2014-01-22 13:39:32 +01:00
using System.Collections.ObjectModel ;
2013-06-24 13:41:48 +02:00
using System.ComponentModel ;
using System.Configuration ;
using System.Diagnostics ;
using System.Drawing ;
using System.IO ;
using System.Runtime.InteropServices ;
using System.Security.Permissions ;
using System.Text ;
using System.Threading ;
using System.Windows.Forms ;
using System.Xml ;
using XenAdmin.Actions.GUIActions ;
2013-08-30 14:35:32 +02:00
using XenAdmin.Controls.MainWindowControls ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Wizards.ImportWizard ;
using XenAPI ;
using XenAdmin.Actions ;
using XenAdmin.Alerts ;
using XenAdmin.Commands ;
using XenAdmin.Controls ;
using XenAdmin.Core ;
using XenAdmin.Dialogs ;
using XenAdmin.Model ;
using XenAdmin.Network ;
using XenAdmin.TabPages ;
using XenAdmin.XenSearch ;
using XenAdmin.Wizards.PatchingWizard ;
using XenAdmin.Plugins ;
using System.Linq ;
namespace XenAdmin
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[ComVisibleAttribute(true)]
2014-01-22 13:39:32 +01:00
public partial class MainWindow : Form , ISynchronizeInvoke , IMainWindow
2013-06-24 13:41:48 +02:00
{
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
/// <summary>
/// A mapping between objects in the tree and the associated selected tab.
/// </summary>
private Dictionary < object , TabPage > selectedTabs = new Dictionary < object , TabPage > ( ) ;
/// <summary>
/// The selected tab for the overview node.
/// </summary>
private TabPage selectedOverviewTab = null ;
internal readonly PerformancePage PerformancePage = new PerformancePage ( ) ;
internal readonly GeneralTabPage GeneralPage = new GeneralTabPage ( ) ;
internal readonly BallooningPage BallooningPage = new BallooningPage ( ) ;
internal readonly BallooningUpsellPage BallooningUpsellPage = new BallooningUpsellPage ( ) ;
internal readonly ConsolePanel ConsolePanel = new ConsolePanel ( ) ;
internal readonly HAPage HAPage = new HAPage ( ) ;
internal readonly HAUpsellPage HAUpsellPage = new HAUpsellPage ( ) ;
internal readonly HomePage HomePage = new HomePage ( ) ;
internal readonly SearchPage SearchPage = new SearchPage ( ) ;
internal readonly NetworkPage NetworkPage = new NetworkPage ( ) ;
internal readonly NICPage NICPage = new NICPage ( ) ;
internal readonly WlbPage WlbPage = new WlbPage ( ) ;
internal readonly WLBUpsellPage WLBUpsellPage = new WLBUpsellPage ( ) ;
internal readonly SrStoragePage SrStoragePage = new SrStoragePage ( ) ;
internal readonly PhysicalStoragePage PhysicalStoragePage = new PhysicalStoragePage ( ) ;
internal readonly VMStoragePage VMStoragePage = new VMStoragePage ( ) ;
internal readonly AdPage AdPage = new AdPage ( ) ;
2013-11-14 12:06:50 +01:00
internal readonly GpuPage GpuPage = new GpuPage ( ) ;
2015-02-06 11:03:42 +01:00
internal readonly DockerProcessPage DockerProcessPage = new DockerProcessPage ( ) ;
2015-02-09 08:42:00 +01:00
internal readonly DockerDetailsPage DockerDetailsPage = new DockerDetailsPage ( ) ;
2013-06-24 13:41:48 +02:00
2013-11-12 13:44:19 +01:00
private ActionBase statusBarAction = null ;
public ActionBase StatusBarAction { get { return statusBarAction ; } }
2013-06-24 13:41:48 +02:00
private bool IgnoreTabChanges = false ;
private bool ToolbarsEnabled ;
private readonly Dictionary < IXenConnection , IList < Form > > activePoolWizards = new Dictionary < IXenConnection , IList < Form > > ( ) ;
private readonly Dictionary < IXenObject , Form > activeXenModelObjectWizards = new Dictionary < IXenObject , Form > ( ) ;
/// <summary>
/// The arguments passed in on the command line.
/// </summary>
private string [ ] CommandLineParam = null ;
private ArgType CommandLineArgType = ArgType . None ;
private static readonly System . Windows . Forms . Timer CheckForUpdatesTimer = new System . Windows . Forms . Timer ( ) ;
private readonly PluginManager pluginManager ;
private readonly ContextMenuBuilder contextMenuBuilder ;
private readonly LicenseManagerLauncher licenseManagerLauncher ;
private readonly LicenseTimer licenseTimer ;
2015-06-08 17:46:16 +02:00
public readonly HealthCheckOverviewLauncher HealthCheckOverviewLauncher ;
2015-08-27 01:30:02 +02:00
private readonly System . Windows . Forms . Timer healthCheckResultTimer = new System . Windows . Forms . Timer ( ) ;
2015-06-08 17:46:16 +02:00
2013-06-24 13:41:48 +02:00
private Dictionary < ToolStripMenuItem , int > pluginMenuItemStartIndexes = new Dictionary < ToolStripMenuItem , int > ( ) ;
2016-01-29 15:38:58 +01:00
private bool expandTreeNodesOnStartup ;
private int connectionsInProgressOnStartup ;
2013-06-24 13:41:48 +02:00
public MainWindow ( ArgType argType , string [ ] args )
{
Program . MainWindow = this ;
licenseManagerLauncher = new LicenseManagerLauncher ( Program . MainWindow ) ;
2015-06-08 17:46:16 +02:00
HealthCheckOverviewLauncher = new HealthCheckOverviewLauncher ( Program . MainWindow ) ;
2013-06-24 13:41:48 +02:00
InvokeHelper . Initialize ( this ) ;
InitializeComponent ( ) ;
SetMenuItemStartIndexes ( ) ;
Icon = Properties . Resources . AppIcon ;
2013-11-23 17:03:21 +01:00
#region Add Tab pages
2013-06-24 13:41:48 +02:00
components . Add ( NICPage ) ;
components . Add ( VMStoragePage ) ;
components . Add ( SrStoragePage ) ;
components . Add ( PerformancePage ) ;
components . Add ( GeneralPage ) ;
components . Add ( BallooningPage ) ;
components . Add ( ConsolePanel ) ;
components . Add ( NetworkPage ) ;
components . Add ( HAPage ) ;
components . Add ( HomePage ) ;
components . Add ( WlbPage ) ;
components . Add ( AdPage ) ;
2013-11-14 12:06:50 +01:00
components . Add ( GpuPage ) ;
2013-10-01 16:35:57 +02:00
components . Add ( SearchPage ) ;
2015-02-06 11:03:42 +01:00
components . Add ( DockerProcessPage ) ;
2015-02-09 08:42:00 +01:00
components . Add ( DockerDetailsPage ) ;
2013-06-24 13:41:48 +02:00
AddTabContents ( VMStoragePage , TabPageStorage ) ;
AddTabContents ( SrStoragePage , TabPageSR ) ;
AddTabContents ( NICPage , TabPageNICs ) ;
AddTabContents ( PerformancePage , TabPagePeformance ) ;
AddTabContents ( GeneralPage , TabPageGeneral ) ;
AddTabContents ( BallooningPage , TabPageBallooning ) ;
AddTabContents ( BallooningUpsellPage , TabPageBallooningUpsell ) ;
AddTabContents ( ConsolePanel , TabPageConsole ) ;
AddTabContents ( NetworkPage , TabPageNetwork ) ;
AddTabContents ( HAPage , TabPageHA ) ;
AddTabContents ( HAUpsellPage , TabPageHAUpsell ) ;
AddTabContents ( HomePage , TabPageHome ) ;
AddTabContents ( WlbPage , TabPageWLB ) ;
AddTabContents ( WLBUpsellPage , TabPageWLBUpsell ) ;
AddTabContents ( PhysicalStoragePage , TabPagePhysicalStorage ) ;
AddTabContents ( AdPage , TabPageAD ) ;
2013-11-14 12:06:50 +01:00
AddTabContents ( GpuPage , TabPageGPU ) ;
2013-10-01 16:35:57 +02:00
AddTabContents ( SearchPage , TabPageSearch ) ;
2015-02-06 11:03:42 +01:00
AddTabContents ( DockerProcessPage , TabPageDockerProcess ) ;
2015-02-09 08:42:00 +01:00
AddTabContents ( DockerDetailsPage , TabPageDockerDetails ) ;
2013-06-24 13:41:48 +02:00
2013-11-23 17:03:21 +01:00
#endregion
2013-06-24 13:41:48 +02:00
TheTabControl . SelectedIndexChanged + = TheTabControl_SelectedIndexChanged ;
2013-11-12 13:44:19 +01:00
navigationPane . DragDropCommandActivated + = navigationPane_DragDropCommandActivated ;
2013-06-24 13:41:48 +02:00
PoolCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( CollectionChanged < Pool > ) ;
MessageCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( MessageCollectionChanged ) ;
HostCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( CollectionChanged < Host > ) ;
VMCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( CollectionChanged < VM > ) ;
SRCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( CollectionChanged < SR > ) ;
FolderCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( CollectionChanged < Folder > ) ;
TaskCollectionChangedWithInvoke = Program . ProgramInvokeHandler ( MeddlingActionManager . TaskCollectionChanged ) ;
ConnectionsManager . History . CollectionChanged + = History_CollectionChanged ;
CommandLineArgType = argType ;
CommandLineParam = args ;
pluginManager = new PluginManager ( ) ;
2013-12-31 11:34:11 +01:00
pluginManager . PluginsChanged + = pluginManager_PluginsChanged ;
2013-06-24 13:41:48 +02:00
pluginManager . LoadPlugins ( ) ;
2014-01-22 13:39:32 +01:00
contextMenuBuilder = new ContextMenuBuilder ( pluginManager , this ) ;
2013-06-24 13:41:48 +02:00
2013-11-18 15:31:00 +01:00
eventsPage . GoToXenObjectRequested + = eventsPage_GoToXenObjectRequested ;
2013-06-24 13:41:48 +02:00
SearchPage . SearchChanged + = SearchPanel_SearchChanged ;
2013-11-21 12:57:57 +01:00
Alert . RegisterAlertCollectionChanged ( XenCenterAlerts_CollectionChanged ) ;
2013-12-05 13:46:39 +01:00
Updates . RegisterCollectionChanged ( Updates_CollectionChanged ) ;
2013-06-24 13:41:48 +02:00
FormFontFixer . Fix ( this ) ;
Folders . InitFolders ( ) ;
2015-02-04 10:48:32 +01:00
DockerContainers . InitDockerContainers ( ) ;
2013-06-24 13:41:48 +02:00
OtherConfigAndTagsWatcher . InitEventHandlers ( ) ;
// Fix colour of text on gradient panels
TitleLabel . ForeColor = Program . TitleBarForeColor ;
loggedInLabel1 . SetTextColor ( Program . TitleBarForeColor ) ;
2013-11-12 13:44:19 +01:00
statusProgressBar . Visible = false ;
2014-01-22 13:39:32 +01:00
SelectionManager . BindTo ( MainMenuBar . Items , this ) ;
SelectionManager . BindTo ( ToolStrip . Items , this ) ;
2013-08-22 18:25:12 +02:00
Properties . Settings . Default . SettingChanging + = Default_SettingChanging ;
2013-06-24 13:41:48 +02:00
licenseTimer = new LicenseTimer ( licenseManagerLauncher ) ;
GeneralPage . LicenseLauncher = licenseManagerLauncher ;
2016-01-22 10:01:36 +01:00
2016-01-28 22:43:15 +01:00
toolStripSeparator7 . Visible = xenSourceOnTheWebToolStripMenuItem . Visible = xenCenterPluginsOnlineToolStripMenuItem . Visible = ! HiddenFeatures . ToolStripMenuItemHidden ;
healthCheckToolStripMenuItem1 . Visible = ! HiddenFeatures . HealthCheckHidden ;
2013-06-24 13:41:48 +02:00
}
2013-08-22 18:25:12 +02:00
private void Default_SettingChanging ( object sender , SettingChangingEventArgs e )
2013-06-24 13:41:48 +02:00
{
if ( e = = null )
return ;
if ( e . SettingName = = "AutoSwitchToRDP" | | e . SettingName = = "EnableRDPPolling" )
{
ConsolePanel . ResetAllViews ( ) ;
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsRealVM )
ConsolePanel . setCurrentSource ( ( VM ) SelectionManager . Selection . First ) ;
else if ( SelectionManager . Selection . FirstIsHost )
ConsolePanel . setCurrentSource ( ( Host ) SelectionManager . Selection . First ) ;
2013-06-24 13:41:48 +02:00
UnpauseVNC ( sender = = TheTabControl ) ;
}
}
private void SetMenuItemStartIndexes ( )
{
foreach ( ToolStripMenuItem menu in MainMenuBar . Items )
{
foreach ( ToolStripItem item in menu . DropDownItems )
{
if ( item ! = null & & item . Text = = "PluginItemsPlaceHolder" )
{
pluginMenuItemStartIndexes . Add ( menu , menu . DropDownItems . IndexOf ( item ) ) ;
menu . DropDownItems . Remove ( item ) ;
break ;
}
}
}
}
internal SelectionBroadcaster SelectionManager
{
get
{
2013-08-26 12:42:32 +02:00
return navigationPane . SelectionManager ;
2013-06-24 13:41:48 +02:00
}
}
internal ContextMenuBuilder ContextMenuBuilder
{
get
{
return contextMenuBuilder ;
}
}
protected override void OnLoad ( EventArgs e )
{
Program . AssertOnEventThread ( ) ;
History . EnableHistoryButtons ( ) ;
History . NewHistoryItem ( new XenModelObjectHistoryItem ( null , TabPageHome ) ) ;
/ *
* Resume window size and location
* /
try
{
// Bring in previous version user setting for the first time.
if ( Properties . Settings . Default . DoUpgrade )
{
Properties . Settings . Default . Upgrade ( ) ;
Properties . Settings . Default . DoUpgrade = false ;
XenAdmin . Settings . TrySaveSettings ( ) ;
}
Point savedLocation = Properties . Settings . Default . WindowLocation ;
Size savedSize = Properties . Settings . Default . WindowSize ;
if ( HelpersGUI . WindowIsOnScreen ( savedLocation , savedSize ) )
{
this . Location = savedLocation ;
this . Size = savedSize ;
}
}
catch
{
}
// Using the Load event ensures that the handle has been
// created:
base . OnLoad ( e ) ;
NewTabs [ 0 ] = TabPageHome ;
NewTabCount = 1 ;
ChangeToNewTabs ( ) ;
2013-08-24 18:00:32 +02:00
}
2013-06-24 13:41:48 +02:00
2013-08-24 18:00:32 +02:00
protected override void OnShown ( EventArgs e )
{
base . OnShown ( e ) ;
2013-11-05 15:40:16 +01:00
TheTabControl . Visible = true ;
alertPage . Visible = updatesPage . Visible = eventsPage . Visible = false ;
2013-08-26 12:42:32 +02:00
navigationPane . FocusTreeView ( ) ;
2013-06-24 13:41:48 +02:00
}
protected override void OnHandleCreated ( EventArgs e )
{
base . OnHandleCreated ( e ) ;
Clip . RegisterClipboardViewer ( ) ;
}
protected override void WndProc ( ref System . Windows . Forms . Message e )
{
//System.Console.WriteLine(Win32.GetWindowsMessageName(e.Msg));
switch ( e . Msg )
{
case Win32 . WM_CHANGECBCHAIN : // Clipboard chain has changed.
Clip . ProcessWMChangeCBChain ( e ) ;
break ;
case Win32 . WM_DRAWCLIPBOARD : // Content of clipboard has changed.
Clip . ProcessWMDrawClipboard ( e ) ;
break ;
case Win32 . WM_DESTROY :
Clip . UnregisterClipboardViewer ( ) ;
base . WndProc ( ref e ) ;
break ;
default :
base . WndProc ( ref e ) ;
break ;
}
}
private void AddTabContents ( Control contents , TabPage TabPage )
{
contents . Location = new Point ( 0 , 0 ) ;
contents . Size = TabPage . Size ;
contents . Anchor = AnchorStyles . Left | AnchorStyles . Bottom | AnchorStyles . Top | AnchorStyles . Right ;
TabPage . Controls . Add ( contents ) ;
}
void History_CollectionChanged ( object sender , CollectionChangeEventArgs e )
{
if ( Program . Exiting )
return ;
Program . BeginInvoke ( Program . MainWindow , ( ) = >
2013-11-19 16:42:47 +01:00
{
ActionBase action = ( ActionBase ) e . Element ;
if ( action = = null )
return ;
switch ( e . Action )
{
case CollectionChangeAction . Add :
{
var meddlingAction = action as MeddlingAction ;
if ( meddlingAction = = null )
{
SetStatusBar ( null , null ) ;
if ( statusBarAction ! = null )
{
statusBarAction . Changed - = actionChanged ;
statusBarAction . Completed - = actionChanged ;
}
statusBarAction = action ;
}
action . Changed + = actionChanged ;
action . Completed + = actionChanged ;
actionChanged ( action ) ;
break ;
}
case CollectionChangeAction . Remove :
{
action . Changed - = actionChanged ;
action . Completed - = actionChanged ;
int errors = ConnectionsManager . History . Count ( a = > a . IsCompleted & & ! a . Succeeded ) ;
navigationPane . UpdateNotificationsButton ( NotificationsSubMode . Events , errors ) ;
if ( eventsPage . Visible )
{
TitleLabel . Text = NotificationsSubModeItem . GetText ( NotificationsSubMode . Events , errors ) ;
TitleIcon . Image = NotificationsSubModeItem . GetImage ( NotificationsSubMode . Events , errors ) ;
}
break ;
}
}
} ) ;
2013-06-24 13:41:48 +02:00
}
2013-08-05 15:28:21 +02:00
void actionChanged ( ActionBase action )
2013-06-24 13:41:48 +02:00
{
if ( Program . Exiting )
return ;
2013-08-05 15:28:21 +02:00
Program . Invoke ( this , ( ) = > actionChanged_ ( action ) ) ;
2013-06-24 13:41:48 +02:00
}
void actionChanged_ ( ActionBase action )
{
2013-11-12 13:44:19 +01:00
var meddlingAction = action as MeddlingAction ;
if ( meddlingAction = = null )
statusProgressBar . Visible = action . ShowProgress & & ! action . IsCompleted ;
2013-06-24 13:41:48 +02:00
// Be defensive against CA-8517.
if ( action . PercentComplete < 0 | | action . PercentComplete > 100 )
{
log . ErrorFormat ( "PercentComplete is erroneously {0}" , action . PercentComplete ) ;
}
2013-11-12 13:44:19 +01:00
else if ( meddlingAction = = null )
{
statusProgressBar . Value = action . PercentComplete ;
}
2013-06-24 13:41:48 +02:00
// Don't show cancelled exception
if ( action . Exception ! = null & & ! ( action . Exception is CancelledException ) )
{
2013-11-12 13:44:19 +01:00
if ( meddlingAction = = null )
2014-04-28 16:01:11 +02:00
SetStatusBar ( Properties . Resources . _000_error_h32bit_16 , action . Exception . Message ) ;
2013-06-24 13:41:48 +02:00
}
2013-11-12 13:44:19 +01:00
else if ( meddlingAction = = null )
{
2014-04-28 16:01:11 +02:00
SetStatusBar ( null , action . IsCompleted
? null
: ! string . IsNullOrEmpty ( action . Description )
? action . Description
: ! string . IsNullOrEmpty ( action . Title )
? action . Title
: null ) ;
2013-11-12 13:44:19 +01:00
}
2013-11-19 16:42:47 +01:00
2015-12-03 19:41:25 +01:00
int errors = ConnectionsManager . History . Count ( a = > a . IsCompleted & & ! a . Succeeded & & ! ( ( a is CancellingAction ) & & ( ( CancellingAction ) a ) . Cancelled ) ) ;
2013-11-19 16:42:47 +01:00
navigationPane . UpdateNotificationsButton ( NotificationsSubMode . Events , errors ) ;
if ( eventsPage . Visible )
{
TitleLabel . Text = NotificationsSubModeItem . GetText ( NotificationsSubMode . Events , errors ) ;
TitleIcon . Image = NotificationsSubModeItem . GetImage ( NotificationsSubMode . Events , errors ) ;
}
2013-11-12 13:44:19 +01:00
}
public void SetStatusBar ( Image image , string message )
{
if ( ( statusLabel . Text ! = null & & statusLabel . Text . Equals ( message ) )
| | ( statusLabel . Image ! = null & & statusLabel . Equals ( image ) ) )
return ;
statusLabel . Image = image ;
statusLabel . Text = Helpers . FirstLine ( message ) ;
}
public void SetProgressBar ( bool visible , int progress )
{
statusProgressBar . Visible = visible ;
statusProgressBar . Value = progress ;
2013-06-24 13:41:48 +02:00
}
private void MainWindow_Shown ( object sender , EventArgs e )
{
MainMenuBar . Location = new Point ( 0 , 0 ) ;
if ( ToolStrip . Renderer is ToolStripProfessionalRenderer )
{
( ( ToolStripProfessionalRenderer ) ToolStrip . Renderer ) . RoundedEdges = false ;
}
ConnectionsManager . XenConnections . CollectionChanged + = XenConnection_CollectionChanged ;
try
{
Settings . RestoreSession ( ) ;
2015-08-24 13:51:46 +02:00
new TransferProxySettingsAction ( ( HTTPHelper . ProxyStyle ) Properties . Settings . Default . ProxySetting ,
Properties . Settings . Default . ProxyAddress ,
Properties . Settings . Default . ProxyPort ,
Properties . Settings . Default . ConnectionTimeout ,
Properties . Settings . Default . BypassProxyForLocal ,
true ) . RunAsync ( ) ;
2013-06-24 13:41:48 +02:00
}
catch ( ConfigurationErrorsException ex )
{
log . Error ( "Could not load settings." , ex ) ;
Program . CloseSplash ( ) ;
new ThreeButtonDialog (
new ThreeButtonDialog . Details (
SystemIcons . Error ,
string . Format ( Messages . MESSAGEBOX_LOAD_CORRUPTED , Settings . GetUserConfigPath ( ) ) ,
Messages . MESSAGEBOX_LOAD_CORRUPTED_TITLE ) ) . ShowDialog ( this ) ;
Application . Exit ( ) ;
return ; // Application.Exit() does not exit the current method.
}
ToolbarsEnabled = Properties . Settings . Default . ToolbarsEnabled ;
RequestRefreshTreeView ( ) ;
UpdateToolbars ( ) ;
2016-01-29 15:38:58 +01:00
// if there are fewer than 30 connections, then expand the tree nodes.
expandTreeNodesOnStartup = ConnectionsManager . XenConnectionsCopy . Count < 30 ;
connectionsInProgressOnStartup = 0 ;
2013-06-24 13:41:48 +02:00
// kick-off connections for all the loaded server list
foreach ( IXenConnection connection in ConnectionsManager . XenConnectionsCopy )
{
if ( ! connection . SaveDisconnected )
{
2016-01-29 15:38:58 +01:00
connectionsInProgressOnStartup + + ;
connection . ConnectionStateChanged + = Connection_ConnectionStateChangedOnStartup ;
connection . CachePopulated + = connection_CachePopulatedOnStartup ;
2013-06-24 13:41:48 +02:00
XenConnectionUI . BeginConnect ( connection , true , this , true ) ;
}
}
RequestRefreshTreeView ( ) ;
ThreadPool . QueueUserWorkItem ( ( WaitCallback ) delegate ( object o )
{
// Sleep a short time before closing the splash
Thread . Sleep ( 500 ) ;
Program . Invoke ( Program . MainWindow , Program . CloseSplash ) ;
} ) ;
if ( ! Program . RunInAutomatedTestMode & & ! Helpers . CommonCriteriaCertificationRelease )
{
if ( ! Properties . Settings . Default . SeenAllowUpdatesDialog )
new AllowUpdatesDialog ( pluginManager ) . ShowDialog ( this ) ;
// start checkforupdates thread
CheckForUpdatesTimer . Interval = 1000 * 60 * 60 * 24 ; // 24 hours
2013-11-21 15:11:29 +01:00
CheckForUpdatesTimer . Tick + = CheckForUpdatesTimer_Tick ;
2013-06-24 13:41:48 +02:00
CheckForUpdatesTimer . Start ( ) ;
2013-12-05 13:46:39 +01:00
Updates . CheckForUpdates ( false ) ;
2013-06-24 13:41:48 +02:00
}
2015-08-27 01:30:02 +02:00
if ( ! Program . RunInAutomatedTestMode )
{
// start healthCheckResult thread
healthCheckResultTimer . Interval = 1000 * 60 * 60 ; // 1 hour
healthCheckResultTimer . Tick + = HealthCheckResultTimer_Tick ;
healthCheckResultTimer . Start ( ) ;
}
2013-06-24 13:41:48 +02:00
ProcessCommand ( CommandLineArgType , CommandLineParam ) ;
}
2013-11-21 15:11:29 +01:00
private void CheckForUpdatesTimer_Tick ( object sender , EventArgs e )
{
2013-12-05 13:46:39 +01:00
Updates . CheckForUpdates ( false ) ;
2013-11-21 15:11:29 +01:00
}
2015-08-27 01:30:02 +02:00
private void HealthCheckResultTimer_Tick ( object sender , EventArgs e )
{
HealthCheck . CheckForAnalysisResults ( ) ;
}
2013-06-24 13:41:48 +02:00
private void LoadTasksAsMeddlingActions ( IXenConnection connection )
{
if ( ! connection . IsConnected | | connection . Session = = null )
return ;
Dictionary < XenRef < Task > , Task > tasks = Task . get_all_records ( connection . Session ) ;
foreach ( KeyValuePair < XenRef < Task > , Task > pair in tasks )
{
pair . Value . Connection = connection ;
pair . Value . opaque_ref = pair . Key ;
MeddlingActionManager . ForceAddTask ( pair . Value ) ;
}
}
private void Cache_Changed ( object sender , EventArgs e )
{
RequestRefreshTreeView ( ) ;
}
private void connection_CachePopulatedOnStartup ( object sender , EventArgs e )
{
IXenConnection c = ( IXenConnection ) sender ;
c . CachePopulated - = connection_CachePopulatedOnStartup ;
2016-01-29 15:38:58 +01:00
if ( expandTreeNodesOnStartup )
TrySelectNewNode ( c , false , true , false ) ;
Program . Invoke ( this , ShowAboutDialogOnStartup ) ;
}
private void Connection_ConnectionStateChangedOnStartup ( object sender , EventArgs e )
{
IXenConnection c = ( IXenConnection ) sender ;
2016-02-04 10:54:42 +01:00
c . ConnectionStateChanged - = Connection_ConnectionStateChangedOnStartup ;
2016-01-29 15:38:58 +01:00
Program . Invoke ( Program . MainWindow , delegate
{
connectionsInProgressOnStartup - - ;
// show the About dialog if this was the last connection in progress and the connection failed
if ( ! c . IsConnected )
ShowAboutDialogOnStartup ( ) ;
} ) ;
}
/// <summary>
/// Show the About dialog after all conncections kicked-off on startup have finished the connection phase (cache populated)
/// Must be called on the event thread.
/// </summary>
private void ShowAboutDialogOnStartup ( )
{
Program . AssertOnEventThread ( ) ;
if ( connectionsInProgressOnStartup > 0 )
return ;
if ( Properties . Settings . Default . ShowAboutDialog & & ! HiddenFeatures . LicenseNagHidden )
ShowForm ( typeof ( AboutDialog ) ) ;
2013-06-24 13:41:48 +02:00
}
private bool Launched = false ;
internal void ProcessCommand ( ArgType argType , string [ ] args )
{
switch ( argType )
{
case ArgType . Import :
log . DebugFormat ( "Importing VM export from {0}" , args [ 0 ] ) ;
OpenGlobalImportWizard ( args [ 0 ] ) ;
break ;
case ArgType . License :
log . DebugFormat ( "Installing license from {0}" , args [ 0 ] ) ;
LaunchLicensePicker ( args [ 0 ] ) ;
break ;
case ArgType . Restore :
log . DebugFormat ( "Restoring host backup from {0}" , args [ 0 ] ) ;
2014-01-22 13:39:32 +01:00
new RestoreHostFromBackupCommand ( this , null , args [ 0 ] ) . Execute ( ) ;
2013-06-24 13:41:48 +02:00
break ;
case ArgType . Update :
log . DebugFormat ( "Installing server update from {0}" , args [ 0 ] ) ;
InstallUpdate ( args [ 0 ] ) ;
break ;
case ArgType . XenSearch :
log . DebugFormat ( "Importing saved XenSearch from '{0}'" , args [ 0 ] ) ;
2014-01-22 13:39:32 +01:00
new ImportSearchCommand ( this , args [ 0 ] ) . Execute ( ) ;
2013-06-24 13:41:48 +02:00
break ;
case ArgType . Connect :
log . DebugFormat ( "Connecting to server '{0}'" , args [ 0 ] ) ;
IXenConnection connection = new XenConnection ( ) ;
connection . Hostname = args [ 0 ] ;
connection . Port = ConnectionsManager . DEFAULT_XEN_PORT ;
connection . Username = args [ 1 ] ;
connection . Password = args [ 2 ] ;
if ( ConnectionsManager . XenConnectionsContains ( connection ) )
break ;
lock ( ConnectionsManager . ConnectionsLock )
ConnectionsManager . XenConnections . Add ( connection ) ;
XenConnectionUI . BeginConnect ( connection , true , null , false ) ;
break ;
case ArgType . None :
if ( Launched )
{
// The user has launched the splash screen, but we're already running.
// Draw his attention.
2014-01-22 13:39:32 +01:00
HelpersGUI . BringFormToFront ( this ) ;
2013-06-24 13:41:48 +02:00
Activate ( ) ;
}
break ;
case ArgType . Passwords :
System . Diagnostics . Trace . Assert ( false ) ;
break ;
}
Launched = true ;
}
// Manages UI and network updates whenever hosts are added and removed
void XenConnection_CollectionChanged ( object sender , CollectionChangeEventArgs e )
{
if ( Program . Exiting )
return ;
//Program.AssertOnEventThread();
Program . BeginInvoke ( Program . MainWindow , ( ) = > XenConnectionCollectionChanged ( e ) ) ;
}
private readonly CollectionChangeEventHandler PoolCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler MessageCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler HostCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler VMCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler SRCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler FolderCollectionChangedWithInvoke = null ;
private readonly CollectionChangeEventHandler TaskCollectionChangedWithInvoke = null ;
private void XenConnectionCollectionChanged ( CollectionChangeEventArgs e )
{
try
{
IXenConnection connection = ( IXenConnection ) e . Element ;
if ( connection = = null )
return ;
2013-08-26 12:42:32 +02:00
navigationPane . XenConnectionCollectionChanged ( e ) ;
2013-08-25 13:42:38 +02:00
2013-06-24 13:41:48 +02:00
if ( e . Action = = CollectionChangeAction . Add )
{
connection . ClearingCache + = connection_ClearingCache ;
connection . ConnectionResult + = Connection_ConnectionResult ;
connection . ConnectionLost + = Connection_ConnectionLost ;
connection . ConnectionClosed + = Connection_ConnectionClosed ;
connection . ConnectionReconnecting + = connection_ConnectionReconnecting ;
connection . XenObjectsUpdated + = Connection_XenObjectsUpdated ;
connection . Cache . RegisterCollectionChanged < XenAPI . Message > ( MessageCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < Pool > ( PoolCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < Host > ( HostCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < VM > ( VMCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < SR > ( SRCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < Folder > ( FolderCollectionChangedWithInvoke ) ;
connection . Cache . RegisterCollectionChanged < Task > ( TaskCollectionChangedWithInvoke ) ;
connection . CachePopulated + = connection_CachePopulated ;
}
else if ( e . Action = = CollectionChangeAction . Remove )
{
connection . ClearingCache - = connection_ClearingCache ;
connection . ConnectionResult - = Connection_ConnectionResult ;
connection . ConnectionLost - = Connection_ConnectionLost ;
connection . ConnectionClosed - = Connection_ConnectionClosed ;
connection . ConnectionReconnecting - = connection_ConnectionReconnecting ;
connection . XenObjectsUpdated - = Connection_XenObjectsUpdated ;
connection . Cache . DeregisterCollectionChanged < XenAPI . Message > ( MessageCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < Pool > ( PoolCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < Host > ( HostCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < VM > ( VMCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < SR > ( SRCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < Folder > ( FolderCollectionChangedWithInvoke ) ;
connection . Cache . DeregisterCollectionChanged < Task > ( TaskCollectionChangedWithInvoke ) ;
connection . CachePopulated - = connection_CachePopulated ;
foreach ( VM vm in connection . Cache . VMs )
{
this . ConsolePanel . closeVNCForSource ( vm ) ;
}
foreach ( Host host in connection . Cache . Hosts )
foreach ( VM vm in host . Connection . ResolveAll ( host . resident_VMs ) )
if ( vm . is_control_domain )
this . ConsolePanel . closeVNCForSource ( vm ) ;
connection . EndConnect ( ) ;
RequestRefreshTreeView ( ) ;
//CA-41228 refresh submenu items when there are no connections
2013-08-22 18:25:12 +02:00
SelectionManager . RefreshSelection ( ) ;
2013-06-24 13:41:48 +02:00
}
}
catch ( Exception exn )
{
log . Error ( exn , exn ) ;
// Can't do any more about this.
}
}
/// <summary>
/// Closes any wizards for this connection. Must be done before we clear the cache so that per-VM wizards are closed.
/// In many cases this is already covered (e.g. if the user explicitly disconnects). This method ensures we also
/// do it when we unexpectedly lose the connection.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void connection_ClearingCache ( object sender , EventArgs e )
{
IXenConnection connection = ( IXenConnection ) sender ;
2014-01-22 13:39:32 +01:00
CloseActiveWizards ( connection ) ;
2013-11-21 12:57:57 +01:00
Alert . RemoveAlert ( alert = > alert . Connection ! = null & & alert . Connection . Equals ( connection ) ) ;
2014-01-08 14:17:02 +01:00
Updates . CheckServerPatches ( ) ;
Updates . CheckServerVersion ( ) ;
2014-10-08 18:16:45 +02:00
RequestRefreshTreeView ( ) ;
2013-06-24 13:41:48 +02:00
}
void connection_CachePopulated ( object sender , EventArgs e )
{
IXenConnection connection = sender as IXenConnection ;
if ( connection = = null )
return ;
Host master = Helpers . GetMaster ( connection ) ;
if ( master = = null )
return ;
2015-11-18 17:52:43 +01:00
log . InfoFormat ( "Connected to {0} (version {1}, build {2}.{3}) with {4} {5} (build {6}.{7})" ,
2013-06-24 13:41:48 +02:00
Helpers . GetName ( master ) , Helpers . HostProductVersionText ( master ) , Helpers . HostProductVersion ( master ) ,
2015-11-18 17:52:43 +01:00
Helpers . HostBuildNumber ( master ) , Messages . XENCENTER , Branding . PRODUCT_VERSION_TEXT ,
2014-02-18 18:38:11 +01:00
Branding . XENCENTER_VERSION , Program . Version . Revision ) ;
2013-06-24 13:41:48 +02:00
2015-11-18 17:52:43 +01:00
// Check the PRODUCT_BRAND
2015-11-23 12:26:05 +01:00
if ( ! Program . RunInAutomatedTestMode & & ! SameProductBrand ( master ) )
2015-11-18 17:52:43 +01:00
{
connection . EndConnect ( ) ;
Program . Invoke ( Program . MainWindow , delegate ( )
{
string msg = string . Format ( Messages . INCOMPATIBLE_PRODUCTS , Helpers . GetName ( master ) ) ;
string url = "" ;
using ( var dlog = new ConnectionRefusedDialog ( ) )
{
dlog . ErrorMessage = msg ;
dlog . Url = "" ;
dlog . ShowDialog ( this ) ;
}
new ActionBase ( Messages . CONNECTION_REFUSED_TITLE ,
string . Format ( "{0}\n{1}" , msg , url ) , false ,
true , Messages . CONNECTION_REFUSED ) ;
} ) ;
return ;
}
2013-06-24 13:41:48 +02:00
// When releasing a new version of the server, we should set xencenter_min and xencenter_max on the server
// as follows:
//
// xencenter_min should be the lowest version of XenCenter we want the new server to work with. In the
// (common) case that we want to force the user to upgrade XenCenter when they upgrade the server,
// xencenter_min should equal the current version of XenCenter. // if (server_min > current_version)
//
// xencenter_max should always equal the current version of XenCenter. This ensures that even if they are
// not required to upgrade, we at least warn them. // else if (server_max > current_version)
int server_min = master . XenCenterMin ;
int server_max = master . XenCenterMax ;
if ( server_min > 0 & & server_max > 0 )
{
int current_version = ( int ) API_Version . LATEST ;
if ( server_min > current_version )
{
connection . EndConnect ( ) ;
2013-09-26 15:12:26 +02:00
2013-06-24 13:41:48 +02:00
Program . Invoke ( Program . MainWindow , delegate ( )
{
2013-09-26 15:12:26 +02:00
string msg = string . Format ( Messages . GUI_OUT_OF_DATE , Helpers . GetName ( master ) ) ;
2016-01-28 22:43:15 +01:00
if ( ! HiddenFeatures . LinkLabelHidden )
2016-01-21 09:54:22 +01:00
msg = msg + Messages . GUI_OUT_OF_DATE_MORE ;
2013-06-24 13:41:48 +02:00
string url = "https://" + connection . Hostname ;
2013-09-26 15:12:26 +02:00
using ( var dlog = new ConnectionRefusedDialog ( ) )
{
dlog . ErrorMessage = msg ;
dlog . Url = url ;
dlog . ShowDialog ( this ) ;
}
2016-01-21 09:54:22 +01:00
2013-09-26 15:12:26 +02:00
new ActionBase ( Messages . CONNECTION_REFUSED_TITLE ,
string . Format ( "{0}\n{1}" , msg , url ) , false ,
true , Messages . CONNECTION_REFUSED ) ;
2013-06-24 13:41:48 +02:00
} ) ;
return ;
}
else if ( server_max > current_version )
{
Alert . AddAlert ( new GuiOldAlert ( ) ) ;
}
LoadTasksAsMeddlingActions ( connection ) ;
}
//
// Every time we connect, make sure any host with other_config[maintenance_mode] == true
// is disabled.
//
CheckMaintenanceMode ( connection ) ;
if ( HelpersGUI . iSCSIisUsed ( ) )
HelpersGUI . PerformIQNCheck ( ) ;
if ( licenseTimer ! = null )
2013-10-15 18:15:21 +02:00
licenseTimer . CheckActiveServerLicense ( connection , false ) ;
2013-11-21 16:56:24 +01:00
2015-07-24 15:12:46 +02:00
if ( Properties . Settings . Default . ShowHealthCheckEnrollmentReminder )
ThreadPool . QueueUserWorkItem ( CheckHealthCheckEnrollment , connection ) ;
2015-08-27 01:30:02 +02:00
ThreadPool . QueueUserWorkItem ( HealthCheck . CheckForAnalysisResults , connection ) ;
2015-07-01 04:35:59 +02:00
ThreadPool . QueueUserWorkItem ( InformHealthCheckEnrollment , connection ) ;
2015-08-27 01:30:02 +02:00
2013-12-05 13:46:39 +01:00
Updates . CheckServerPatches ( ) ;
Updates . CheckServerVersion ( ) ;
2013-06-24 13:41:48 +02:00
RequestRefreshTreeView ( ) ;
}
2015-06-08 17:46:16 +02:00
private void CheckHealthCheckEnrollment ( object connection )
{
2016-01-28 22:43:15 +01:00
if ( HealthCheckOverviewLauncher ! = null & & ! HiddenFeatures . HealthCheckHidden )
2015-06-08 17:46:16 +02:00
HealthCheckOverviewLauncher . CheckHealthCheckEnrollment ( ( IXenConnection ) connection ) ;
}
2015-07-01 04:35:59 +02:00
private void InformHealthCheckEnrollment ( object connection )
{
Pool pool = Helpers . GetPoolOfOne ( ( IXenConnection ) connection ) ;
if ( pool = = null )
return ;
2015-07-29 09:44:41 +02:00
var newHealthCheckSSettings = pool . HealthCheckSettings ;
new TransferHealthCheckSettingsAction ( pool , newHealthCheckSSettings ,
newHealthCheckSSettings . GetSecretyInfo ( pool . Connection , HealthCheckSettings . UPLOAD_CREDENTIAL_USER_SECRET ) ,
newHealthCheckSSettings . GetSecretyInfo ( pool . Connection , HealthCheckSettings . UPLOAD_CREDENTIAL_PASSWORD_SECRET ) , true ) . RunAsync ( ) ;
2015-07-01 04:35:59 +02:00
}
2015-11-18 17:52:43 +01:00
public static bool SameProductBrand ( Host host )
{
2016-02-10 12:52:30 +01:00
return host . ProductBrand = = Branding . PRODUCT_BRAND | | Branding . PRODUCT_BRAND = = "[XenServer product]" ;
2015-11-18 17:52:43 +01:00
}
2013-06-24 13:41:48 +02:00
/// <summary>
/// Ensures all hosts on the connection are disabled if they are in maintenance mode.
/// </summary>
/// <param name="connection"></param>
private void CheckMaintenanceMode ( IXenConnection connection )
{
foreach ( Host host in connection . Cache . Hosts )
{
CheckMaintenanceMode ( host ) ;
}
}
/// <summary>
/// Ensures the host is disabled if it is in maintenance mode by spawning a new HostAction if necessary.
/// </summary>
/// <param name="host"></param>
private void CheckMaintenanceMode ( Host host )
{
if ( host . IsLive & & host . MaintenanceMode & & host . enabled )
{
2014-01-22 13:39:32 +01:00
Program . MainWindow . CloseActiveWizards ( host ) ;
2013-06-24 13:41:48 +02:00
var action = new DisableHostAction ( host ) ;
action . Completed + = action_Completed ;
action . RunAsync ( ) ;
Program . Invoke ( this , UpdateToolbars ) ;
}
}
void MessageCollectionChanged ( object sender , CollectionChangeEventArgs e )
{
Program . AssertOnEventThread ( ) ;
XenAPI . Message m = ( XenAPI . Message ) e . Element ;
if ( e . Action = = CollectionChangeAction . Add )
{
if ( ! m . ShowOnGraphs & & ! m . IsSquelched )
Alert . AddAlert ( MessageAlert . ParseMessage ( m ) ) ;
}
else if ( e . Action = = CollectionChangeAction . Remove )
{
if ( ! m . ShowOnGraphs )
MessageAlert . RemoveAlert ( m ) ;
}
}
void CollectionChanged < T > ( object sender , CollectionChangeEventArgs e ) where T : XenObject < T >
{
Program . AssertOnEventThread ( ) ;
T o = ( T ) e . Element ;
if ( e . Action = = CollectionChangeAction . Add )
{
if ( o is Pool )
( ( Pool ) e . Element ) . PropertyChanged + = Pool_PropertyChanged ;
else if ( o is Host )
( ( Host ) e . Element ) . PropertyChanged + = Host_PropertyChanged ;
else if ( o is VM )
( ( VM ) e . Element ) . PropertyChanged + = VM_PropertyChanged ;
else
o . PropertyChanged + = o_PropertyChanged ;
}
else if ( e . Action = = CollectionChangeAction . Remove )
{
if ( o is Pool )
( ( Pool ) e . Element ) . PropertyChanged - = Pool_PropertyChanged ;
else if ( o is Host )
( ( Host ) e . Element ) . PropertyChanged - = Host_PropertyChanged ;
else if ( o is VM )
( ( VM ) e . Element ) . PropertyChanged - = VM_PropertyChanged ;
else
o . PropertyChanged - = o_PropertyChanged ;
if ( o is VM )
{
VM vm = ( VM ) e . Element ;
ConsolePanel . closeVNCForSource ( vm ) ;
2014-01-22 13:39:32 +01:00
CloseActiveWizards ( vm ) ;
2013-06-24 13:41:48 +02:00
}
selectedTabs . Remove ( o ) ;
2014-01-22 13:39:32 +01:00
pluginManager . DisposeURLs ( o ) ;
2013-06-24 13:41:48 +02:00
}
}
private void Pool_PropertyChanged ( object obj , PropertyChangedEventArgs e )
{
Pool pool = ( Pool ) obj ;
switch ( e . PropertyName )
{
case "other_config" :
// other_config may contain HideFromXenCenter
UpdateToolbars ( ) ;
2013-12-05 13:46:39 +01:00
// other_config contains which patches to ignore
Updates . CheckServerPatches ( ) ;
Updates . CheckServerVersion ( ) ;
2013-06-24 13:41:48 +02:00
break ;
case "name_label" :
pool . Connection . FriendlyName = Helpers . GetName ( pool ) ;
break ;
}
}
private void Host_PropertyChanged ( object obj , PropertyChangedEventArgs e )
{
Host host = ( Host ) obj ;
switch ( e . PropertyName )
{
case "allowed_operations" :
case "enabled" :
// We want to ensure that a host is disabled if it is in maintenance mode, by starting a new DisableHostAction if necessary (CheckMaintenanceMode)
if ( host . enabled & & host . MaintenanceMode )
{
// This is an invalid state: the host is enabled but still "in maintenance mode";
// But maybe MaintenanceMode hasn't been updated yet, because host.enabled being processed before host.other_config (CA-75625);
// We'll check it again after the cache update operation is complete, in Connection_XenObjectsUpdated
hostsInInvalidState . Add ( host ) ;
}
UpdateToolbars ( ) ;
break ;
case "edition" :
case "license_server" :
case "license_params" :
case "other_config" :
// other_config may contain HideFromXenCenter
UpdateToolbars ( ) ;
break ;
case "name_label" :
//check whether it's a standalone host
if ( Helpers . GetPool ( host . Connection ) = = null )
host . Connection . FriendlyName = Helpers . GetName ( host ) ;
break ;
}
}
private void VM_PropertyChanged ( object obj , PropertyChangedEventArgs e )
{
VM vm = ( VM ) obj ;
switch ( e . PropertyName )
{
case "allowed_operations" :
case "is_a_template" :
case "resident_on" :
UpdateToolbars ( ) ;
break ;
case "power_state" :
UpdateToolbars ( ) ;
// Make all vms have the correct start times
UpdateBodgedTime ( vm , e . PropertyName ) ;
break ;
case "other_config" :
// other_config may contain HideFromXenCenter
UpdateToolbars ( ) ;
// Make all vms have the correct start times
UpdateBodgedTime ( vm , e . PropertyName ) ;
break ;
}
}
void o_PropertyChanged ( object sender , PropertyChangedEventArgs e )
{
switch ( e . PropertyName )
{
case "allowed_operations" :
case "power_state" :
case "is_a_template" :
case "enabled" :
UpdateToolbars ( ) ;
break ;
case "other_config" :
// other_config may contain HideFromXenCenter
UpdateToolbars ( ) ;
break ;
}
}
// Update bodged startup time if the powerstate goes to running (vm started from halted), otherconfig last shutdown changed (vm rebooted) or start time changed (occurs a few seconds after start)
private void UpdateBodgedTime ( VM vm , string p )
{
if ( vm = = null )
return ;
if ( p = = "power_state" )
{
vm . BodgeStartupTime = DateTime . UtcNow ; // always newer than current bodge startup time
}
else if ( p = = "other_config" & & vm . other_config . ContainsKey ( "last_shutdown_time" ) )
{
DateTime newTime = vm . LastShutdownTime ;
if ( newTime ! = DateTime . MinValue & & newTime . Ticks > vm . BodgeStartupTime . Ticks )
vm . BodgeStartupTime = newTime ; // only update if is newer than current bodge startup time
}
}
void Connection_ConnectionResult ( object sender , Network . ConnectionResultEventArgs e )
{
RequestRefreshTreeView ( ) ;
Program . Invoke ( this , ( EventHandler < ConnectionResultEventArgs > ) Connection_ConnectionResult_ , sender , e ) ;
}
private void Connection_ConnectionResult_ ( object sender , Network . ConnectionResultEventArgs e )
{
Program . AssertOnEventThread ( ) ;
try
{
UpdateToolbars ( ) ;
}
catch ( Exception exn )
{
log . Error ( exn , exn ) ;
// Can do nothing more about this.
}
}
void Connection_ConnectionClosed ( object sender , EventArgs e )
{
RequestRefreshTreeView ( ) ;
Program . Invoke ( this , ( EventHandler < Network . ConnectionResultEventArgs > ) Connection_ConnectionClosed_ , sender , e ) ;
gc ( ) ;
}
private void Connection_ConnectionClosed_ ( object sender , EventArgs e )
{
Program . AssertOnEventThread ( ) ;
try
{
UpdateToolbars ( ) ;
}
catch ( Exception exn )
{
log . Error ( exn , exn ) ;
// Nothing more we can do with this.
}
}
// called whenever our connection with the Xen server fails (i.e., after we've successfully logged in)
void Connection_ConnectionLost ( object sender , EventArgs e )
{
if ( Program . Exiting )
return ;
Program . Invoke ( this , ( EventHandler ) Connection_ConnectionLost_ , sender , e ) ;
RequestRefreshTreeView ( ) ;
gc ( ) ;
}
private void Connection_ConnectionLost_ ( object sender , EventArgs e )
{
Program . AssertOnEventThread ( ) ;
try
{
IXenConnection connection = ( IXenConnection ) sender ;
2014-01-22 13:39:32 +01:00
CloseActiveWizards ( connection ) ;
2013-06-24 13:41:48 +02:00
UpdateToolbars ( ) ;
}
catch ( Exception exn )
{
log . Error ( exn , exn ) ;
// Can do nothing about this.
}
}
private static void gc ( )
{
2015-03-20 14:17:06 +01:00
//log_gc("Before"); // Don't log this, CA-159791
2013-06-24 13:41:48 +02:00
GC . Collect ( ) ;
2015-03-20 14:17:06 +01:00
//log_gc("After");
2013-06-24 13:41:48 +02:00
}
private static void log_gc ( string when )
{
log . DebugFormat ( "{0} GC: approx {1} bytes in use" , when , GC . GetTotalMemory ( false ) ) ;
for ( int i = 0 ; i < = GC . MaxGeneration ; i + + )
{
log . DebugFormat ( "Number of times GC has occurred for generation {0} objects: {1}" , i , GC . CollectionCount ( i ) ) ;
}
log . Debug ( "GDI objects in use: " + Win32 . GetGuiResourcesGDICount ( Process . GetCurrentProcess ( ) . Handle ) ) ;
log . Debug ( "USER objects in use: " + Win32 . GetGuiResourcesUserCount ( Process . GetCurrentProcess ( ) . Handle ) ) ;
}
void connection_ConnectionReconnecting ( object sender , EventArgs e )
{
if ( Program . Exiting )
return ;
RequestRefreshTreeView ( ) ;
gc ( ) ;
}
private List < Host > hostsInInvalidState = new List < Host > ( ) ;
// called whenever Xen objects on the server change state
void Connection_XenObjectsUpdated ( object sender , EventArgs e )
{
if ( Program . Exiting )
return ;
IXenConnection connection = ( IXenConnection ) sender ;
if ( hostsInInvalidState . Count > 0 )
{
foreach ( var host in hostsInInvalidState . Where ( host = > host . Connection = = connection ) )
CheckMaintenanceMode ( host ) ;
hostsInInvalidState . RemoveAll ( host = > host . Connection = = connection ) ;
}
RequestRefreshTreeView ( ) ;
}
private int ignoreUpdateToolbars = 0 ;
private bool calledUpdateToolbars = false ;
/// <summary>
/// Requests a refresh of the main tree view. The refresh will be managed such that we are not overloaded using an UpdateManager.
/// </summary>
public void RequestRefreshTreeView ( )
{
2013-11-20 14:09:17 +01:00
Program . Invoke ( this , navigationPane . RequestRefreshTreeView ) ;
2013-06-24 13:41:48 +02:00
}
2013-08-22 11:55:32 +02:00
private void UpdateHeaderAndTabPages ( )
{
Program . Invoke ( this , ( ) = >
{
// This is required to update search results when things change.
if ( TheTabControl . SelectedTab = = TabPageGeneral )
GeneralPage . BuildList ( ) ;
else if ( TheTabControl . SelectedTab = = TabPageSearch )
SearchPage . BuildList ( ) ;
2013-08-24 18:00:32 +02:00
UpdateHeader ( ) ;
2013-08-22 11:55:32 +02:00
} ) ;
2013-06-24 13:41:48 +02:00
}
void exitToolStripMenuItem_Click ( object sender , EventArgs e )
{
this . Close ( ) ;
}
private bool _menuShortcuts = true ;
public bool MenuShortcuts
{
set
{
if ( value ! = _menuShortcuts )
{
//if the VNC Console is active (the user is typing into it etc) all of the shortcuts for XenCenter are disabled
//IMPORTANT! add any shortcuts you want to pass to the VNC console into this if, else statement
_menuShortcuts = value ;
// update the selection so menu items can enable/disable keyboard shortcuts as appropriate.
2013-08-22 18:25:12 +02:00
SelectionManager . RefreshSelection ( ) ;
2013-06-24 13:41:48 +02:00
}
}
}
/// <summary>
/// Must be called on the event thread.
/// </summary>
public void UpdateToolbars ( )
{
Program . AssertOnEventThread ( ) ;
if ( ignoreUpdateToolbars > 0 )
{
calledUpdateToolbars = true ;
return ;
}
ToolStrip . SuspendLayout ( ) ;
UpdateToolbarsCore ( ) ;
MainMenuBar_MenuActivate ( null , null ) ;
ToolStrip . ResumeLayout ( ) ;
}
private static int TOOLBAR_HEIGHT = 31 ;
/// <summary>
/// Updates the toolbar buttons. Also updates which tabs are visible.
/// </summary>
public void UpdateToolbarsCore ( )
{
// refresh the selection-manager
2013-08-22 18:25:12 +02:00
SelectionManager . RefreshSelection ( ) ;
2013-06-24 13:41:48 +02:00
ToolStrip . Height = ToolbarsEnabled ? TOOLBAR_HEIGHT : 0 ;
ToolStrip . Enabled = ToolbarsEnabled ;
ShowToolbarMenuItem . Checked = toolbarToolStripMenuItem . Checked = ToolbarsEnabled ;
2015-02-11 14:46:23 +01:00
bool containerButtonsAvailable = startContainerToolStripButton . Enabled | | stopContainerToolStripButton . Enabled | |
resumeContainerToolStripButton . Enabled | | pauseContainerToolStripButton . Enabled | | restartContainerToolStripButton . Enabled ;
startContainerToolStripButton . Available = containerButtonsAvailable & & startContainerToolStripButton . Enabled ;
stopContainerToolStripButton . Available = containerButtonsAvailable & & ( stopContainerToolStripButton . Enabled | | ! startContainerToolStripButton . Available ) ;
resumeContainerToolStripButton . Available = containerButtonsAvailable & & resumeContainerToolStripButton . Enabled ;
pauseContainerToolStripButton . Available = containerButtonsAvailable & & ( pauseContainerToolStripButton . Enabled | | ! resumeContainerToolStripButton . Available ) ;
restartContainerToolStripButton . Available = containerButtonsAvailable ;
2013-06-24 13:41:48 +02:00
powerOnHostToolStripButton . Available = powerOnHostToolStripButton . Enabled ;
startVMToolStripButton . Available = startVMToolStripButton . Enabled ;
2015-02-11 14:46:23 +01:00
shutDownToolStripButton . Available = shutDownToolStripButton . Enabled | | ( ! startVMToolStripButton . Available & & ! powerOnHostToolStripButton . Available & & ! containerButtonsAvailable ) ;
RebootToolbarButton . Available = RebootToolbarButton . Enabled | | ! containerButtonsAvailable ;
2013-06-24 13:41:48 +02:00
resumeToolStripButton . Available = resumeToolStripButton . Enabled ;
2015-02-11 14:46:23 +01:00
SuspendToolbarButton . Available = SuspendToolbarButton . Enabled | | ( ! resumeToolStripButton . Available & & ! containerButtonsAvailable ) ;
2013-06-24 13:41:48 +02:00
ForceRebootToolbarButton . Available = ( ( ForceVMRebootCommand ) ForceRebootToolbarButton . Command ) . ShowOnMainToolBar ;
ForceShutdownToolbarButton . Available = ( ( ForceVMShutDownCommand ) ForceShutdownToolbarButton . Command ) . ShowOnMainToolBar ;
2013-08-22 18:25:12 +02:00
IXenConnection selectionConnection = SelectionManager . Selection . GetConnectionOfFirstItem ( ) ;
2013-06-24 13:41:48 +02:00
Pool selectionPool = selectionConnection = = null ? null : Helpers . GetPool ( selectionConnection ) ;
Host selectionMaster = null = = selectionPool ? null : selectionPool . Connection . Resolve ( selectionPool . master ) ;
// 'Home' tab is only visible if the 'Overview' tree node is selected, or if the tree is
// empty (i.e. at startup).
2013-08-22 18:25:12 +02:00
bool show_home = SelectionManager . Selection . Count = = 1 & & SelectionManager . Selection [ 0 ] . Value = = null ;
2013-06-24 13:41:48 +02:00
// The upsell pages use the first selected XenObject: but they're only shown if there is only one selected object (see calls to ShowTab() below).
2013-08-22 18:25:12 +02:00
bool dmc_upsell = Helpers . FeatureForbidden ( SelectionManager . Selection . FirstAsXenObject , Host . RestrictDMC ) ;
2015-10-26 17:01:55 +01:00
bool ha_upsell = Helpers . FeatureForbidden ( SelectionManager . Selection . FirstAsXenObject , Host . RestrictHA ) ;
2013-08-22 18:25:12 +02:00
bool wlb_upsell = Helpers . FeatureForbidden ( SelectionManager . Selection . FirstAsXenObject , Host . RestrictWLB ) ;
2013-06-24 13:41:48 +02:00
bool is_connected = selectionConnection ! = null & & selectionConnection . IsConnected ;
bool multi = SelectionManager . Selection . Count > 1 ;
2013-08-22 18:25:12 +02:00
bool isPoolSelected = SelectionManager . Selection . FirstIsPool ;
bool isVMSelected = SelectionManager . Selection . FirstIsVM ;
bool isHostSelected = SelectionManager . Selection . FirstIsHost ;
bool isSRSelected = SelectionManager . Selection . FirstIsSR ;
bool isRealVMSelected = SelectionManager . Selection . FirstIsRealVM ;
bool isTemplateSelected = SelectionManager . Selection . FirstIsTemplate ;
bool isHostLive = SelectionManager . Selection . FirstIsLiveHost ;
2014-12-05 15:16:58 +01:00
bool isDockerContainerSelected = SelectionManager . Selection . First is DockerContainer ;
2013-06-24 13:41:48 +02:00
2013-08-22 18:25:12 +02:00
bool selectedTemplateHasProvisionXML = SelectionManager . Selection . FirstIsTemplate & & ( ( VM ) SelectionManager . Selection [ 0 ] . XenObject ) . HasProvisionXML ;
2013-06-24 13:41:48 +02:00
NewTabCount = 0 ;
ShowTab ( TabPageHome , ! SearchMode & & show_home ) ;
2015-10-27 19:11:53 +01:00
ShowTab ( TabPageGeneral , ! multi & & ! SearchMode & & ( isVMSelected | | ( isHostSelected & & ( isHostLive | | ! is_connected ) ) | | isPoolSelected | | isSRSelected | | isDockerContainerSelected ) ) ;
2015-10-26 17:01:55 +01:00
ShowTab ( dmc_upsell ? TabPageBallooningUpsell : TabPageBallooning , ! multi & & ! SearchMode & & ( isVMSelected | | ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
2013-06-24 13:41:48 +02:00
ShowTab ( TabPageStorage , ! multi & & ! SearchMode & & ( isRealVMSelected | | ( isTemplateSelected & & ! selectedTemplateHasProvisionXML ) ) ) ;
2015-10-27 19:11:53 +01:00
ShowTab ( TabPageSR , ! multi & & ! SearchMode & & isSRSelected ) ;
2013-06-24 13:41:48 +02:00
ShowTab ( TabPagePhysicalStorage , ! multi & & ! SearchMode & & ( ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
ShowTab ( TabPageNetwork , ! multi & & ! SearchMode & & ( isVMSelected | | ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
ShowTab ( TabPageNICs , ! multi & & ! SearchMode & & ( ( isHostSelected & & isHostLive ) ) ) ;
2016-02-12 17:48:52 +01:00
ShowTab ( TabPageDockerProcess , ! multi & & ! SearchMode & & isDockerContainerSelected & & ! ( SelectionManager . Selection . First as DockerContainer ) . Parent . IsWindows ) ;
2015-02-18 10:50:55 +01:00
ShowTab ( TabPageDockerDetails , ! multi & & ! SearchMode & & isDockerContainerSelected ) ;
2013-06-24 13:41:48 +02:00
2013-11-14 12:23:35 +01:00
bool isPoolOrLiveStandaloneHost = isPoolSelected | | ( isHostSelected & & isHostLive & & selectionPool = = null ) ;
2015-03-31 18:26:37 +02:00
ShowTab ( TabPageGPU , ! multi & & ! SearchMode & & ( ( isHostSelected & & isHostLive ) | | isPoolOrLiveStandaloneHost ) & & Helpers . ClearwaterSp1OrGreater ( selectionConnection ) & & ! Helpers . FeatureForbidden ( selectionConnection , Host . RestrictGpu ) ) ;
2013-11-14 12:23:35 +01:00
2013-08-22 18:25:12 +02:00
pluginManager . SetSelectedXenObject ( SelectionManager . Selection . FirstAsXenObject ) ;
2013-06-24 13:41:48 +02:00
bool shownConsoleReplacement = false ;
foreach ( TabPageFeature f in pluginManager . GetAllFeatures < TabPageFeature > ( f = > f . IsConsoleReplacement & & ! f . IsError & & ! multi & & f . ShowTab ) )
{
ShowTab ( f . TabPage , true ) ;
shownConsoleReplacement = true ;
}
ShowTab ( TabPageConsole , ! shownConsoleReplacement & & ! multi & & ! SearchMode & & ( isRealVMSelected | | ( isHostSelected & & isHostLive ) ) ) ;
ShowTab ( TabPagePeformance , ! multi & & ! SearchMode & & ( isRealVMSelected | | ( isHostSelected & & isHostLive ) ) ) ;
2015-10-26 17:01:55 +01:00
ShowTab ( ha_upsell ? TabPageHAUpsell : TabPageHA , ! multi & & ! SearchMode & & isPoolSelected ) ;
ShowTab ( TabPageSnapshots , ! multi & & ! SearchMode & & isRealVMSelected ) ;
2014-04-28 07:44:37 +02:00
2014-05-07 07:15:29 +02:00
//Any Clearwater XenServer, or WLB is not licensed on XenServer, the WLB tab and any WLB menu items disappear completely.
if ( ! ( SelectionManager . Selection . All ( s = > Helpers . IsClearwater ( s . Connection ) ) | | wlb_upsell ) )
2015-10-26 17:01:55 +01:00
ShowTab ( TabPageWLB , ! multi & & ! SearchMode & & isPoolSelected ) ;
2014-04-28 07:44:37 +02:00
2015-10-26 17:01:55 +01:00
ShowTab ( TabPageAD , ! multi & & ! SearchMode & & ( isPoolSelected | | isHostSelected & & isHostLive ) ) ;
2013-06-24 13:41:48 +02:00
foreach ( TabPageFeature f in pluginManager . GetAllFeatures < TabPageFeature > ( f = > ! f . IsConsoleReplacement & & ! multi & & f . ShowTab ) )
ShowTab ( f . TabPage , true ) ;
2013-10-01 16:35:57 +02:00
ShowTab ( TabPageSearch , true ) ;
2013-06-24 13:41:48 +02:00
// N.B. Change NewTabs definition if you add more tabs here.
// Save and restore focus on treeView, since selecting tabs in ChangeToNewTabs() has the
// unavoidable side-effect of giving them focus - this is irritating if trying to navigate
// the tree using the keyboard.
2013-08-26 12:42:32 +02:00
navigationPane . SaveAndRestoreTreeViewFocus ( ChangeToNewTabs ) ;
2013-06-24 13:41:48 +02:00
}
private readonly TabPage [ ] NewTabs = new TabPage [ 512 ] ;
int NewTabCount ;
private void ShowTab ( TabPage page , bool visible )
{
if ( visible )
{
NewTabs [ NewTabCount ] = page ;
NewTabCount + + ;
}
}
private void ChangeToNewTabs ( )
{
TabPage new_selected_page = NewSelectedPage ( ) ;
TheTabControl . SuspendLayout ( ) ;
IgnoreTabChanges = true ;
try
{
TabControl . TabPageCollection p = TheTabControl . TabPages ;
int i = 0 ; // Index into NewTabs
int m = 0 ; // Index into p
while ( i < NewTabCount )
{
if ( m = = p . Count )
{
p . Add ( NewTabs [ i ] ) ;
if ( new_selected_page = = NewTabs [ i ] )
TheTabControl . SelectedTab = new_selected_page ;
m + + ;
i + + ;
}
else if ( p [ m ] = = NewTabs [ i ] )
{
if ( new_selected_page = = NewTabs [ i ] )
TheTabControl . SelectedTab = new_selected_page ;
m + + ;
i + + ;
}
2013-08-23 12:32:27 +02:00
else if ( NewTabs . Contains ( p [ m ] ) )
2013-06-24 13:41:48 +02:00
{
p . Insert ( m , NewTabs [ i ] ) ;
if ( new_selected_page = = NewTabs [ i ] )
TheTabControl . SelectedTab = new_selected_page ;
m + + ;
i + + ;
}
else
{
if ( TheTabControl . SelectedTab = = p [ m ] & & new_selected_page = = NewTabs [ i ] )
{
// This clause is deliberately targeted at the case when you go from
// Overview:Home to Host:Overview.
p . Insert ( m , NewTabs [ i ] ) ;
TheTabControl . SelectedTab = new_selected_page ;
m + + ;
i + + ;
}
p . Remove ( p [ m ] ) ;
}
}
// Remove any tabs that are left at the end of the list.
while ( m < p . Count )
{
TabPage removed = p [ p . Count - 1 ] ;
p . Remove ( removed ) ;
int index = NewTabsIndexOf ( removed ) ;
if ( index ! = - 1 )
{
// If this is a tab that we want, then we've got it in the list twice -- one
// reference was here when we entered this function, and is the one that we're
// pointing at now, and the other reference we've inserted through the loop above.
// This is bad -- p.Remove(removed) above has now invalidated removed.Parent
// (removed is still in the list through the other reference). Fix this up by
// removing the other reference too and starting over.
// We can't do the Remove call in the loop above, because this has a poor visual
// effect.
p . Remove ( removed ) ;
p . Insert ( index , removed ) ;
if ( new_selected_page = = removed )
TheTabControl . SelectedTab = removed ;
}
}
}
finally
{
IgnoreTabChanges = false ;
TheTabControl . ResumeLayout ( ) ;
2013-08-22 18:25:12 +02:00
SetLastSelectedPage ( SelectionManager . Selection . First , TheTabControl . SelectedTab ) ;
2013-06-24 13:41:48 +02:00
}
}
private TabPage NewSelectedPage ( )
{
2013-08-22 18:25:12 +02:00
Object o = SelectionManager . Selection . First ;
2013-06-24 13:41:48 +02:00
IXenObject s = o as IXenObject ;
2013-09-02 15:45:42 +02:00
TabPage last_selected_page = GetLastSelectedPage ( o ) ;
return last_selected_page ! = null & & NewTabs . Contains ( last_selected_page )
? last_selected_page
: NewTabs [ 0 ] ;
2013-06-24 13:41:48 +02:00
}
2013-09-02 15:45:42 +02:00
private void SetLastSelectedPage ( object o , TabPage p )
2013-06-24 13:41:48 +02:00
{
2013-08-25 13:42:38 +02:00
if ( SearchMode )
2013-06-24 13:41:48 +02:00
return ;
if ( o = = null )
{
selectedOverviewTab = p ;
}
else
{
selectedTabs [ o ] = p ;
}
}
private TabPage GetLastSelectedPage ( object o )
{
return
o = = null ? selectedOverviewTab :
selectedTabs . ContainsKey ( o ) ? selectedTabs [ o ] :
null ;
}
private int NewTabsIndexOf ( TabPage tp )
{
for ( int i = 0 ; i < NewTabCount ; i + + )
{
if ( NewTabs [ i ] = = tp )
return i ;
}
return - 1 ;
}
2013-12-31 11:34:11 +01:00
private void pluginManager_PluginsChanged ( )
2013-06-24 13:41:48 +02:00
{
2013-12-31 11:34:11 +01:00
foreach ( ToolStripMenuItem menu in MainMenuBar . Items )
2013-06-24 13:41:48 +02:00
{
2013-12-31 11:34:11 +01:00
//clear existing plugin items
for ( int i = menu . DropDownItems . Count - 1 ; i > = 0 ; i - - )
2013-06-24 13:41:48 +02:00
{
2013-12-31 11:34:11 +01:00
CommandToolStripMenuItem commandMenuItem = menu . DropDownItems [ i ] as CommandToolStripMenuItem ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
if ( commandMenuItem ! = null & & ( commandMenuItem . Command is MenuItemFeatureCommand
| | commandMenuItem . Command is ParentMenuItemFeatureCommand ) )
2013-06-24 13:41:48 +02:00
{
menu . DropDownItems . RemoveAt ( i ) ;
2013-12-31 11:34:11 +01:00
if ( menu . DropDownItems . Count > 0 & & menu . DropDownItems [ i ] is ToolStripSeparator )
menu . DropDownItems . RemoveAt ( i ) ;
2013-06-24 13:41:48 +02:00
}
}
2013-12-31 11:34:11 +01:00
// get insert index using the placeholder
int insertIndex = pluginMenuItemStartIndexes [ menu ] ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
bool itemAdded = false ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
// add plugin items for this menu at insertIndex
foreach ( PluginDescriptor plugin in pluginManager . Plugins )
2013-06-24 13:41:48 +02:00
{
2013-12-31 11:34:11 +01:00
if ( ! plugin . Enabled )
continue ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
foreach ( Feature feature in plugin . Features )
2013-06-24 13:41:48 +02:00
{
2013-12-31 11:34:11 +01:00
var menuItemFeature = feature as MenuItemFeature ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
if ( menuItemFeature ! = null & & menuItemFeature . ParentFeature = = null & & ( int ) menuItemFeature . Menu = = MainMenuBar . Items . IndexOf ( menu ) )
{
2014-01-22 13:39:32 +01:00
Command cmd = menuItemFeature . GetCommand ( this , SelectionManager . Selection ) ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
menu . DropDownItems . Insert ( insertIndex , new CommandToolStripMenuItem ( cmd ) ) ;
insertIndex + + ;
itemAdded = true ;
}
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
var parentMenuItemFeature = feature as ParentMenuItemFeature ;
2013-06-24 13:41:48 +02:00
2013-12-31 11:34:11 +01:00
if ( parentMenuItemFeature ! = null & & ( int ) parentMenuItemFeature . Menu = = MainMenuBar . Items . IndexOf ( menu ) )
2013-06-24 13:41:48 +02:00
{
2014-01-22 13:39:32 +01:00
Command cmd = parentMenuItemFeature . GetCommand ( this , SelectionManager . Selection ) ;
2013-12-31 11:34:11 +01:00
CommandToolStripMenuItem parentMenuItem = new CommandToolStripMenuItem ( cmd ) ;
menu . DropDownItems . Insert ( insertIndex , parentMenuItem ) ;
insertIndex + + ;
itemAdded = true ;
foreach ( MenuItemFeature childFeature in parentMenuItemFeature . Features )
{
2014-01-22 13:39:32 +01:00
Command childCommand = childFeature . GetCommand ( this , SelectionManager . Selection ) ;
2013-12-31 11:34:11 +01:00
parentMenuItem . DropDownItems . Add ( new CommandToolStripMenuItem ( childCommand ) ) ;
}
2013-06-24 13:41:48 +02:00
}
}
}
2013-12-31 11:34:11 +01:00
if ( itemAdded & & insertIndex ! = menu . DropDownItems . Count )
menu . DropDownItems . Insert ( insertIndex , new ToolStripSeparator ( ) ) ;
2013-06-24 13:41:48 +02:00
}
}
private void MainMenuBar_MenuActivate ( object sender , EventArgs e )
{
2013-08-22 18:25:12 +02:00
Host hostAncestor = SelectionManager . Selection . Count = = 1 ? SelectionManager . Selection [ 0 ] . HostAncestor : null ;
IXenConnection connection = SelectionManager . Selection . GetConnectionOfFirstItem ( ) ;
bool vm = SelectionManager . Selection . FirstIsRealVM & & ! ( ( VM ) SelectionManager . Selection . First ) . Locked ;
2013-06-24 13:41:48 +02:00
exportSettingsToolStripMenuItem . Enabled = ConnectionsManager . XenConnectionsCopy . Count > 0 ;
this . MenuShortcuts = true ;
startOnHostToolStripMenuItem . Available = startOnHostToolStripMenuItem . Enabled ;
resumeOnToolStripMenuItem . Available = resumeOnToolStripMenuItem . Enabled ;
relocateToolStripMenuItem . Available = relocateToolStripMenuItem . Enabled ;
2013-08-22 18:25:12 +02:00
sendCtrlAltDelToolStripMenuItem . Enabled = ( TheTabControl . SelectedTab = = TabPageConsole ) & & vm & & ( ( VM ) SelectionManager . Selection . First ) . power_state = = vm_power_state . Running ;
2013-06-24 13:41:48 +02:00
templatesToolStripMenuItem1 . Checked = Properties . Settings . Default . DefaultTemplatesVisible ;
customTemplatesToolStripMenuItem . Checked = Properties . Settings . Default . UserTemplatesVisible ;
localStorageToolStripMenuItem . Checked = Properties . Settings . Default . LocalSRsVisible ;
ShowHiddenObjectsToolStripMenuItem . Checked = Properties . Settings . Default . ShowHiddenVMs ;
connectDisconnectToolStripMenuItem . Enabled = ConnectionsManager . XenConnectionsCopy . Count > 0 ;
}
private void xenSourceOnTheWebToolStripMenuItem_Click ( object sender , EventArgs e )
{
Program . OpenURL ( InvisibleMessages . HOMEPAGE ) ;
}
private void xenCenterPluginsOnTheWebToolStripMenuItem_Click ( object sender , EventArgs e )
{
Program . OpenURL ( InvisibleMessages . PLUGINS_URL ) ;
}
private void aboutXenSourceAdminToolStripMenuItem_Click ( object sender , EventArgs e )
{
2013-08-21 18:13:23 +02:00
ShowForm ( typeof ( AboutDialog ) ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Apply license, if HostAncestorOfSelectedNode is null, show host picker, if filepath == "" show filepicker
/// </summary>
public void LaunchLicensePicker ( string filepath )
{
HelpersGUI . BringFormToFront ( this ) ;
OpenFileDialog dialog = null ;
DialogResult result = DialogResult . Cancel ;
if ( filepath = = "" )
{
if ( ! Program . RunInAutomatedTestMode )
{
dialog = new OpenFileDialog ( ) ;
dialog . Multiselect = false ;
dialog . Title = Messages . INSTALL_LICENSE_KEY ;
dialog . CheckFileExists = true ;
dialog . CheckPathExists = true ;
dialog . Filter = string . Format ( "{0} (*.xslic)|*.xslic|{1} (*.*)|*.*" , Messages . XS_LICENSE_FILES , Messages . ALL_FILES ) ;
dialog . ShowHelp = true ;
dialog . HelpRequest + = new EventHandler ( dialog_HelpRequest ) ;
result = dialog . ShowDialog ( this ) ;
}
}
else
{
result = DialogResult . OK ;
}
if ( result = = DialogResult . OK | | Program . RunInAutomatedTestMode )
{
filepath = Program . RunInAutomatedTestMode ? "" : filepath = = "" ? dialog . FileName : filepath ;
2013-08-22 18:25:12 +02:00
Host hostAncestor = SelectionManager . Selection . Count = = 1 ? SelectionManager . Selection [ 0 ] . HostAncestor : null ;
2013-06-24 13:41:48 +02:00
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . Count = = 1 & & hostAncestor = = null )
2013-06-24 13:41:48 +02:00
{
SelectHostDialog hostdialog = new SelectHostDialog ( ) ;
hostdialog . TheHost = null ;
hostdialog . Owner = this ;
hostdialog . ShowDialog ( this ) ;
if ( string . IsNullOrEmpty ( filepath ) | | hostdialog . DialogResult ! = DialogResult . OK )
{
return ;
}
hostAncestor = hostdialog . TheHost ;
}
DoLicenseAction ( hostAncestor , filepath ) ;
}
}
private void DoLicenseAction ( Host host , string filePath )
{
ApplyLicenseAction action = new ApplyLicenseAction ( host . Connection , host , filePath ) ;
ActionProgressDialog actionProgress = new ActionProgressDialog ( action , ProgressBarStyle . Marquee ) ;
actionProgress . Text = Messages . INSTALL_LICENSE_KEY ;
actionProgress . ShowDialog ( this ) ;
}
private void dialog_HelpRequest ( object sender , EventArgs e )
{
Help . HelpManager . Launch ( "LicenseKeyDialog" ) ;
}
/// <param name="e">
/// If null, then we deduce the method was called by TreeView_AfterSelect
/// and don't focus the VNC console. i.e. we only focus the VNC console if the user
/// explicitly clicked on the console tab rather than arriving there by navigating
/// in treeView.
/// </param>
private void TheTabControl_SelectedIndexChanged ( object sender , EventArgs e )
{
if ( IgnoreTabChanges )
return ;
TabPage t = TheTabControl . SelectedTab ;
if ( ! SearchMode )
2013-08-22 18:25:12 +02:00
History . NewHistoryItem ( new XenModelObjectHistoryItem ( SelectionManager . Selection . FirstAsXenObject , t ) ) ;
2013-06-24 13:41:48 +02:00
if ( t ! = TabPageBallooning )
BallooningPage . IsHidden ( ) ;
if ( t = = TabPageConsole )
{
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsRealVM )
2013-06-24 13:41:48 +02:00
{
2013-08-22 18:25:12 +02:00
ConsolePanel . setCurrentSource ( ( VM ) SelectionManager . Selection . First ) ;
2013-06-24 13:41:48 +02:00
UnpauseVNC ( e ! = null & & sender = = TheTabControl ) ;
}
2013-08-22 18:25:12 +02:00
else if ( SelectionManager . Selection . FirstIsHost )
2013-06-24 13:41:48 +02:00
{
2013-08-22 18:25:12 +02:00
ConsolePanel . setCurrentSource ( ( Host ) SelectionManager . Selection . First ) ;
2013-06-24 13:41:48 +02:00
UnpauseVNC ( e ! = null & & sender = = TheTabControl ) ;
}
}
else
{
2013-11-14 13:24:57 +01:00
ConsolePanel . PauseAllViews ( ) ;
// Start timer for closing the VNC connection after an interval (20 seconds)
// when the console tab is not selected
ConsolePanel . StartCloseVNCTimer ( ConsolePanel . activeVNCView ) ;
2013-06-24 13:41:48 +02:00
if ( t = = TabPageGeneral )
{
2013-08-22 18:25:12 +02:00
GeneralPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageBallooning )
{
2013-08-22 18:25:12 +02:00
BallooningPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageSR )
{
2015-10-27 19:11:53 +01:00
SrStoragePage . SR = SelectionManager . Selection . First as SR ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageNetwork )
{
2013-08-22 18:25:12 +02:00
NetworkPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageNICs )
{
2013-08-22 18:25:12 +02:00
NICPage . Host = SelectionManager . Selection . First as Host ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageStorage )
{
2013-08-22 18:25:12 +02:00
VMStoragePage . VM = SelectionManager . Selection . First as VM ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPagePeformance )
{
2013-08-22 18:25:12 +02:00
PerformancePage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageSearch & & ! SearchMode )
{
2013-10-08 11:17:57 +02:00
var rootNode = SelectionManager . Selection . RootNode ;
var rootNodeGrouping = rootNode = = null ? null : rootNode . Tag as GroupingTag ;
var search = rootNode = = null ? null : rootNode . Tag as Search ;
if ( search ! = null )
{
SearchPage . Search = search ;
}
else if ( rootNodeGrouping ! = null )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
var objectsView = rootNodeGrouping . Grouping as OrganizationViewObjects ;
var vappsView = rootNodeGrouping . Grouping as OrganizationViewVapps ;
2013-12-02 16:26:46 +01:00
var foldersView = rootNodeGrouping . Grouping as OrganizationViewFolders ;
2013-10-08 11:17:57 +02:00
if ( vappsView ! = null )
{
SearchPage . Search = Search . SearchForVappGroup ( rootNodeGrouping . Grouping ,
rootNodeGrouping . Parent , rootNodeGrouping . Group ) ;
}
else if ( objectsView ! = null )
{
2014-09-22 16:55:20 +02:00
//We are in Objects View
2014-09-17 16:47:43 +02:00
GroupingTag gt = null ;
2013-10-08 11:17:57 +02:00
2014-09-17 16:47:43 +02:00
if ( SelectionManager . Selection . Count = = 1 )
{
gt = SelectionManager . Selection . First as GroupingTag
? ? SelectionManager . Selection [ 0 ] . GroupAncestor ;
}
else
{
2014-09-22 16:55:20 +02:00
//If multiple items have been selected we count the number of the grouping tags in the selection
2014-09-19 13:45:42 +02:00
var selectedGroups = SelectionManager . Selection . Where ( s = > s . GroupingTag ! = null ) ;
2014-09-22 16:55:20 +02:00
//if exactly one grouping tag has been selected we show the search view for that one tag, but only if all the other items in the selection belong to this group/tag
2014-09-19 13:45:42 +02:00
if ( selectedGroups . Count ( ) = = 1 )
{
var groupingTag = selectedGroups . First ( ) . GroupingTag ;
if ( SelectionManager . Selection . Where ( s = > s . GroupingTag = = null ) . All ( s = > s . GroupAncestor = = groupingTag ) )
gt = groupingTag ;
else
gt = null ;
}
else
{
gt = SelectionManager . Selection . GroupAncestor ;
}
2014-09-17 16:47:43 +02:00
}
2014-09-22 16:55:20 +02:00
//if there has been a grouping tag determined above we use that
//if not we show the search view for the root node
2014-09-17 16:47:43 +02:00
if ( gt ! = null )
{
SearchPage . Search = Search . SearchForNonVappGroup ( gt . Grouping , gt . Parent , gt . Group ) ;
}
else
{
SearchPage . Search = Search . SearchForNonVappGroup ( rootNodeGrouping . Grouping , rootNodeGrouping . Parent , rootNodeGrouping . Group ) ;
}
2013-10-08 11:17:57 +02:00
}
2013-12-02 16:26:46 +01:00
else if ( foldersView ! = null )
{
SearchPage . Search = Search . SearchForFolderGroup ( rootNodeGrouping . Grouping ,
rootNodeGrouping . Parent , rootNodeGrouping . Group ) ;
}
2013-10-08 11:17:57 +02:00
else
{
SearchPage . Search = Search . SearchForNonVappGroup ( rootNodeGrouping . Grouping ,
rootNodeGrouping . Parent , rootNodeGrouping . Group ) ;
}
2013-06-24 13:41:48 +02:00
}
else
{
2014-09-19 14:47:04 +02:00
// Infrastructure View:
// If XenCenter node or a disconnected host is selected, show the default search
// Otherwise, find the top-level parent (= pool or standalone server) and show the search restricted to that
// In the case of multiselect, if all the selections are within one pool (or standalone server), then show that report.
// Otherwise show everything, as on the XenCenter node.
var connection = SelectionManager . Selection . GetConnectionOfAllItems ( ) ; // null for cross-pool selection
if ( connection ! = null )
{
2015-10-19 18:07:12 +02:00
//If ShowJustHostInSearch is enabled and only one live host is selected, we show the search for the host only
if ( Properties . Settings . Default . ShowJustHostInSearch & & SelectionManager . Selection . Count = = 1
& & SelectionManager . Selection . FirstIsLiveHost )
{
SearchPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
}
else
{
var pool = Helpers . GetPool ( connection ) ;
SearchPage . XenObject = pool ? ? ( IXenObject ) Helpers . GetMaster ( connection ) ; // pool or standalone server
}
2014-09-19 14:47:04 +02:00
}
else
SearchPage . XenObject = null ;
2013-06-24 13:41:48 +02:00
}
}
else if ( t = = TabPageHA )
{
2013-08-22 18:25:12 +02:00
HAPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageWLB )
{
2013-08-22 18:25:12 +02:00
WlbPage . Pool = SelectionManager . Selection . First as Pool ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageSnapshots )
{
2013-08-22 18:25:12 +02:00
snapshotPage . VM = SelectionManager . Selection . First as VM ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPagePhysicalStorage )
{
2014-01-22 13:39:32 +01:00
PhysicalStoragePage . SetSelectionBroadcaster ( SelectionManager , this ) ;
2013-08-22 18:25:12 +02:00
PhysicalStoragePage . Host = SelectionManager . Selection . First as Host ;
PhysicalStoragePage . Connection = SelectionManager . Selection . GetConnectionOfFirstItem ( ) ;
2013-06-24 13:41:48 +02:00
}
else if ( t = = TabPageAD )
{
2013-08-22 18:25:12 +02:00
AdPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
2013-06-24 13:41:48 +02:00
}
2013-11-14 12:06:50 +01:00
else if ( t = = TabPageGPU )
{
GpuPage . XenObject = SelectionManager . Selection . FirstAsXenObject ;
}
2015-02-06 11:03:42 +01:00
else if ( t = = TabPageDockerProcess )
{
2015-02-26 10:45:43 +01:00
DockerProcessPage . DockerContainer = SelectionManager . Selection . First as DockerContainer ;
2015-02-06 11:03:42 +01:00
}
2015-02-09 08:42:00 +01:00
else if ( t = = TabPageDockerDetails )
{
2015-02-26 10:45:43 +01:00
DockerDetailsPage . DockerContainer = SelectionManager . Selection . First as DockerContainer ;
2015-02-09 08:42:00 +01:00
}
2013-06-24 13:41:48 +02:00
}
if ( t = = TabPagePeformance )
PerformancePage . ResumeGraph ( ) ;
else
PerformancePage . PauseGraph ( ) ;
if ( t = = TabPageSearch )
SearchPage . PanelShown ( ) ;
else
SearchPage . PanelHidden ( ) ;
2015-02-09 08:42:00 +01:00
if ( t = = TabPageDockerDetails )
DockerDetailsPage . ResumeRefresh ( ) ;
else
DockerDetailsPage . PauseRefresh ( ) ;
2015-02-18 10:50:55 +01:00
if ( t = = TabPageDockerProcess )
DockerProcessPage . ResumeRefresh ( ) ;
else
DockerProcessPage . PauseRefresh ( ) ;
2013-06-24 13:41:48 +02:00
if ( t ! = null )
2013-08-22 18:25:12 +02:00
SetLastSelectedPage ( SelectionManager . Selection . First , t ) ;
2013-06-24 13:41:48 +02:00
}
private void UnpauseVNC ( bool focus )
{
ConsolePanel . UnpauseActiveView ( ) ;
if ( focus )
{
ConsolePanel . FocusActiveView ( ) ;
ConsolePanel . SwitchIfRequired ( ) ;
}
}
/// <summary>
/// The tabs that may be visible in the main GUI window. Used in SwitchToTab().
/// </summary>
public enum Tab
{
2015-02-09 08:42:00 +01:00
Overview , Home , Settings , Storage , Network , Console , Performance , NICs , SR , DockerProcess , DockerDetails
2013-06-24 13:41:48 +02:00
}
public void SwitchToTab ( Tab tab )
{
switch ( tab )
{
case Tab . Overview :
TheTabControl . SelectedTab = TabPageSearch ;
break ;
case Tab . Home :
TheTabControl . SelectedTab = TabPageHome ;
break ;
case Tab . Settings :
TheTabControl . SelectedTab = TabPageGeneral ;
break ;
case Tab . Storage :
TheTabControl . SelectedTab = TabPageStorage ;
break ;
case Tab . Network :
TheTabControl . SelectedTab = TabPageNetwork ;
break ;
case Tab . Console :
TheTabControl . SelectedTab = TabPageConsole ;
break ;
case Tab . Performance :
TheTabControl . SelectedTab = TabPagePeformance ;
break ;
case Tab . NICs :
TheTabControl . SelectedTab = TabPageNICs ;
break ;
case Tab . SR :
TheTabControl . SelectedTab = TabPageSR ;
break ;
2015-02-06 11:03:42 +01:00
case Tab . DockerProcess :
TheTabControl . SelectedTab = TabPageDockerProcess ;
break ;
2015-02-09 08:42:00 +01:00
case Tab . DockerDetails :
TheTabControl . SelectedTab = TabPageDockerDetails ;
break ;
2013-06-24 13:41:48 +02:00
default :
throw new NotImplementedException ( ) ;
}
}
private void templatesToolStripMenuItem1_Click ( object sender , EventArgs e )
{
templatesToolStripMenuItem1 . Checked = ! templatesToolStripMenuItem1 . Checked ;
2013-09-12 00:12:08 +02:00
Properties . Settings . Default . DefaultTemplatesVisible = templatesToolStripMenuItem1 . Checked ;
ViewSettingsChanged ( ) ;
2013-06-24 13:41:48 +02:00
}
private void customTemplatesToolStripMenuItem_Click ( object sender , EventArgs e )
{
customTemplatesToolStripMenuItem . Checked = ! customTemplatesToolStripMenuItem . Checked ;
2013-09-12 00:12:08 +02:00
Properties . Settings . Default . UserTemplatesVisible = customTemplatesToolStripMenuItem . Checked ;
ViewSettingsChanged ( ) ;
2013-06-24 13:41:48 +02:00
}
private void localStorageToolStripMenuItem_Click ( object sender , EventArgs e )
{
localStorageToolStripMenuItem . Checked = ! localStorageToolStripMenuItem . Checked ;
2013-09-12 00:12:08 +02:00
Properties . Settings . Default . LocalSRsVisible = localStorageToolStripMenuItem . Checked ;
ViewSettingsChanged ( ) ;
}
private void ShowHiddenObjectsToolStripMenuItem_Click ( object sender , EventArgs e )
{
ShowHiddenObjectsToolStripMenuItem . Checked = ! ShowHiddenObjectsToolStripMenuItem . Checked ;
Properties . Settings . Default . ShowHiddenVMs = ShowHiddenObjectsToolStripMenuItem . Checked ;
ViewSettingsChanged ( ) ;
}
private void ViewSettingsChanged ( )
{
2013-06-24 13:41:48 +02:00
Settings . TrySaveSettings ( ) ;
2013-09-12 00:12:08 +02:00
navigationPane . UpdateSearch ( ) ;
RequestRefreshTreeView ( ) ;
2013-06-24 13:41:48 +02:00
}
2013-08-24 18:00:32 +02:00
private void EditSelectedNodeInTreeView ( )
2013-06-24 13:41:48 +02:00
{
2013-08-26 12:42:32 +02:00
navigationPane . EditSelectedNode ( ) ;
2013-06-24 13:41:48 +02:00
}
protected override void OnClosing ( CancelEventArgs e )
{
bool currentTasks = false ;
foreach ( ActionBase a in ConnectionsManager . History )
{
2014-03-11 15:30:01 +01:00
if ( a is MeddlingAction | | a . IsCompleted )
continue ;
currentTasks = true ;
break ;
2013-06-24 13:41:48 +02:00
}
2013-10-09 14:33:06 +02:00
2013-06-24 13:41:48 +02:00
if ( currentTasks )
{
e . Cancel = true ;
2014-03-11 15:30:01 +01:00
if ( Program . RunInAutomatedTestMode | |
new Dialogs . WarningDialogs . CloseXenCenterWarningDialog ( ) . ShowDialog ( this ) = = DialogResult . OK )
2013-06-24 13:41:48 +02:00
{
this . Hide ( ) ;
// Close all open forms
List < Form > forms = new List < Form > ( ) ;
foreach ( Form form in Application . OpenForms )
{
if ( form ! = this )
{
forms . Add ( form ) ;
}
}
foreach ( Form form in forms )
{
form . Close ( ) ;
}
// Disconnect the named pipe
Program . DisconnectPipe ( ) ;
foreach ( ActionBase a in ConnectionsManager . History )
{
if ( ! Program . RunInAutomatedTestMode )
{
if ( a is AsyncAction )
{
AsyncAction aa = ( AsyncAction ) a ;
aa . PrepareForLogReloadAfterRestart ( ) ;
}
if ( ! a . IsCompleted & & a . CanCancel & & ! a . SafeToExit )
a . Cancel ( ) ;
}
else
{
if ( ! a . IsCompleted & & a . CanCancel )
a . Cancel ( ) ;
}
}
2014-03-11 15:30:01 +01:00
ThreadPool . QueueUserWorkItem ( CloseWhenActionsCanceled ) ;
2013-06-24 13:41:48 +02:00
}
return ;
}
// Disconnect the named pipe
Program . DisconnectPipe ( ) ;
Properties . Settings . Default . WindowSize = this . Size ;
Properties . Settings . Default . WindowLocation = this . Location ;
try
{
Settings . SaveServerList ( ) ;
Properties . Settings . Default . Save ( ) ;
}
catch ( ConfigurationErrorsException ex )
{
new ThreeButtonDialog (
new ThreeButtonDialog . Details (
SystemIcons . Error ,
string . Format ( Messages . MESSAGEBOX_SAVE_CORRUPTED , Settings . GetUserConfigPath ( ) ) ,
Messages . MESSAGEBOX_SAVE_CORRUPTED_TITLE ) ) . ShowDialog ( this ) ;
log . Error ( "Couldn't save settings" ) ;
log . Error ( ex , ex ) ;
}
base . OnClosing ( e ) ;
}
private void sendCtrlAltDelToolStripMenuItem_Click ( object sender , EventArgs e )
{
ConsolePanel . SendCAD ( ) ;
}
2014-01-22 13:39:32 +01:00
#region IMainWindowCommandInterface Members
2013-06-24 13:41:48 +02:00
/// <summary>
/// Closes all per-Connection and per-VM wizards for the given connection.
/// </summary>
/// <param name="connection"></param>
2014-01-22 13:39:32 +01:00
public void CloseActiveWizards ( IXenConnection connection )
2013-06-24 13:41:48 +02:00
{
Program . Invoke ( Program . MainWindow , delegate
{
// Close and remove any active wizards for any VMs
foreach ( VM vm in connection . Cache . VMs )
{
2014-01-22 13:39:32 +01:00
CloseActiveWizards ( vm ) ;
2013-06-24 13:41:48 +02:00
}
closeActivePoolWizards ( connection ) ;
} ) ;
}
/// <summary>
/// Closes all per-Connection wizards.
/// </summary>
/// <param name="connection"></param>
private void closeActivePoolWizards ( IXenConnection connection )
{
IList < Form > wizards ;
if ( activePoolWizards . TryGetValue ( connection , out wizards ) )
{
foreach ( var wizard in wizards )
{
if ( ! wizard . IsDisposed )
{
wizard . Close ( ) ;
}
}
activePoolWizards . Remove ( connection ) ;
}
}
/// <summary>
/// Closes all per-XenObject wizards.
/// </summary>
/// <param name="obj"></param>
2014-01-22 13:39:32 +01:00
public void CloseActiveWizards ( IXenObject obj )
2013-06-24 13:41:48 +02:00
{
Program . Invoke ( Program . MainWindow , delegate
{
Form wizard ;
if ( activeXenModelObjectWizards . TryGetValue ( obj , out wizard ) )
{
if ( ! wizard . IsDisposed )
{
wizard . Close ( ) ;
}
activeXenModelObjectWizards . Remove ( obj ) ;
}
} ) ;
}
/// <summary>
/// Show the given wizard, and impose a one-wizard-per-XenObject limit.
/// </summary>
/// <param name="obj">The relevant VM</param>
/// <param name="wizard">The new wizard to show</param>
public void ShowPerXenModelObjectWizard ( IXenObject obj , Form wizard )
{
2014-01-22 13:39:32 +01:00
CloseActiveWizards ( obj ) ;
2013-06-24 13:41:48 +02:00
activeXenModelObjectWizards . Add ( obj , wizard ) ;
wizard . Show ( this ) ;
}
/// <summary>
/// Show the given wizard, and impose a one-wizard-per-connection limit.
/// </summary>
/// <param name="connection">The connection. May be null, in which case the wizard
/// is not addded to any dictionary. This should happen iff this is the New Pool Wizard.</param>
/// <param name="wizard">The new wizard to show. May not be null.</param>
public void ShowPerConnectionWizard ( IXenConnection connection , Form wizard )
{
if ( connection ! = null )
{
if ( activePoolWizards . ContainsKey ( connection ) )
{
var w = activePoolWizards [ connection ] . Where ( x = > x . GetType ( ) = = wizard . GetType ( ) ) . FirstOrDefault ( ) ;
if ( w ! = null & & ! w . IsDisposed )
{
if ( w . WindowState = = FormWindowState . Minimized )
{
w . WindowState = FormWindowState . Normal ;
}
w . Focus ( ) ;
return ;
}
if ( w ! = null & & w . IsDisposed )
activePoolWizards [ connection ] . Remove ( w ) ;
}
//closeActivePoolWizards(connection);
if ( activePoolWizards . ContainsKey ( connection ) )
activePoolWizards [ connection ] . Add ( wizard ) ;
else
activePoolWizards . Add ( connection , new List < Form > ( ) { wizard } ) ;
}
if ( ! wizard . Disposing & & ! wizard . IsDisposed & & ! Program . Exiting )
{
wizard . Show ( this ) ;
}
}
/// <summary>
/// Shows a form of the specified type if it has already been created. If the form doesn't exist yet
/// it is created first and then shown.
/// </summary>
/// <param name="type">The type of the form to be shown.</param>
public void ShowForm ( Type type )
{
2013-08-21 18:13:23 +02:00
ShowForm ( type , null ) ;
}
/// <summary>
/// Shows a form of the specified type if it has already been created. If the form doesn't exist yet
/// it is created first and then shown.
/// </summary>
/// <param name="type">The type of the form to be shown.</param>
/// <param name="args">The arguments to pass to the form's consructor</param>
public void ShowForm ( Type type , object [ ] args )
{
2013-12-31 11:34:11 +01:00
foreach ( Form form in Application . OpenForms )
2013-06-24 13:41:48 +02:00
{
if ( form . GetType ( ) = = type )
{
HelpersGUI . BringFormToFront ( form ) ;
return ;
}
}
2013-08-21 18:13:23 +02:00
Form newForm = ( Form ) Activator . CreateInstance ( type , args ) ;
2013-06-24 13:41:48 +02:00
newForm . Show ( this ) ;
}
2014-01-22 13:39:32 +01:00
public Form Form
{
get { return this ; }
}
public void Invoke ( MethodInvoker method )
{
Program . Invoke ( this , method ) ;
}
public bool SelectObjectInTree ( IXenObject xenObject )
{
return SelectObject ( xenObject ) ;
}
public Collection < IXenConnection > GetXenConnectionsCopy ( )
{
return new Collection < IXenConnection > ( ConnectionsManager . XenConnectionsCopy ) ;
}
public void SaveServerList ( )
{
Settings . SaveServerList ( ) ;
}
public bool RunInAutomatedTestMode
{
get { return Program . RunInAutomatedTestMode ; }
}
public void RemoveConnection ( IXenConnection connection )
{
ConnectionsManager . ClearCacheAndRemoveConnection ( connection ) ;
}
public void PutSelectedNodeIntoEditMode ( )
{
EditSelectedNodeInTreeView ( ) ;
}
public void TrySelectNewObjectInTree ( Predicate < object > tagMatch , bool selectNode , bool expandNode , bool ensureNodeVisible )
{
TrySelectNewNode ( tagMatch , selectNode , expandNode , ensureNodeVisible ) ;
}
public void TrySelectNewObjectInTree ( IXenConnection c , bool selectNode , bool expandNode , bool ensureNodeVisible )
{
TrySelectNewNode ( c , selectNode , expandNode , ensureNodeVisible ) ;
}
public bool MenuShortcutsEnabled
{
get { return _menuShortcuts ; }
}
#endregion
2013-06-24 13:41:48 +02:00
#region Help
private string TabHelpID ( )
{
string modelObj = getSelectedXenModelObjectType ( ) ;
if ( TheTabControl . SelectedTab = = TabPageHome )
return "TabPageHome" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageSearch )
return "TabPageSearch" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageConsole )
return "TabPageConsole" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageGeneral )
return "TabPageSettings" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPagePhysicalStorage | | TheTabControl . SelectedTab = = TabPageStorage | | TheTabControl . SelectedTab = = TabPageSR )
return "TabPageStorage" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageNetwork )
return "TabPageNetwork" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageNICs )
return "TabPageNICs" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageWLB )
return "TabPageWLB" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPagePeformance )
return "TabPagePerformance" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageHA )
return "TabPageHA" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageHAUpsell )
return "TabPageHAUpsell" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageSnapshots )
return "TabPageSnapshots" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageBallooning )
return "TabPageBallooning" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageAD )
return "TabPageAD" + modelObj ;
if ( TheTabControl . SelectedTab = = TabPageBallooningUpsell )
return "TabPageBallooningUpsell" ;
if ( TheTabControl . SelectedTab = = TabPageWLBUpsell )
return "TabPageWLBUpsell" ;
2013-11-14 12:06:50 +01:00
if ( TheTabControl . SelectedTab = = TabPageGPU )
return "TabPageGPU" + modelObj ;
2015-02-06 11:03:42 +01:00
if ( TheTabControl . SelectedTab = = TabPageDockerProcess )
return "TabPageDockerProcess" + modelObj ;
2015-02-09 08:42:00 +01:00
if ( TheTabControl . SelectedTab = = TabPageDockerDetails )
return "TabPageDockerDetails" + modelObj ;
2013-06-24 13:41:48 +02:00
return "TabPageUnknown" ;
}
private string getSelectedXenModelObjectType ( )
{
// for now, since there are few topics which depend on the selected object we shall just check the special cases
// when more topic are added we can just return the ModelObjectName
2013-08-22 18:25:12 +02:00
if ( TheTabControl . SelectedTab = = TabPageGeneral & & SelectionManager . Selection . First is VM )
2013-06-24 13:41:48 +02:00
{
return "VM" ;
}
if ( TheTabControl . SelectedTab = = TabPagePhysicalStorage | | TheTabControl . SelectedTab = = TabPageStorage | | TheTabControl . SelectedTab = = TabPageSR )
{
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsPool )
2013-06-24 13:41:48 +02:00
return "Pool" ;
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsHost )
2013-06-24 13:41:48 +02:00
return "Server" ;
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsVM )
2013-06-24 13:41:48 +02:00
return "VM" ;
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsSR )
2013-06-24 13:41:48 +02:00
return "Storage" ;
}
if ( TheTabControl . SelectedTab = = TabPageNetwork )
{
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsHost )
2013-06-24 13:41:48 +02:00
return "Server" ;
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . FirstIsVM )
2013-06-24 13:41:48 +02:00
return "VM" ;
}
return "" ;
}
public void ShowHelpTOC ( )
{
ShowHelpTopic ( null ) ;
}
public void ShowHelpTopic ( string topicID )
{
2016-01-28 10:35:51 +01:00
// Abandon all hope, ye who enter here: if you're ever tempted to directly invoke hh.exe, see first:
// JAXC-43: Online help doesn't work if install XenCenter into the path that contains special characters.
// hh.exe can't seem to cope with certain multi-byte characters in the path to the chm.
// System.Windows.Forms.Help.ShowHelp() can cope with the special characters in the path, but has the
// irritating behaviour that the launched help is always on top of the app window (CA-8863).
// So we show the help 'on top' of an invisible dummy Form.
using ( var helpForm = new Form ( ) )
{
string chm = Path . Combine ( Program . AssemblyDir , InvisibleMessages . MAINWINDOW_HELP_PATH ) ;
if ( topicID = = null )
{
// Show TOC
System . Windows . Forms . Help . ShowHelp ( helpForm , chm , HelpNavigator . TableOfContents ) ;
}
else
{
System . Windows . Forms . Help . ShowHelp ( helpForm , chm , HelpNavigator . TopicId , topicID ) ;
}
}
2013-06-24 13:41:48 +02:00
}
public void MainWindow_HelpRequested ( object sender , HelpEventArgs hlpevent )
{
// CA-28064. MessageBox hack to kill the hlpevent it passes to MainWindows.
if ( Program . MainWindow . ContainsFocus & & _menuShortcuts )
LaunchHelp ( ) ;
}
private void helpTopicsToolStripMenuItem_Click ( object sender , EventArgs e )
{
ShowHelpTOC ( ) ;
}
private void helpContextMenuItem_Click ( object sender , EventArgs e )
{
LaunchHelp ( ) ;
}
private void LaunchHelp ( )
{
2013-11-05 15:40:16 +01:00
if ( alertPage . Visible )
Help . HelpManager . Launch ( "AlertSummaryDialog" ) ;
else if ( updatesPage . Visible )
Help . HelpManager . Launch ( "ManageUpdatesDialog" ) ;
else if ( eventsPage . Visible )
Help . HelpManager . Launch ( "EventsPane" ) ;
2013-06-24 13:41:48 +02:00
else
2013-11-05 15:40:16 +01:00
{
if ( TheTabControl . SelectedTab . Tag is TabPageFeature & & ( ( TabPageFeature ) TheTabControl . SelectedTab . Tag ) . HasHelp )
( ( TabPageFeature ) TheTabControl . SelectedTab . Tag ) . LaunchHelp ( ) ;
else
Help . HelpManager . Launch ( TabHelpID ( ) ) ;
}
2013-06-24 13:41:48 +02:00
}
public bool HasHelp ( )
{
return Help . HelpManager . HasHelpFor ( TabHelpID ( ) ) ;
}
private void viewApplicationLogToolStripMenuItem_Click ( object sender , EventArgs e )
{
Program . ViewLogFiles ( ) ;
}
#endregion
/// <summary>
/// Used to select the pool or standalone host node for the specified connection which is about to appear in the tree.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="selectNode">if set to <c>true</c> then the pool/standalone host node will be selected.</param>
/// <param name="expandNode">if set to <c>true</c> then the pool/standalone host node will be expanded.</param>
/// <param name="ensureNodeVisible">if set to <c>true</c> then the matched node will be made visible.</param>
public void TrySelectNewNode ( IXenConnection connection , bool selectNode , bool expandNode , bool ensureNodeVisible )
{
if ( connection ! = null )
{
TrySelectNewNode ( delegate ( object o )
{
if ( o = = null )
{
return false ;
}
else if ( o . Equals ( Helpers . GetPool ( connection ) ) )
{
return true ;
}
Host [ ] hosts = connection . Cache . Hosts ;
return hosts . Length > 0 & & o . Equals ( hosts [ 0 ] ) ;
} , selectNode , expandNode , ensureNodeVisible ) ;
}
}
/// <summary>
/// Used to select or expand a node which is about to appear in the tree. This is used so that new hosts, folders, pools
/// etc. can be picked and then selected/expanded.
///
/// It fires off a new thread and then repeatedly tries to select a node which matches the specified match
/// delegate. It stops if it times out or is successful.
/// </summary>
/// <param name="tagMatch">A match for the tag of the node.</param>
/// <param name="selectNode">if set to <c>true</c> then the matched node will be selected.</param>
/// <param name="expandNode">if set to <c>true</c> then the matched node will be expanded.</param>
/// <param name="ensureNodeVisible">if set to <c>true</c> then the matched node will be made visible.</param>
public void TrySelectNewNode ( Predicate < object > tagMatch , bool selectNode , bool expandNode , bool ensureNodeVisible )
{
ThreadPool . QueueUserWorkItem ( delegate
{
bool success = false ;
for ( int i = 0 ; i < 20 & & ! success ; i + + )
{
Program . Invoke ( Program . MainWindow , delegate
2013-08-24 18:00:32 +02:00
{
2013-08-26 12:42:32 +02:00
success = navigationPane . TryToSelectNewNode ( tagMatch , selectNode , expandNode , ensureNodeVisible ) ;
2013-08-24 18:00:32 +02:00
} ) ;
2013-06-24 13:41:48 +02:00
Thread . Sleep ( 500 ) ;
}
} ) ;
}
/// <summary>
/// Selects the specified object in the treeview.
/// </summary>
/// <param name="o">The object to be selected.</param>
/// <returns>A value indicating whether selection was successful.</returns>
public bool SelectObject ( IXenObject o )
{
2013-08-26 12:42:32 +02:00
return navigationPane . SelectObject ( o ) ;
2013-06-24 13:41:48 +02:00
}
2013-11-18 15:31:00 +01:00
private void eventsPage_GoToXenObjectRequested ( IXenObject obj )
{
navigationPane . SwitchToInfrastructureMode ( ) ;
navigationPane . SelectObject ( obj ) ;
}
2013-12-05 13:46:39 +01:00
private void Updates_CollectionChanged ( object sender , CollectionChangeEventArgs e )
2013-11-19 16:42:47 +01:00
{
2013-12-05 13:46:39 +01:00
Program . Invoke ( this , ( ) = >
{
int updatesCount = Updates . UpdateAlertsCount ;
navigationPane . UpdateNotificationsButton ( NotificationsSubMode . Updates , updatesCount ) ;
2013-11-19 16:42:47 +01:00
2013-12-05 13:46:39 +01:00
if ( updatesPage . Visible )
{
TitleLabel . Text = NotificationsSubModeItem . GetText ( NotificationsSubMode . Updates , updatesCount ) ;
TitleIcon . Image = NotificationsSubModeItem . GetImage ( NotificationsSubMode . Updates , updatesCount ) ;
}
} ) ;
2013-11-19 16:42:47 +01:00
}
2013-06-24 13:41:48 +02:00
private void CloseWhenActionsCanceled ( object o )
{
int i = 0 ;
while ( true )
{
if ( i > 20 )
Program . ForcedExiting = true ;
if ( i > 40 | | AllActionsCompleted ( ) )
{
Program . Invoke ( this , Application . Exit ) ;
break ;
}
i + + ;
System . Threading . Thread . Sleep ( 500 ) ;
}
}
private bool AllActionsCompleted ( )
{
foreach ( ActionBase a in ConnectionsManager . History )
{
if ( ! a . IsCompleted )
return false ;
}
return true ;
}
private void preferencesToolStripMenuItem_Click ( object sender , EventArgs e )
{
OptionsDialog dialog = new OptionsDialog ( pluginManager ) ;
dialog . ShowDialog ( this ) ;
}
2013-08-05 15:28:21 +02:00
internal void action_Completed ( ActionBase sender )
2013-06-24 13:41:48 +02:00
{
if ( Program . Exiting )
{
return ;
}
RequestRefreshTreeView ( ) ;
2013-08-05 15:28:21 +02:00
//Update toolbars, since if an action has just completed, various
//buttons may need to be re-enabled. Applies to:
// HostAction
// EnableHAAction
// DisableHAAction
Program . Invoke ( this , UpdateToolbars ) ;
2013-06-24 13:41:48 +02:00
}
internal void OpenGlobalImportWizard ( string param )
{
HelpersGUI . BringFormToFront ( this ) ;
2013-08-22 18:25:12 +02:00
Host hostAncestor = SelectionManager . Selection . Count = = 1 ? SelectionManager . Selection [ 0 ] . HostAncestor : null ;
new ImportWizard ( SelectionManager . Selection . GetConnectionOfFirstItem ( ) , hostAncestor , param , false ) . Show ( ) ;
2013-06-24 13:41:48 +02:00
}
internal void InstallUpdate ( string path )
{
var wizard = new PatchingWizard ( ) ;
wizard . Show ( this ) ;
wizard . NextStep ( ) ;
wizard . AddFile ( path ) ;
}
#region XenSearch
// SearchMode doesn't just mean we are looking at the Search tab.
// It's set when we import a search from a file; or when we double-click
// on a folder or tag name to search for it.
private bool searchMode = false ;
public bool SearchMode
{
get
{
return searchMode ;
}
set
{
if ( searchMode = = value )
return ;
searchMode = value ;
2013-08-26 12:42:32 +02:00
navigationPane . InSearchMode = value ;
2013-06-24 13:41:48 +02:00
UpdateToolbarsCore ( ) ;
}
}
2014-01-22 13:39:32 +01:00
public bool DoSearch ( string filename )
2013-06-24 13:41:48 +02:00
{
List < Search > searches = Search . LoadFile ( filename ) ;
if ( searches ! = null & & searches . Count > 0 )
{
Program . Invoke ( Program . MainWindow , delegate ( )
{
DoSearch ( searches [ 0 ] ) ;
} ) ;
return true ;
}
return false ;
}
public void DoSearch ( Search search )
{
History . NewHistoryItem ( new SearchHistoryItem ( search ) ) ;
SearchMode = true ;
SearchPage . Search = search ;
UpdateHeader ( ) ;
}
public void SearchForTag ( string tag )
{
DoSearch ( Search . SearchForTag ( tag ) ) ;
}
public void SearchForFolder ( string path )
{
DoSearch ( Search . SearchForFolder ( path ) ) ;
}
2013-08-01 13:49:11 +02:00
void SearchPanel_SearchChanged ( )
2013-06-24 13:41:48 +02:00
{
if ( SearchMode )
History . ReplaceHistoryItem ( new SearchHistoryItem ( SearchPage . Search ) ) ;
else
History . ReplaceHistoryItem ( new ModifiedSearchHistoryItem (
2013-08-22 18:25:12 +02:00
SelectionManager . Selection . FirstAsXenObject , SearchPage . Search ) ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Updates the shiny gradient bar with selected object name and icon.
/// Also updates 'Logged in as:'.
/// </summary>
private void UpdateHeader ( )
{
2014-10-01 18:43:03 +02:00
if ( navigationPane . currentMode = = NavigationPane . NavigationMode . Notifications )
2013-11-07 11:00:53 +01:00
return ;
2013-06-24 13:41:48 +02:00
if ( SearchMode & & SearchPage . Search ! = null )
{
TitleLabel . Text = HelpersGUI . GetLocalizedSearchName ( SearchPage . Search ) ;
TitleIcon . Image = Images . GetImage16For ( SearchPage . Search ) ;
}
2013-08-22 18:25:12 +02:00
else if ( ! SearchMode & & SelectionManager . Selection . ContainsOneItemOfType < IXenObject > ( ) )
2013-06-24 13:41:48 +02:00
{
2013-08-22 18:25:12 +02:00
IXenObject xenObject = SelectionManager . Selection [ 0 ] . XenObject ;
2015-01-14 17:20:36 +01:00
TitleLabel . Text = xenObject . NameWithLocation ;
2013-06-24 13:41:48 +02:00
TitleIcon . Image = Images . GetImage16For ( xenObject ) ;
// When in folder view only show the logged in label if it is clear to which connection the object belongs (most likely pools and hosts)
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection [ 0 ] . PoolAncestor = = null & & SelectionManager . Selection [ 0 ] . HostAncestor = = null )
2013-06-24 13:41:48 +02:00
loggedInLabel1 . Connection = null ;
else
loggedInLabel1 . Connection = xenObject . Connection ;
}
else
{
TitleLabel . Text = Messages . XENCENTER ;
TitleIcon . Image = Properties . Resources . Logo ;
loggedInLabel1 . Connection = null ;
}
}
2013-10-09 10:13:47 +02:00
private void UpdateViewMenu ( NavigationPane . NavigationMode mode )
{
//the order is the reverse from the order in which we want them to appear
var items = new ToolStripItem [ ]
{
toolStripSeparator24 ,
ShowHiddenObjectsToolStripMenuItem ,
localStorageToolStripMenuItem ,
templatesToolStripMenuItem1 ,
customTemplatesToolStripMenuItem
} ;
if ( mode = = NavigationPane . NavigationMode . Infrastructure )
{
foreach ( var item in items )
{
if ( ! viewToolStripMenuItem . DropDownItems . Contains ( item ) )
viewToolStripMenuItem . DropDownItems . Insert ( 0 , item ) ;
}
}
else if ( mode = = NavigationPane . NavigationMode . Notifications )
{
foreach ( var item in items )
viewToolStripMenuItem . DropDownItems . Remove ( item ) ;
}
else
{
for ( int i = 2 ; i < items . Length ; i + + )
viewToolStripMenuItem . DropDownItems . Remove ( items [ i ] ) ;
for ( int i = 0 ; i < 2 ; i + + )
if ( ! viewToolStripMenuItem . DropDownItems . Contains ( items [ i ] ) )
viewToolStripMenuItem . DropDownItems . Insert ( 0 , items [ i ] ) ;
}
pluginMenuItemStartIndexes [ viewToolStripMenuItem ] = viewToolStripMenuItem . DropDownItems . IndexOf ( toolStripSeparator24 ) + 1 ;
}
2013-11-12 13:44:19 +01:00
void navigationPane_DragDropCommandActivated ( string cmdText )
{
SetStatusBar ( null , cmdText ) ;
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeViewSelectionChanged ( )
2013-08-24 18:00:32 +02:00
{
UpdateToolbars ( ) ;
//
// NB do not trigger updates to the panels in this method
// instead, put them in TheTabControl_SelectedIndexChanged,
// so only the selected tab is updated
//
TheTabControl_SelectedIndexChanged ( null , EventArgs . Empty ) ;
if ( TheTabControl . SelectedTab ! = null )
TheTabControl . SelectedTab . Refresh ( ) ;
UpdateHeader ( ) ;
}
2013-11-07 11:00:53 +01:00
private void navigationPane_NotificationsSubModeChanged ( NotificationsSubModeItem submodeItem )
2013-08-30 16:19:59 +02:00
{
2013-11-07 11:00:53 +01:00
alertPage . Visible = submodeItem . SubMode = = NotificationsSubMode . Alerts ;
updatesPage . Visible = submodeItem . SubMode = = NotificationsSubMode . Updates ;
eventsPage . Visible = submodeItem . SubMode = = NotificationsSubMode . Events ;
2013-11-19 16:42:47 +01:00
TheTabControl . Visible = false ;
2013-08-30 16:19:59 +02:00
if ( alertPage . Visible )
alertPage . RefreshAlertList ( ) ;
if ( updatesPage . Visible )
2013-12-05 13:46:39 +01:00
updatesPage . RefreshUpdateList ( ) ;
2013-09-02 15:45:42 +02:00
if ( eventsPage . Visible )
{
eventsPage . RefreshDisplayedEvents ( ) ;
}
2013-11-07 11:00:53 +01:00
loggedInLabel1 . Connection = null ;
TitleLabel . Text = submodeItem . Text ;
TitleIcon . Image = submodeItem . Image ;
2013-08-30 16:19:59 +02:00
}
2013-08-30 14:35:32 +02:00
private void navigationPane_NavigationModeChanged ( NavigationPane . NavigationMode mode )
{
if ( mode = = NavigationPane . NavigationMode . Notifications )
{
TheTabControl . Visible = false ;
}
else
{
2014-06-30 17:38:48 +02:00
bool tabControlWasVisible = TheTabControl . Visible ;
2013-08-30 14:35:32 +02:00
TheTabControl . Visible = true ;
2013-09-02 15:45:42 +02:00
alertPage . Visible = updatesPage . Visible = eventsPage . Visible = false ;
2014-06-30 17:38:48 +02:00
// force an update of the selected tab when switching back from Notification view,
// as some tabs ignore the update events when not visible (e.g. Snapshots, HA)
if ( ! tabControlWasVisible )
TheTabControl_SelectedIndexChanged ( null , null ) ;
2013-08-30 14:35:32 +02:00
}
2013-10-09 10:13:47 +02:00
UpdateViewMenu ( mode ) ;
2013-08-30 14:35:32 +02:00
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeNodeBeforeSelected ( )
2013-08-24 18:00:32 +02:00
{
SearchMode = false ;
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeNodeClicked ( )
2013-08-24 18:00:32 +02:00
{
if ( SearchMode )
{
SearchMode = false ;
TheTabControl_SelectedIndexChanged ( null , null ) ;
UpdateHeader ( ) ;
}
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeNodeRightClicked ( )
2013-08-24 18:00:32 +02:00
{
MainMenuBar_MenuActivate ( MainMenuBar , new EventArgs ( ) ) ;
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeViewRefreshed ( )
2013-08-24 18:00:32 +02:00
{
UpdateHeaderAndTabPages ( ) ;
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeViewRefreshResumed ( )
2013-08-24 18:00:32 +02:00
{
ignoreUpdateToolbars - - ;
if ( ignoreUpdateToolbars = = 0 & & calledUpdateToolbars )
UpdateToolbars ( ) ;
}
2013-08-26 12:42:32 +02:00
private void navigationPane_TreeViewRefreshSuspended ( )
2013-08-24 18:00:32 +02:00
{
if ( ignoreUpdateToolbars = = 0 )
calledUpdateToolbars = false ;
ignoreUpdateToolbars + + ;
}
2013-06-24 13:41:48 +02:00
#endregion
void XenCenterAlerts_CollectionChanged ( object sender , CollectionChangeEventArgs e )
{
2013-11-19 16:42:47 +01:00
Program . BeginInvoke ( Program . MainWindow , ( ) = >
{
navigationPane . UpdateNotificationsButton (
NotificationsSubMode . Alerts , Alert . NonDismissingAlertCount ) ;
if ( alertPage . Visible )
{
TitleLabel . Text = NotificationsSubModeItem . GetText ( NotificationsSubMode . Alerts , Alert . NonDismissingAlertCount ) ;
TitleIcon . Image = NotificationsSubModeItem . GetImage ( NotificationsSubMode . Alerts , Alert . NonDismissingAlertCount ) ;
}
} ) ;
2013-06-24 13:41:48 +02:00
}
private void backButton_Click ( object sender , EventArgs e )
{
History . Back ( 1 ) ;
}
private void forwardButton_Click ( object sender , EventArgs e )
{
History . Forward ( 1 ) ;
}
private void backButton_DropDownOpening ( object sender , EventArgs e )
{
ToolStripSplitButton button = sender as ToolStripSplitButton ;
if ( button = = null )
return ;
History . PopulateBackDropDown ( button ) ;
}
private void forwardButton_DropDownOpening ( object sender , EventArgs e )
{
ToolStripSplitButton button = sender as ToolStripSplitButton ;
if ( button = = null )
return ;
History . PopulateForwardDropDown ( button ) ;
}
private void LicenseManagerMenuItem_Click ( object sender , EventArgs e )
{
2013-08-22 18:25:12 +02:00
licenseManagerLauncher . LaunchIfRequired ( false , ConnectionsManager . XenConnections , SelectionManager . Selection ) ;
2013-06-24 13:41:48 +02:00
}
private void MainWindow_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . KeyCode = = Keys . F5 )
{
RequestRefreshTreeView ( ) ;
if ( TheTabControl . SelectedTab = = TabPageSearch )
SearchPage . PanelProd ( ) ;
}
}
private void ShowToolbarMenuItem_Click ( object sender , EventArgs e )
{
ToolbarsEnabled = ! ToolbarsEnabled ;
Properties . Settings . Default . ToolbarsEnabled = ToolbarsEnabled ;
UpdateToolbars ( ) ;
}
private void MainMenuBar_MouseClick ( object sender , MouseEventArgs e )
{
if ( e . Button = = MouseButtons . Right )
{
ToolBarContextMenu . Show ( Program . MainWindow , e . Location ) ;
}
}
/// <summary>
/// Equivalent to MainController.Confirm(conn, this, msg, args).
/// </summary>
public bool Confirm ( IXenConnection conn , string title , string msg , params object [ ] args )
{
return Confirm ( conn , this , title , msg , args ) ;
}
/// <summary>
/// Show a MessageBox asking to confirm an operation. The MessageBox will be parented to the given Control.
/// Displays default "Yes" and "No" buttons ("Yes" button is selected by default).
/// The args given will be ellipsised to Helpers.DEFAULT_NAME_TRIM_LENGTH, if they are strings.
/// If in automated test mode, then always returns true.
/// If the user refuses the operation, then returns false.
/// If the given connection has disconnected in the time it takes the user to confirm,
/// then shows an information MessageBox, and returns false.
/// Otherwise, the user has agreed and the connection is still alive, so
/// sets MainWindow.AllowHistorySwitch to true and returns true.
/// </summary>
public static bool Confirm ( IXenConnection conn , Control parent , string title , string msg , params object [ ] args )
{
return Confirm ( conn , parent , title , null , null , null , msg , args ) ;
}
/// <summary>
/// Show a MessageBox asking to confirm an operation. The MessageBox will be parented to the given Control.
/// "Yes" and "No" buttons can be customized.
/// The args given will be ellipsised to Helpers.DEFAULT_NAME_TRIM_LENGTH, if they are strings.
/// If in automated test mode, then always returns true.
/// If the user refuses the operation, then returns false.
/// If the given connection has disconnected in the time it takes the user to confirm,
/// then shows an information MessageBox, and returns false.
/// Otherwise, the user has agreed and the connection is still alive, so
/// sets MainWindow.AllowHistorySwitch to true and returns true.
/// </summary>
public static bool Confirm ( IXenConnection conn , Control parent , string title ,
string helpName , ThreeButtonDialog . TBDButton buttonYes , ThreeButtonDialog . TBDButton buttonNo ,
string msg , params object [ ] args )
{
if ( Program . RunInAutomatedTestMode )
return true ;
Trim ( args ) ;
var buttons = new [ ]
{
buttonYes ? ? ThreeButtonDialog . ButtonYes ,
buttonNo ? ? ThreeButtonDialog . ButtonNo
} ;
var details = new ThreeButtonDialog . Details ( SystemIcons . Exclamation ,
args . Length = = 0 ? msg : string . Format ( msg , args ) , title ) ;
var dialog = String . IsNullOrEmpty ( helpName )
? new ThreeButtonDialog ( details , buttons )
: new ThreeButtonDialog ( details , helpName , buttons ) ;
if ( dialog . ShowDialog ( parent ? ? Program . MainWindow ) ! = DialogResult . Yes )
return false ;
if ( conn ! = null & & ! conn . IsConnected )
{
ShowDisconnectedMessage ( parent ) ;
return false ;
}
return true ;
}
/// <summary>
/// Show a message telling the user that the connection has disappeared. We check this after
/// we've shown a dialog, in case it's happened in the time it took them to click OK.
/// </summary>
public static void ShowDisconnectedMessage ( Control parent )
{
// We could have done some teardown by now, so we need to be paranoid about things going away
// beneath us.
if ( Program . Exiting )
return ;
if ( parent = = null | | parent . Disposing | | parent . IsDisposed )
{
parent = Program . MainWindow ;
if ( parent . Disposing | | parent . IsDisposed )
return ;
}
new ThreeButtonDialog (
new ThreeButtonDialog . Details (
SystemIcons . Warning ,
Messages . DISCONNECTED_BEFORE_ACTION_STARTED ,
Messages . XENCENTER ) ) . ShowDialog ( parent ) ;
}
private static void Trim ( object [ ] args )
{
int n = args . Length ;
for ( int i = 0 ; i < n ; i + + )
{
if ( args [ i ] is string )
args [ i ] = ( ( string ) args [ i ] ) . Ellipsise ( Helpers . DEFAULT_NAME_TRIM_LENGTH ) ;
}
}
#region ISynchronizeInvoke Members
// this explicit implementation of ISynchronizeInvoke is used to allow the model to update
// its API on the main program thread while being decoupled from MainWindow.
IAsyncResult ISynchronizeInvoke . BeginInvoke ( Delegate method , object [ ] args )
{
return Program . BeginInvoke ( this , method , args ) ;
}
object ISynchronizeInvoke . EndInvoke ( IAsyncResult result )
{
return EndInvoke ( result ) ;
}
object ISynchronizeInvoke . Invoke ( Delegate method , object [ ] args )
{
return Program . Invoke ( this , method , args ) ;
}
bool ISynchronizeInvoke . InvokeRequired
{
get { return InvokeRequired ; }
}
#endregion
private void importSettingsToolStripMenuItem_Click ( object sender , EventArgs e )
{
using ( OpenFileDialog dialog = new OpenFileDialog ( ) )
{
dialog . Filter = Messages . XENCENTER_CONFIG_FILTER ;
if ( dialog . ShowDialog ( this ) ! = DialogResult . Cancel )
{
try
{
log . InfoFormat ( "Importing server list from '{0}'" , dialog . FileName ) ;
XmlDocument xmlDocument = new XmlDocument ( ) ;
using ( var stream = dialog . OpenFile ( ) )
xmlDocument . Load ( stream ) ;
foreach ( XmlNode itemConnection in xmlDocument . GetElementsByTagName ( "XenConnection" ) )
{
var conn = new XenConnection ( ) ;
foreach ( XmlNode item in itemConnection . ChildNodes )
{
switch ( item . Name )
{
case "Hostname" :
conn . Hostname = item . InnerText ;
break ;
case "Port" :
conn . Port = int . Parse ( item . InnerText ) ;
break ;
case "FriendlyName" :
conn . FriendlyName = item . InnerText ;
break ;
}
}
if ( null = = ConnectionsManager . XenConnections . Find ( existing = > ( existing . Hostname = = conn . Hostname & & existing . Port = = conn . Port ) ) )
ConnectionsManager . XenConnections . Add ( conn ) ;
2013-08-25 15:06:03 +02:00
RequestRefreshTreeView ( ) ;
2013-06-24 13:41:48 +02:00
}
log . InfoFormat ( "Imported server list from '{0}' successfully." , dialog . FileName ) ;
}
catch ( XmlException )
{
log . ErrorFormat ( "Failed to import server list from '{0}'" , dialog . FileName ) ;
new ThreeButtonDialog (
new ThreeButtonDialog . Details ( SystemIcons . Error , Messages . ERRO_IMPORTING_SERVER_LIST , Messages . XENCENTER ) )
. ShowDialog ( this ) ;
}
}
}
}
private void exportSettingsToolStripMenuItem_Click ( object sender , EventArgs e )
{
using ( SaveFileDialog dialog = new SaveFileDialog ( ) )
{
dialog . Filter = Messages . XENCENTER_CONFIG_FILTER ;
dialog . Title = Messages . ACTION_SAVE_CHANGES_IN_PROGRESS ;
dialog . CheckPathExists = true ;
if ( dialog . ShowDialog ( this ) ! = DialogResult . Cancel )
{
log . InfoFormat ( "Exporting server list to '{0}'" , dialog . FileName ) ;
try
{
using ( var xmlWriter = new XmlTextWriter ( dialog . OpenFile ( ) , Encoding . Unicode ) )
{
xmlWriter . WriteStartDocument ( ) ;
xmlWriter . WriteStartElement ( "XenConnections" ) ;
xmlWriter . WriteWhitespace ( "\n" ) ;
foreach ( var connection in ConnectionsManager . XenConnections )
{
xmlWriter . WriteStartElement ( "XenConnection" ) ;
{
xmlWriter . WriteElementString ( "Hostname" , connection . Hostname ) ;
xmlWriter . WriteElementString ( "Port" , connection . Port . ToString ( ) ) ;
xmlWriter . WriteWhitespace ( "\n " ) ;
xmlWriter . WriteElementString ( "FriendlyName" , connection . FriendlyName ) ;
}
xmlWriter . WriteEndElement ( ) ;
xmlWriter . WriteWhitespace ( "\n" ) ;
}
xmlWriter . WriteEndElement ( ) ;
xmlWriter . WriteEndDocument ( ) ;
}
log . InfoFormat ( "Exported server list to '{0}' successfully." , dialog . FileName ) ;
}
catch
{
log . ErrorFormat ( "Failed to export server list to '{0}'." , dialog . FileName ) ;
throw ;
}
}
}
}
private void MainWindow_Load ( object sender , EventArgs e )
{
SetSplitterDistance ( ) ;
}
private void MainWindow_Resize ( object sender , EventArgs e )
{
SetSplitterDistance ( ) ;
}
private void SetSplitterDistance ( )
{
//CA-71697: chosen min size so the tab contents are visible
2014-07-10 13:04:32 +02:00
int chosenPanel2MinSize = MinimumSize . Width / 2 ;
2013-06-24 13:41:48 +02:00
int min = splitContainer1 . Panel1MinSize ;
int max = splitContainer1 . Width - chosenPanel2MinSize ;
if ( max < min )
return ;
splitContainer1 . Panel2MinSize = chosenPanel2MinSize ;
if ( splitContainer1 . SplitterDistance < min )
splitContainer1 . SplitterDistance = min ;
else if ( splitContainer1 . SplitterDistance > max )
splitContainer1 . SplitterDistance = max ;
}
}
}