/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using XenAdmin.Controls; using XenAdmin.Core; using XenAdmin.Network; using XenAPI; using XenAdmin.Commands; namespace XenAdmin.Wizards.BugToolWizardFiles { public partial class GenericSelectHostsPage : XenTabPage { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly CollectionChangeEventHandler Host_CollectionChangedWithInvoke; private bool inupdate; public GenericSelectHostsPage() { InitializeComponent(); buildList(); Host_CollectionChangedWithInvoke = Program.ProgramInvokeHandler(Host_CollectionChanged); HostListTreeView.ShowImages = true; HostListTreeView.ShowCheckboxes = true; HostListTreeView.ShowDescription = true; HostListTreeView.ItemCheckChanged += HostListTreeView_ItemCheckChanged; ConnectionsManager.XenConnections.CollectionChanged += XenConnections_CollectionChanged; } #region XenTabPage overrides public override string HelpID { get { return "SelectServers"; } } public override string Text { get { return Messages.BUGTOOL_PAGE_SERVERS_TEXT; } } public override string PageTitle { get { return Messages.BUGTOOL_PAGE_SERVERS_TITLE; } } public override bool EnableNext() { return HostListTreeView.CheckedItems().Count > 0; } protected override void PageLoadedCore(PageLoadedDirection direction) { EnableDisableButtons(); } #endregion public void SelectHosts(List selectedObjects) { if (selectedObjects.Count == 0 || HostListTreeView.Items.Count == 0) return; HostListTreeView.BeginUpdate(); HostListTreeView.ClearSelected(); for (int index = 0; index < HostListTreeView.Items.Count; index++) { var node = HostListTreeView.Items[index] as HostCustomTreeNode; if (node == null) continue; IXenConnection con = node.Tag as IXenConnection; if (con != null) { var pool = Helpers.GetPool(con); if (pool == null) { Host master = Helpers.GetMaster(con); if (master != null && selectedObjects.Contains(master)) node.State = CheckState.Checked; } else { if (selectedObjects.Contains(pool)) { foreach (var subnode in node.ChildNodes) subnode.State = CheckState.Checked; } } continue; } var host = node.Tag as Host; if (host != null && selectedObjects.Contains(host)) node.State = CheckState.Checked; } //focus on first checked item so the user can find it in a long list foreach (var node in HostListTreeView.CheckedItems()) { HostListTreeView.SelectedItems.Add(node); break; } HostListTreeView.EndUpdate(); } public List SelectedHosts { get { List hosts = new List(); foreach (HostCustomTreeNode node in HostListTreeView.CheckedItems()) { IXenConnection c = node.Tag as IXenConnection; if (c != null) { if (Helpers.GetPool(c) == null) { Host master = Helpers.GetMaster(c); if (master != null) hosts.Add(master); } continue; } Host host = node.Tag as Host; if (host != null) hosts.Add(host); } return hosts; } } private void buildList() { Program.AssertOnEventThread(); if (inupdate) return; inupdate = true; HostListTreeView.BeginUpdate(); try { // Save old checked states to preserve across update var oldCheckStates = new Dictionary(); foreach (HostCustomTreeNode node in HostListTreeView.Items) { if (node.HostOrPoolUuid != null) oldCheckStates.Add(node.HostOrPoolUuid, node.State); } HostListTreeView.ClearAllNodes(); DeregisterEvents(); foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy) { connection.ConnectionStateChanged += connection_ConnectionStateChanged; connection.Cache.RegisterCollectionChanged(Host_CollectionChangedWithInvoke); connection.CachePopulated += connection_CachePopulated; if (!connection.IsConnected) continue; // don't show disconnected connections CA-60514 HostCustomTreeNode node = new HostCustomTreeNode(true) { Text = Helpers.GetName(connection), Tag = connection, Enabled = true, Description = "", State = CheckState.Unchecked, Image = Images.GetImage16For(connection) }; HostListTreeView.AddNode(node); // Save uuid of pool to this node Pool pool = Helpers.GetPoolOfOne(connection); if (pool == null) continue; pool.PropertyChanged += pool_PropertyChanged; node.HostOrPoolUuid = pool.uuid; node.State = (oldCheckStates.ContainsKey(node.HostOrPoolUuid) && node.Enabled) ? oldCheckStates[node.HostOrPoolUuid] : CheckState.Unchecked; if (Helpers.GetPool(connection) != null) { node.Image = Images.GetImage16For(pool); foreach (Host host in connection.Cache.Hosts) { bool isHostLive = host.IsLive(); HostCustomTreeNode childnode = new HostCustomTreeNode(true) { Text = Helpers.GetName(host), Tag = host, HostOrPoolUuid = host.uuid, Enabled = isHostLive, Description = isHostLive ? "" : Messages.HOST_NOT_LIVE, Image = Images.GetImage16For(host) }; childnode.State = (oldCheckStates.ContainsKey(childnode.HostOrPoolUuid) && childnode.Enabled) ? oldCheckStates[childnode.HostOrPoolUuid] : CheckState.Unchecked; HostListTreeView.AddChildNode(node, childnode); RegisterHostEvents(host); } } else { Host master = Helpers.GetMaster(connection); if (master != null) { bool isMasterLive = master.IsLive(); node.Enabled = isMasterLive; node.Description = isMasterLive ? "" : Messages.HOST_NOT_LIVE; node.Image = Images.GetImage16For(master); RegisterHostEvents(master); } } } } finally { inupdate = false; HostListTreeView.EndUpdate(); EnableDisableButtons(); } } private void DeregisterEvents() { foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy) { connection.ConnectionStateChanged -= connection_ConnectionStateChanged; connection.Cache.DeregisterCollectionChanged(Host_CollectionChangedWithInvoke); connection.CachePopulated -= connection_CachePopulated; Pool pool = Helpers.GetPoolOfOne(connection); if (pool == null) continue; pool.PropertyChanged -= pool_PropertyChanged; if (Helpers.GetPool(connection) != null) { foreach (Host host in connection.Cache.Hosts) DeregisterHostEvents(host); } else { Host master = Helpers.GetMaster(connection); if (master != null) DeregisterHostEvents(master); } } } private void RegisterHostEvents(Host host) { Host_metrics metrics = host.Connection.Resolve(host.metrics); if (metrics != null) metrics.PropertyChanged += hostMetrics_PropertyChanged; host.PropertyChanged += host_PropertyChanged; } private void DeregisterHostEvents(Host host) { Host_metrics metrics = host.Connection.Resolve(host.metrics); if (metrics != null) metrics.PropertyChanged -= hostMetrics_PropertyChanged; host.PropertyChanged -= host_PropertyChanged; } private void connection_CachePopulated(object sender, EventArgs e) { Program.Invoke(this, buildList); } private void Host_CollectionChanged(object sender, CollectionChangeEventArgs e) { buildList(); } private void pool_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "name_label" || e.PropertyName == "master") { Program.Invoke(this, buildList); } } private void hostMetrics_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "live") { Program.Invoke(this, buildList); } } private void host_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "name_label" || e.PropertyName == "enabled" || e.PropertyName == "patches" || e.PropertyName == "metrics") { Program.Invoke(this, buildList); } } private void connection_ConnectionStateChanged(object sender, EventArgs e) { Program.Invoke(this, (CollectionChangeEventHandler)XenConnections_CollectionChanged, this, null); } private void XenConnections_CollectionChanged(object sender, CollectionChangeEventArgs e) { Program.BeginInvoke(Program.MainWindow,buildList); } private void EnableDisableButtons() { if (!Visible) return; // CA-28387 OnPageUpdated(); SelectAllButton.Enabled = HostListTreeView.CheckableItems().Count != 0; SelectNoneButton.Enabled = HostListTreeView.CheckedItems().Count > 0; } #region Control event handlers private void SelectNoneButton_Click(object sender, EventArgs e) { HostListTreeView.SecretNode.State = CheckState.Unchecked; HostListTreeView.Refresh(); EnableDisableButtons(); } private void SelectAllButton_Click(object sender, EventArgs e) { HostListTreeView.SecretNode.State = CheckState.Checked; HostListTreeView.Refresh(); EnableDisableButtons(); } private void connectbutton_Click(object sender, EventArgs e) { new AddHostCommand(Program.MainWindow, ParentForm).Execute(); } private void HostListTreeView_ItemCheckChanged(object sender, EventArgs e) { EnableDisableButtons(); } #endregion } public class HostCustomTreeNode : CustomTreeNode { public string HostOrPoolUuid; public HostCustomTreeNode(bool selectable) : base(selectable) {} // Fixed for CA-57131. // Though it would be better to use the usual search mechanism for building // the tree, so that the order is absolutely guaranteed to be the same. protected override int SameLevelSortOrder(CustomTreeNode other) { if (other.Tag is IXenConnection && this.Tag is IXenConnection) { return (this.Tag as IXenConnection).CompareTo(other.Tag as IXenConnection); } else if (other.Tag is IXenConnection) { return -1; } else if (this.Tag is IXenConnection) { return 1; } else if (this.Tag is Host && other.Tag is Host) { return (this.Tag as Host).CompareTo(other.Tag as Host); } else { return base.SameLevelSortOrder(other); } } } }