/* Copyright (c) Cloud Software Group, Inc. * * 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.Drawing; using System.Linq; using System.Windows.Forms; using XenAPI; using XenAdmin.Wizards.NewSRWizard_Pages; using XenAdmin.Core; using XenCenterLib; namespace XenAdmin.Controls { /// /// A flicker-free ListBox for SRs. /// Add to this control ToStringWrapper<SR.SRInfo>s, which will /// be drawn 'UUID (size)' or will be drawn gray and unselectable. /// public class SRListBox : FlickerFreeListBox { private static readonly Font MonospaceFont = new Font(FontFamily.GenericMonospace, 9); private String MustSelectUUID = null; public SRListBox() { this.DrawMode = DrawMode.OwnerDrawFixed; this.DrawItem += SRListBox_DrawItem; // Since we are doing OwnerDraw, we need to set the ItemHeight this.ItemHeight = Drawing.MeasureText("()01234567890abcdefABCDEFKTGMB", this.Font).Height + 2; } public void SetMustSelectUUID(String uuid) { MustSelectUUID = uuid; } public void TryAndSelectUUID() { foreach (SR.SRInfo info in Items) if (info.UUID == MustSelectUUID && CanSelectSRInfo(info)) { SelectedItem = info; return; } SelectedIndex = -1; } private bool CanSelectSRInfo(SR.SRInfo info) { SR sr = SrWizardHelpers.SrInUse(info.UUID); if (sr != null && sr.HasPBDs()) return false; if (!String.IsNullOrEmpty(MustSelectUUID) && info.UUID != MustSelectUUID) return false; return true; } protected override void OnKeyDown(KeyEventArgs e) { bool movingUp = e.KeyCode == Keys.Up || e.KeyCode == Keys.Left || e.KeyCode == Keys.PageUp; bool movingDown = e.KeyCode == Keys.Down || e.KeyCode == Keys.Right || e.KeyCode == Keys.PageDown; bool movingPage = e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown; if (Items.Count <= 0 || !(movingUp || movingDown)) { base.OnKeyDown(e); return; } int index = SelectedIndex; int bottomIndex = TopIndex + ClientSize.Height / ItemHeight; int firstAvailable = -1; int lastAvailableInView = -1; int lastAvailableOffView = -1; if (movingUp) { while (--index >= 0) { SR.SRInfo nextInfo = Items[index] as SR.SRInfo; if (nextInfo == null || CanSelectSRInfo(nextInfo)) { if (firstAvailable == -1) firstAvailable = index; if (movingPage) { if (index >= TopIndex) lastAvailableInView = index; else lastAvailableOffView = index; } else break; } } } if (movingDown) { while (++index <= Items.Count - 1) { SR.SRInfo nextInfo = Items[index] as SR.SRInfo; if (nextInfo == null || CanSelectSRInfo(nextInfo)) { if (firstAvailable == -1) firstAvailable = index; if (movingPage) { if (index <= bottomIndex) lastAvailableInView = index; else lastAvailableOffView = index; } else break; } } } if (movingPage) { if (lastAvailableInView > -1) SelectedIndex = lastAvailableInView; else if (lastAvailableOffView > -1) SelectedIndex = lastAvailableOffView; } else if (firstAvailable > -1) SelectedIndex = firstAvailable; e.Handled = true; base.OnKeyDown(e); } protected override void OnSelectedIndexChanged(EventArgs e) { SR.SRInfo info = SelectedItem as SR.SRInfo; if (info == null || CanSelectSRInfo(info)) { base.OnSelectedIndexChanged(e); return; } //If we cannot select any SRInfos - give up if (!Items.Cast().Any(CanSelectSRInfo)) return; TryAndSelectUUID(); } private void SRListBox_DrawItem(object sender, DrawItemEventArgs e) { if (e.Index == -1) return; SR.SRInfo info = Items[e.Index] as SR.SRInfo; if (info == null) return; SR sr = SrWizardHelpers.SrInUse(info.UUID); Color fore, back; if (!Enabled) { fore = SystemColors.GrayText; back = SystemColors.Control; } else if (!CanSelectSRInfo(info)) { // Draw in-use SRs grayed out fore = SystemColors.GrayText; back = SystemColors.Window; } else if ((e.State & DrawItemState.Selected) > 0) { // When control enabled, draw the selected item blue fore = SystemColors.HighlightText; back = SystemColors.Highlight; } else { fore = SystemColors.ControlText; back = SystemColors.Window; } // Fill in background using (SolidBrush backBrush = new SolidBrush(back)) { e.Graphics.FillRectangle(backBrush, e.Bounds); } if (sr == null) { // Draw SR UUID in monospace, but size in normal font Size s = Drawing.MeasureText(info.UUID + " ", MonospaceFont); Drawing.DrawText(e.Graphics, info.UUID + " ", MonospaceFont, e.Bounds.Location, fore); if(!String.IsNullOrEmpty(info.Aggr)) Drawing.DrawText(e.Graphics, info.Aggr + " ", e.Font, new Point(e.Bounds.Left + s.Width, e.Bounds.Top), fore); } else { String text = String.Format(Messages.SR_X_ON_Y, sr.Name(), Helpers.GetName(sr.Connection)); if (!sr.HasPBDs()) text = String.Format(Messages.DETACHED_BRACKETS, text); Drawing.DrawText(e.Graphics, text, e.Font, e.Bounds.Location, fore); } } protected override void WndProc(ref System.Windows.Forms.Message msg) { switch (msg.Msg) { case Win32.WM_LBUTTONDOWN: case Win32.WM_LBUTTONDBLCLK: int i = IndexFromPoint(PointToClient(MousePosition)); if (i < 0 || i >= Items.Count) break; SR.SRInfo info = Items[i] as SR.SRInfo; if (info == null) break; // If cannot select item, ignore message if (!CanSelectSRInfo(info)) return; break; } base.WndProc(ref msg); } } }