2013-06-24 13:41:48 +02:00
/ * Copyright ( c ) Citrix Systems Inc .
* All rights reserved .
*
* Redistribution and use in source and binary forms ,
* with or without modification , are permitted provided
* that the following conditions are met :
*
* * Redistributions of source code must retain the above
* copyright notice , this list of conditions and the
* following disclaimer .
* * Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the
* following disclaimer in the documentation and / or other
* materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ,
* INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
* /
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.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 XenAdmin.Network.StorageLink ;
using System.Linq ;
[assembly: UIPermission(SecurityAction.RequestMinimum, Clipboard = UIPermissionClipboard.AllClipboard)]
namespace XenAdmin
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[ComVisibleAttribute(true)]
public partial class MainWindow : Form , ISynchronizeInvoke
{
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 ( ) ;
private bool IgnoreTabChanges = false ;
2013-09-02 15:45:42 +02:00
public bool AllowHistorySwitch
{
set
{
if ( value )
2013-09-12 00:12:08 +02:00
navigationPane . SwitchToNotificationsView ( NotificationsSubMode . Events ) ;
2013-09-02 15:45:42 +02:00
}
}
2013-06-24 13:41:48 +02:00
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 MainWindowCommandInterface commandInterface ;
private readonly LicenseManagerLauncher licenseManagerLauncher ;
private readonly LicenseTimer licenseTimer ;
private Dictionary < ToolStripMenuItem , int > pluginMenuItemStartIndexes = new Dictionary < ToolStripMenuItem , int > ( ) ;
public MainWindow ( ArgType argType , string [ ] args )
{
Program . MainWindow = this ;
licenseManagerLauncher = new LicenseManagerLauncher ( Program . MainWindow ) ;
InvokeHelper . Initialize ( this ) ;
InitializeComponent ( ) ;
SetMenuItemStartIndexes ( ) ;
Icon = Properties . Resources . AppIcon ;
components . Add ( SearchPage ) ;
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 ) ;
AddTabContents ( SearchPage , TabPageSearch ) ;
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 ) ;
TheTabControl . SelectedIndexChanged + = TheTabControl_SelectedIndexChanged ;
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 ;
commandInterface = new MainWindowCommandInterface ( this ) ;
pluginManager = new PluginManager ( ) ;
pluginManager . LoadPlugins ( ) ;
contextMenuBuilder = new ContextMenuBuilder ( pluginManager , commandInterface ) ;
SearchPage . SearchChanged + = SearchPanel_SearchChanged ;
Alert . XenCenterAlerts . CollectionChanged + = XenCenterAlerts_CollectionChanged ;
FormFontFixer . Fix ( this ) ;
Folders . InitFolders ( ) ;
OtherConfigAndTagsWatcher . InitEventHandlers ( ) ;
// Fix colour of text on gradient panels
TitleLabel . ForeColor = Program . TitleBarForeColor ;
loggedInLabel1 . SetTextColor ( Program . TitleBarForeColor ) ;
2013-08-22 18:25:12 +02:00
SelectionManager . BindTo ( MainMenuBar . Items , commandInterface ) ;
SelectionManager . BindTo ( ToolStrip . Items , commandInterface ) ;
Properties . Settings . Default . SettingChanging + = Default_SettingChanging ;
2013-06-24 13:41:48 +02:00
licenseTimer = new LicenseTimer ( licenseManagerLauncher ) ;
GeneralPage . LicenseLauncher = licenseManagerLauncher ;
}
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 )
{
ToolStripMenuItem menuItem = item as ToolStripMenuItem ;
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 ;
}
}
internal IMainWindow CommandInterface
{
get
{
return commandInterface ;
}
}
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-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 , ( ) = >
{
ActionBase action = ( ActionBase ) e . Element ;
if ( action = = null )
return ;
2013-08-07 12:09:35 +02:00
action . Changed + = actionChanged ;
action . Completed + = actionChanged ;
actionChanged ( action ) ;
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 )
{
// Be defensive against CA-8517.
if ( action . PercentComplete < 0 | | action . PercentComplete > 100 )
{
log . ErrorFormat ( "PercentComplete is erroneously {0}" , action . PercentComplete ) ;
}
// Don't show cancelled exception
if ( action . Exception ! = null & & ! ( action . Exception is CancelledException ) )
{
2013-09-02 15:45:42 +02:00
IXenObject model =
2013-06-24 13:41:48 +02:00
( IXenObject ) action . VM ? ?
( IXenObject ) action . Host ? ?
( IXenObject ) action . Pool ? ?
( IXenObject ) action . SR ;
2013-09-02 15:45:42 +02:00
if ( model ! = null )
model . InError = true ;
2013-06-24 13:41:48 +02:00
RequestRefreshTreeView ( ) ;
}
}
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 ( ) ;
}
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 ( ) ;
// kick-off connections for all the loaded server list
foreach ( IXenConnection connection in ConnectionsManager . XenConnectionsCopy )
{
if ( ! connection . SaveDisconnected )
{
XenConnectionUI . BeginConnect ( connection , true , this , true ) ;
// if there are fewer than 30 connections, then expand the tree nodes.
if ( ConnectionsManager . XenConnectionsCopy . Count < 30 )
{
connection . CachePopulated + = connection_CachePopulatedOnStartup ;
}
}
}
Program . StorageLinkConnections . CollectionChanged + = StorageLinkConnections_CollectionChanged ;
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
CheckForUpdatesTimer . Tick + = Updates . Tick ;
CheckForUpdatesTimer . Start ( ) ;
Updates . AutomaticCheckForUpdates ( ) ;
}
ProcessCommand ( CommandLineArgType , CommandLineParam ) ;
}
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 StorageLinkConnections_CollectionChanged ( object sender , CollectionChangeEventArgs e )
{
var con = ( ( StorageLinkConnection ) e . Element ) ;
if ( e . Action = = CollectionChangeAction . Add )
{
con . ConnectionStateChanged + = ( s , ee ) = >
{
if ( ee . ConnectionState = = StorageLinkConnectionState . Connected )
{
2013-08-25 15:06:03 +02:00
RequestRefreshTreeView ( ) ;
2013-06-24 13:41:48 +02:00
TrySelectNewNode ( o = >
{
var server = con . Cache . Server ;
return server ! = null & & server . Equals ( o ) ;
} , false , true , false ) ;
}
Program . Invoke ( this , UpdateToolbars ) ;
} ;
con . Cache . Changed + = Cache_Changed ;
}
else if ( e . Action = = CollectionChangeAction . Remove )
{
con . Cache . Changed - = Cache_Changed ;
}
RequestRefreshTreeView ( ) ;
}
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 ;
TrySelectNewNode ( c , false , true , false ) ;
}
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 ] ) ;
new RestoreHostFromBackupCommand ( commandInterface , null , args [ 0 ] ) . Execute ( ) ;
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 ] ) ;
new ImportSearchCommand ( commandInterface , args [ 0 ] ) . Execute ( ) ;
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.
BringToFront ( ) ;
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
}
// update ui
//XenAdmin.Settings.SaveServerList();
}
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 ;
closeActiveWizards ( connection ) ;
lock ( Alert . XenCenterAlertsLock )
Alert . XenCenterAlerts . RemoveAll ( new Predicate < Alert > ( delegate ( Alert alert ) { return alert . Connection ! = null & & alert . Connection . Equals ( connection ) ; } ) ) ;
}
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 ;
log . InfoFormat ( "Connected to {0} (version {1}, build {2}.{3}) with XenCenter {4} (build {5})" ,
Helpers . GetName ( master ) , Helpers . HostProductVersionText ( master ) , Helpers . HostProductVersion ( master ) ,
Helpers . HostBuildNumber ( master ) , Branding . PRODUCT_VERSION_TEXT , Program . Version . Revision ) ;
// 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 ) ) ;
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 ) ;
}
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 )
licenseTimer . CheckActiveServerLicense ( connection ) ;
Updates . CheckServerPatches ( ) ;
Updates . CheckServerVersion ( ) ;
RequestRefreshTreeView ( ) ;
}
/// <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 )
{
Program . MainWindow . closeActiveWizards ( host ) ;
AllowHistorySwitch = true ;
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 ) ;
closeActiveWizards ( vm ) ;
}
selectedTabs . Remove ( o ) ;
pluginManager . DisposeURLs ( ( IXenObject ) o ) ;
}
}
private void Pool_PropertyChanged ( object obj , PropertyChangedEventArgs e )
{
Pool pool = ( Pool ) obj ;
switch ( e . PropertyName )
{
case "other_config" :
// other_config may contain HideFromXenCenter
UpdateToolbars ( ) ;
// other_config contains which patches to ignore
Updates . CheckServerPatches ( ) ;
Updates . CheckServerVersion ( ) ;
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 ;
closeActiveWizards ( connection ) ;
UpdateToolbars ( ) ;
}
catch ( Exception exn )
{
log . Error ( exn , exn ) ;
// Can do nothing about this.
}
}
private static void gc ( )
{
log_gc ( "Before" ) ;
GC . Collect ( ) ;
log_gc ( "After" ) ;
}
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-08-26 12:42:32 +02:00
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 ;
powerOnHostToolStripButton . Available = powerOnHostToolStripButton . Enabled ;
startVMToolStripButton . Available = startVMToolStripButton . Enabled ;
shutDownToolStripButton . Available = shutDownToolStripButton . Enabled | | ( ! startVMToolStripButton . Available & & ! powerOnHostToolStripButton . Available ) ;
resumeToolStripButton . Available = resumeToolStripButton . Enabled ;
SuspendToolbarButton . Available = SuspendToolbarButton . Enabled | | ! resumeToolStripButton . Available ;
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
// Only show the HA tab if the host's license has the HA flag set
bool has_ha_license_flag = selectionMaster ! = null & & ! selectionMaster . RestrictHAOrlando ;
bool george_or_greater = Helpers . GeorgeOrGreater ( selectionConnection ) ;
bool mr_or_greater = Helpers . MidnightRideOrGreater ( selectionConnection ) ;
// 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 ) ;
bool ha_upsell = Helpers . FeatureForbidden ( SelectionManager . Selection . FirstAsXenObject , Host . RestrictHAFloodgate ) ;
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 ;
bool isStorageLinkSelected = SelectionManager . Selection . FirstIsStorageLink ;
bool isStorageLinkSRSelected = SelectionManager . Selection . First is StorageLinkRepository & & ( ( StorageLinkRepository ) SelectionManager . Selection . First ) . SR ( ConnectionsManager . XenConnectionsCopy ) ! = null ;
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 ) ;
ShowTab ( TabPageSearch , ( SearchMode | | show_home | | SearchTabVisible ) ) ;
ShowTab ( TabPageGeneral , ! multi & & ! SearchMode & & ( isVMSelected | | ( isHostSelected & & ( isHostLive | | ! is_connected ) ) | | isPoolSelected | | isSRSelected | | isStorageLinkSelected ) ) ;
ShowTab ( dmc_upsell ? TabPageBallooningUpsell : TabPageBallooning , ! multi & & ! SearchMode & & mr_or_greater & & ( isVMSelected | | ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
ShowTab ( TabPageStorage , ! multi & & ! SearchMode & & ( isRealVMSelected | | ( isTemplateSelected & & ! selectedTemplateHasProvisionXML ) ) ) ;
ShowTab ( TabPageSR , ! multi & & ! SearchMode & & ( isSRSelected | | isStorageLinkSRSelected ) ) ;
ShowTab ( TabPagePhysicalStorage , ! multi & & ! SearchMode & & ( ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
ShowTab ( TabPageNetwork , ! multi & & ! SearchMode & & ( isVMSelected | | ( isHostSelected & & isHostLive ) | | isPoolSelected ) ) ;
ShowTab ( TabPageNICs , ! multi & & ! SearchMode & & ( ( isHostSelected & & isHostLive ) ) ) ;
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 ) ) ) ;
ShowTab ( ha_upsell ? TabPageHAUpsell : TabPageHA , ! multi & & ! SearchMode & & isPoolSelected & & has_ha_license_flag ) ;
ShowTab ( TabPageSnapshots , ! multi & & ! SearchMode & & george_or_greater & & isRealVMSelected ) ;
//Disable the WLB tab from Clearwater onwards
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . All ( s = > ! Helpers . ClearwaterOrGreater ( s . Connection ) ) )
2013-06-24 13:41:48 +02:00
ShowTab ( wlb_upsell ? TabPageWLBUpsell : TabPageWLB , ! multi & & ! SearchMode & & isPoolSelected & & george_or_greater ) ;
ShowTab ( TabPageAD , ! multi & & ! SearchMode & & ( isPoolSelected | | isHostSelected & & isHostLive ) & & george_or_greater ) ;
// put plugin tabs before logs tab
foreach ( TabPageFeature f in pluginManager . GetAllFeatures < TabPageFeature > ( f = > ! f . IsConsoleReplacement & & ! multi & & f . ShowTab ) )
{
ShowTab ( f . TabPage , true ) ;
}
// 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 bool SearchTabVisible
{
get
{
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . Count = = 1 )
2013-06-24 13:41:48 +02:00
{
2013-08-22 18:25:12 +02:00
Host host = SelectionManager . Selection [ 0 ] . XenObject as Host ;
2013-06-24 13:41:48 +02:00
if ( host ! = null )
{
return host . IsLive ;
}
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection [ 0 ] . XenObject is Pool )
2013-06-24 13:41:48 +02:00
{
return true ;
}
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection [ 0 ] . GroupingTag ! = null )
2013-06-24 13:41:48 +02:00
{
return true ;
}
2013-08-22 18:25:12 +02:00
if ( SelectionManager . Selection [ 0 ] . XenObject is Folder )
2013-06-24 13:41:48 +02:00
{
return true ;
}
}
2013-08-22 18:25:12 +02:00
else if ( SelectionManager . Selection . Count > 1 )
2013-06-24 13:41:48 +02:00
{
return true ;
}
return false ;
}
}
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 ;
}
private void topLevelMenu_DropDownOpening ( object sender , EventArgs e )
{
ToolStripMenuItem menu = ( ToolStripMenuItem ) sender ;
//clear existing plugin items
for ( int i = menu . DropDownItems . Count - 1 ; i > = 0 ; i - - )
{
CommandToolStripMenuItem commandMenuItem = menu . DropDownItems [ i ] as CommandToolStripMenuItem ;
if ( commandMenuItem ! = null & & ( commandMenuItem . Command is MenuItemFeatureCommand | | commandMenuItem . Command is ParentMenuItemFeatureCommand ) )
{
menu . DropDownItems . RemoveAt ( i ) ;
if ( menu . DropDownItems [ i ] is ToolStripSeparator )
{
menu . DropDownItems . RemoveAt ( i ) ;
}
}
}
// get insert index using the placeholder
int insertIndex = pluginMenuItemStartIndexes [ menu ] ;
bool addSeparatorAtEnd = false ;
// add plugin items for this menu at insertIndex
foreach ( PluginDescriptor plugin in pluginManager . Plugins )
{
if ( ! plugin . Enabled )
{
continue ;
}
foreach ( Feature feature in plugin . Features )
{
MenuItemFeature menuItemFeature = feature as MenuItemFeature ;
if ( menuItemFeature ! = null & & menuItemFeature . ParentFeature = = null & & ( int ) menuItemFeature . Menu = = MainMenuBar . Items . IndexOf ( menu ) )
{
Command cmd = menuItemFeature . GetCommand ( commandInterface , SelectionManager . Selection ) ;
menu . DropDownItems . Insert ( insertIndex , new CommandToolStripMenuItem ( cmd ) ) ;
insertIndex + + ;
addSeparatorAtEnd = true ;
}
ParentMenuItemFeature parentMenuItemFeature = feature as ParentMenuItemFeature ;
if ( parentMenuItemFeature ! = null & & ( int ) parentMenuItemFeature . Menu = = MainMenuBar . Items . IndexOf ( menu ) )
{
Command cmd = parentMenuItemFeature . GetCommand ( commandInterface , SelectionManager . Selection ) ;
CommandToolStripMenuItem parentMenuItem = new CommandToolStripMenuItem ( cmd ) ;
menu . DropDownItems . Insert ( insertIndex , parentMenuItem ) ;
insertIndex + + ;
addSeparatorAtEnd = true ;
foreach ( MenuItemFeature childFeature in parentMenuItemFeature . Features )
{
Command childCommand = childFeature . GetCommand ( commandInterface , SelectionManager . Selection ) ;
parentMenuItem . DropDownItems . Add ( new CommandToolStripMenuItem ( childCommand ) ) ;
}
}
}
}
if ( addSeparatorAtEnd )
{
menu . DropDownItems . Insert ( insertIndex , new ToolStripSeparator ( ) ) ;
}
}
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
Host best_host = hostAncestor ? ? ( connection = = null ? null : Helpers . GetMaster ( connection ) ) ;
bool george_or_greater = best_host ! = null & & Helpers . GeorgeOrGreater ( best_host ) ;
exportSettingsToolStripMenuItem . Enabled = ConnectionsManager . XenConnectionsCopy . Count > 0 ;
this . MenuShortcuts = true ;
startOnHostToolStripMenuItem . Available = startOnHostToolStripMenuItem . Enabled ;
resumeOnToolStripMenuItem . Available = resumeOnToolStripMenuItem . Enabled ;
relocateToolStripMenuItem . Available = relocateToolStripMenuItem . Enabled ;
storageLinkToolStripMenuItem . Available = storageLinkToolStripMenuItem . 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 )
{
AllowHistorySwitch = true ;
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 )
{
AllowHistorySwitch = false ;
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
{
ConsolePanel . PauseAllViews ( ) ;
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 )
{
2013-08-22 18:25:12 +02:00
StorageLinkRepository slr = SelectionManager . Selection . First as StorageLinkRepository ;
SrStoragePage . SR = slr = = null ? SelectionManager . Selection . First as SR : slr . SR ( ConnectionsManager . XenConnectionsCopy ) ;
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-08-22 18:25:12 +02:00
if ( SelectionManager . Selection . First is GroupingTag )
2013-06-24 13:41:48 +02:00
{
2013-08-22 18:25:12 +02:00
GroupingTag gt = ( GroupingTag ) SelectionManager . Selection . First ;
2013-06-24 13:41:48 +02:00
SearchPage . Search = Search . SearchForGroup ( gt . Grouping , gt . Parent , gt . Group ) ;
}
else
{
2013-08-22 18:25:12 +02:00
SearchPage . XenObject = SelectionManager . Selection . Count > 1 ? null : SelectionManager . Selection . FirstAsXenObject ;
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 )
{
2013-08-22 18:25:12 +02:00
PhysicalStoragePage . SetSelectionBroadcaster ( SelectionManager , commandInterface ) ;
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
}
}
if ( t = = TabPagePeformance )
{
PerformancePage . ResumeGraph ( ) ;
}
else
{
PerformancePage . PauseGraph ( ) ;
}
if ( t = = TabPageSearch )
{
SearchPage . PanelShown ( ) ;
}
else
{
SearchPage . PanelHidden ( ) ;
}
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
{
2013-08-10 14:17:14 +02:00
Overview , Home , Settings , Storage , Network , Console , Performance , History , NICs , SR
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 ;
default :
throw new NotImplementedException ( ) ;
}
}
#region "Window" main menu item
private void windowToolStripMenuItem_DropDownOpening ( object sender , EventArgs e )
{
windowToolStripMenuItem . DropDown . Items . Clear ( ) ;
topLevelMenu_DropDownOpening ( sender , e ) ;
foreach ( Form form in GetAuxWindows ( ) )
{
2013-08-22 17:48:16 +02:00
ToolStripMenuItem item = new ToolStripMenuItem ( form . Text . EscapeAmpersands ( ) ) ;
2013-06-24 13:41:48 +02:00
item . Tag = form ;
windowToolStripMenuItem . DropDown . Items . Add ( item ) ;
}
}
private List < Form > GetAuxWindows ( )
{
List < Form > result = new List < Form > ( ) ;
foreach ( Form form in Application . OpenForms )
{
2013-07-02 15:51:03 +02:00
if ( form ! = this & & form . Text ! = "" & & ! ( form is ConnectingToServerDialog ) )
2013-06-24 13:41:48 +02:00
{
result . Add ( form ) ;
}
}
return result ;
}
private void windowToolStripMenuItem_DropDownItemClicked ( object sender , ToolStripItemClickedEventArgs e )
{
if ( e . ClickedItem . Tag is Form )
{
HelpersGUI . BringFormToFront ( ( Form ) e . ClickedItem . Tag ) ;
}
}
#endregion
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 )
{
2013-08-07 12:09:35 +02:00
if ( ! a . IsCompleted )
2013-06-24 13:41:48 +02:00
{
currentTasks = true ;
break ;
}
}
if ( currentTasks )
{
e . Cancel = true ;
DialogResult result = Program . RunInAutomatedTestMode ? DialogResult . OK :
new Dialogs . WarningDialogs . CloseXenCenterWarningDialog ( ) . ShowDialog ( this ) ;
if ( result = = DialogResult . OK )
{
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 ( ) ;
}
}
System . Threading . ThreadPool . QueueUserWorkItem ( new System . Threading . WaitCallback ( CloseWhenActionsCanceled ) ) ;
}
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 ( ) ;
}
/// <summary>
/// Closes all per-Connection and per-VM wizards for the given connection.
/// </summary>
/// <param name="connection"></param>
public void closeActiveWizards ( IXenConnection connection )
{
Program . Invoke ( Program . MainWindow , delegate
{
// Close and remove any active wizards for any VMs
foreach ( VM vm in connection . Cache . VMs )
{
closeActiveWizards ( vm ) ;
}
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>
public void closeActiveWizards ( IXenObject obj )
{
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 )
{
closeActiveWizards ( obj ) ;
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 )
{
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 ) ;
}
#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" ;
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 ) ;
}
/// <summary>
/// The never-shown Form that is the parent used in ShowHelp() calls.
/// </summary>
private static Form helpForm ;
public void ShowHelpTopic ( string topicID )
{
if ( helpForm = = null )
{
helpForm = new Form ( ) ;
helpForm . CreateControl ( ) ;
}
// 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.
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 ) ;
}
}
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 ( )
{
if ( TheTabControl . SelectedTab . Tag is TabPageFeature & & ( ( TabPageFeature ) TheTabControl . SelectedTab . Tag ) . HasHelp )
( ( TabPageFeature ) TheTabControl . SelectedTab . Tag ) . LaunchHelp ( ) ;
else
Help . HelpManager . Launch ( TabHelpID ( ) ) ;
}
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
}
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 ( ) ;
}
}
private bool DoSearch ( string filename )
{
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 ( )
{
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 ;
2013-06-24 13:41:48 +02:00
TitleLabel . Text = GetTitleLabel ( xenObject ) ;
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 ;
}
}
string GetTitleLabel ( IXenObject xenObject )
{
string name = Helpers . GetName ( xenObject ) ;
VM vm = xenObject as VM ;
if ( vm ! = null & & vm . is_a_real_vm )
{
Host server = vm . Home ( ) ;
if ( server ! = null )
return string . Format ( Messages . VM_ON_SERVER , name , server ) ;
Pool pool = Helpers . GetPool ( vm . Connection ) ;
if ( pool ! = null )
return string . Format ( Messages . VM_IN_POOL , name , pool ) ;
}
return name ;
}
2013-08-23 13:23:35 +02:00
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-08-30 16:19:59 +02:00
private void navigationPane_NotificationsSubModeChanged ( NotificationsSubMode submode )
{
2013-09-02 15:45:42 +02:00
TheTabControl . Visible = false ;
2013-08-30 16:19:59 +02:00
alertPage . Visible = submode = = NotificationsSubMode . Alerts ;
updatesPage . Visible = submode = = NotificationsSubMode . Updates ;
2013-09-02 15:45:42 +02:00
eventsPage . Visible = submode = = NotificationsSubMode . Events ;
2013-08-30 16:19:59 +02:00
if ( alertPage . Visible )
alertPage . RefreshAlertList ( ) ;
if ( updatesPage . Visible )
updatesPage . RefreshUpdateList ( ) ;
else
updatesPage . CancelUpdateCheck ( ) ;
2013-09-02 15:45:42 +02:00
if ( eventsPage . Visible )
{
// Unmark node if user has now seen error in log tab
if ( SelectionManager . Selection . FirstAsXenObject ! = null )
SelectionManager . Selection . FirstAsXenObject . InError = false ;
eventsPage . RefreshDisplayedEvents ( ) ;
RequestRefreshTreeView ( ) ;
}
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
{
TheTabControl . Visible = true ;
2013-09-02 15:45:42 +02:00
alertPage . Visible = updatesPage . Visible = eventsPage . Visible = false ;
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 ;
AllowHistorySwitch = 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-08-30 14:35:32 +02:00
Program . BeginInvoke ( Program . MainWindow , navigationPane . UpdateNotificationsButton ) ;
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 ;
}
Program . MainWindow . AllowHistorySwitch = true ;
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.
// See StorageLinkConnection for an example of its usage.
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
int chosenPanel2MinSize = splitContainer1 . Width / 2 ;
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 ;
}
}
}