/* 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 System.Collections; using System.Text.RegularExpressions; using XenAdmin; using XenAdmin.Core; using XenAdmin.Network; using XenAPI; using System.Runtime.InteropServices; namespace XenAdmin.Controls { public partial class ISODropDownBox : NonSelectableComboBox { public VM vm; protected VBD cdrom; protected bool refreshOnClose = false; protected bool changing = false; private IXenConnection _connection; protected bool physicalOnly = false; protected bool isoOnly = false; protected bool empty = false; private bool noTools = false; private VDI selectedCD; public VDI SelectedCD { get { var selectedVdi = SelectedItem as ToStringWrapper; return selectedVdi == null ? null : selectedVdi.item; } set { selectedCD = value; } } public ISODropDownBox() { SR_CollectionChangedWithInvoke = Program.ProgramInvokeHandler(SR_CollectionChanged); InitializeComponent(); } private void RefreshSRs_() { BeginUpdate(); try { Items.Clear(); RefreshSRs(); } finally { EndUpdate(); } } private static string srToString(SR sr) { return sr.Name; } protected virtual void RefreshSRs() { Program.AssertOnEventThread(); if (Empty) Items.Add(new ToStringWrapper(null, Messages.EMPTY)); //Create a special VDIWrapper for the empty dropdown item if (connection == null) return; List> items = new List>(); foreach (SR sr in connection.Cache.SRs) { if (sr.content_type != SR.Content_Type_ISO) continue; if (physicalOnly && !sr.Physical) continue; if (isoOnly && (sr.Physical || (noTools && sr.IsToolsSR))) continue; if (vm == null && sr.IsBroken()) continue; if (vm != null) { if (vm.power_state == vm_power_state.Halted) { Host storageHost = vm.GetStorageHost(true); // The storage host is the host that the VM is bound to because the VM is using local storage on that host. // It will be null if there is no such host (i.e. the VM is not restricted host-wise by storage). if (storageHost != null && !sr.CanBeSeenFrom(storageHost)) { // The storage host was not null, and this SR can't be seen from that host: don't show the SR. continue; } } else { // If VM is running, only show SRs on its current host Host runningOn = vm.Connection.Resolve(vm.resident_on); if (!sr.CanBeSeenFrom(runningOn)) { continue; } } } items.Add(new ToStringWrapper(sr, srToString)); } if (items.Count > 0) { items.Sort(); foreach (ToStringWrapper srWrapper in items) { AddSR(srWrapper); } } } public virtual void SelectCD() { if (selectedCD == null) { if (Items.Count > 0) SelectedIndex = 0; else SelectedIndex = -1; return; } foreach (object o in Items) { ToStringWrapper vdiNameWrapper = o as ToStringWrapper; if (vdiNameWrapper == null) continue; VDI iso = vdiNameWrapper.item; if (iso == null || !iso.Show(Properties.Settings.Default.ShowHiddenVMs)) continue; if (iso == selectedCD) { SelectedItem = o; break; } } } // TODO: this means only physical. refactor to mean display physical public bool Physical { get { return physicalOnly; } set { physicalOnly = value; } } // TODO: this means only iso. refactor to mean display iso public bool ISO { get { return isoOnly; } set { isoOnly = value; } } public bool Empty { get { return empty; } set { empty = value; } } protected void AddSR(ToStringWrapper srWrapper) { Items.Add(srWrapper); List> items = new List>(); if (srWrapper.item.Physical) { List> vdis = new List>(); foreach (VDI vdi in connection.ResolveAll(srWrapper.item.VDIs)) { ToStringWrapper vdiWrapper = new ToStringWrapper(vdi, vdi.Name); vdis.Add(vdiWrapper); } vdis.Sort(new Comparison>(delegate(ToStringWrapper object1, ToStringWrapper object2) { return Core.StringUtility.NaturalCompare(object1.item.Name, object2.item.Name); })); Host host = srWrapper.item.GetStorageHost(); if (host != null) { for (int i = 0; i < vdis.Count; i++) { items.Add(new ToStringWrapper(vdis[i].item, " " + string.Format(Messages.ISOCOMBOBOX_CD_DRIVE, i, host.Name))); } } } else { if (srWrapper.item.IsToolsSR) { foreach (VDI vdi in connection.ResolveAll(srWrapper.item.VDIs)) { if(Actions.InstallPVToolsAction.ISONameOld.Equals(vdi.name_label) || Actions.InstallPVToolsAction.ISONameNew.Equals(vdi.name_label)) items.Add(new ToStringWrapper(vdi, " " + vdi.Name)); } } else { foreach (VDI vdi in connection.ResolveAll(srWrapper.item.VDIs)) { items.Add(new ToStringWrapper(vdi, " " + vdi.Name)); } items.Sort(new Comparison>(delegate(ToStringWrapper object1, ToStringWrapper object2) { return Core.StringUtility.NaturalCompare(object1.item.Name, object2.item.Name); })); } } foreach (ToStringWrapper vdiWrapper in items) { Items.Add(vdiWrapper); } } public int ISOCount { get { int i = 0; foreach (object o in Items) { if (o is ToStringWrapper) i++; } return i; } } public IXenConnection connection { set { if (connection != null) { DeregisterEvents(); } _connection = value; if (connection != null) { RegisterEvents(); refreshAll(); } } get { if (vm != null) { return vm.Connection; } else { return _connection; } } } protected virtual void DeregisterEvents() { if (connection == null) return; // deregister collection listener connection.Cache.DeregisterCollectionChanged(SR_CollectionChangedWithInvoke); // Remove SR listeners foreach (SR sr in connection.Cache.SRs) { sr.PropertyChanged -= sr_PropertyChanged; foreach (PBD pbd in connection.Cache.PBDs) { pbd.PropertyChanged -= pbd_PropertyChanged; } } } protected void RegisterEvents() { if (connection == null) return; // register collection listener connection.Cache.RegisterCollectionChanged(SR_CollectionChangedWithInvoke); // Add SR listeners foreach (SR sr in connection.Cache.SRs) { sr.PropertyChanged -= sr_PropertyChanged; sr.PropertyChanged += sr_PropertyChanged; foreach (PBD pbd in connection.Cache.PBDs) { pbd.PropertyChanged -= pbd_PropertyChanged; pbd.PropertyChanged += pbd_PropertyChanged; } } } private readonly CollectionChangeEventHandler SR_CollectionChangedWithInvoke = null; protected void SR_CollectionChanged(object sender, CollectionChangeEventArgs e) { Program.AssertOnEventThread(); if (vm == null || e.Action == CollectionChangeAction.Refresh) return; foreach (SR sr in connection.Cache.SRs) { sr.PropertyChanged -= sr_PropertyChanged; sr.PropertyChanged += sr_PropertyChanged; } Program.Invoke(this, refreshAll); } public virtual void refreshAll() { if (!DroppedDown) { RefreshSRs_(); SelectCD(); refreshOnClose = false; } else { refreshOnClose = true; } } private void sr_PropertyChanged(object sender1, PropertyChangedEventArgs e) { if (e.PropertyName == "VDIs" || e.PropertyName == "PBDs") { refreshAll(); } } private void pbd_PropertyChanged(object sender1, PropertyChangedEventArgs e) { if (e.PropertyName == "currently_attached") { refreshAll(); } } protected void cdrom_PropertyChanged(object sender1, PropertyChangedEventArgs e) { if ((e.PropertyName == "empty" || e.PropertyName == "vdi") && !changing) { SelectCD(); } } protected void vm_PropertyChanged(object sender1, PropertyChangedEventArgs e) { if (e.PropertyName == "VBDs" || e.PropertyName == "resident_on" || e.PropertyName == "affinity") { refreshAll(); } } protected override void OnSelectionChangeCommitted(EventArgs e) { base.OnSelectionChangeCommitted(e); var selectedVdi = SelectedItem as ToStringWrapper; if (selectedVdi != null) selectedCD = selectedVdi.item; } protected override void OnDrawItem(DrawItemEventArgs e) { if (e.Index != -1) { Object o = Items[e.Index]; if (o is ToStringWrapper) { e.DrawBackground(); Drawing.DrawText(e.Graphics, o.ToString(), Program.DefaultFontBold, e.Bounds, SystemColors.ControlText, TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } else { if ((e.State & DrawItemState.Selected) != 0) { e.DrawBackground(); Drawing.DrawText(e.Graphics, o.ToString(), Program.DefaultFont, e.Bounds, e.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } else if((e.State & DrawItemState.Disabled) != 0) { e.DrawBackground(); Drawing.DrawText(e.Graphics, o.ToString(), Program.DefaultFont, e.Bounds, SystemColors.GrayText, TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } else { e.DrawBackground(); Drawing.DrawText(e.Graphics, o.ToString(), Program.DefaultFont, e.Bounds, e.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } e.DrawFocusRectangle(); } } base.OnDrawItem(e); } protected override void OnDropDownClosed(EventArgs e) { base.OnDropDownClosed(e); if (refreshOnClose) refreshAll(); } protected override bool IsItemNonSelectable(object o) { return o is ToStringWrapper; } } }