xenadmin/XenAdmin/Controls/VisualMenuItem.cs
Michael ebb918296b CA-284226: Optimize performance of menu Start-on-Server and Migrate-to-Server (#1985)
* CA-284226: Reduce unnecessary CanExecute() calls.

* CA-284226: Optimize the performance of menu Migrate to Server and Start on Server.

* Fix an error in updating Migrate menu with WLB, which lead to crash.

* Clear the worker queue when menu is closed.

Signed-off-by: Michael Zhao <michael.zhao@citrix.com>

* Fix comments.
2018-03-20 07:07:19 +00:00

237 lines
7.0 KiB
C#

/* 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.Text;
using System.Windows.Forms;
using XenAdmin.Core;
using System.Drawing;
/*
* This class provides the option of including an extra image on a menu item
* after the text.
* ToolStripMenuItems do not take their width from get preferred size, it is
* necessary to pad the text with blank characters so the second image can be
* drawn.
*
* Assumes all menu items are in the same menu for alignment.
*
*
*/
namespace XenAdmin.Controls
{
public class VisualMenuItem : ToolStripMenuItem
{
private static int leftMargin = 35;
private static int topMargin = 4;
private static int imagePadding = 5;
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
UpdateWidths();
VisualMenuItemAlignData.Refresh();
RefreshPadding();
}
}
private double starRating = 0;
public double StarRating
{
get { return starRating; }
set { starRating = value; }
}
private int textWidth = 0;
public int TextWidth
{
get { return textWidth; }
}
private Image secondImage;
public Image SecondImage
{
get { return secondImage; }
set
{
secondImage = value;
VisualMenuItemAlignData.Refresh();
RefreshPadding();
this.Invalidate();
}
}
public VisualMenuItem()
{
}
public VisualMenuItem(string Text)
: base(Text)
{
// spacePadding will be set when text is assigned
}
public VisualMenuItem(string Text, Image Image)
: base(Text, Image)
{
// spacePadding will be set when text/image is assigned
}
private string spacePadding = "";
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (secondImage == null)
return;
e.Graphics.DrawImage(secondImage,
leftMargin + VisualMenuItemAlignData.MaxStringLength + imagePadding,
topMargin, secondImage.Width, secondImage.Height);
}
protected override void OnParentChanged(ToolStrip oldParent, ToolStrip newParent)
{
base.OnParentChanged(oldParent, newParent);
if (HasAlignData())
{
VisualMenuItemAlignData.Refresh();
}
RefreshPadding();
}
private void UpdateWidths()
{
textWidth = Drawing.MeasureText(base.Text.TrimEnd(), this.Font).Width;
}
private bool HasAlignData()
{
// at the moment we just use a single static object, so no need to distinguish instance ownership
return true;
}
public void RefreshPadding()
{
spacePadding = "";
if (HasAlignData())
{
while (textWidth + Drawing.MeasureText(spacePadding, this.Font).Width < VisualMenuItemAlignData.MaxCombinedWidth)
{
spacePadding += " ";
}
}
base.Text = base.Text.TrimEnd();
base.Text += spacePadding;
}
public int ImageWidth()
{
if (secondImage == null)
{
return 0;
}
return (secondImage.Width + imagePadding * 2);
}
}
public static class VisualMenuItemAlignData
{
private static ToolStripMenuItem parentStrip;
public static ToolStripMenuItem ParentStrip
{
get { return parentStrip; }
set
{
parentStrip = value;
Refresh();
}
}
private static int maxStringLength;
public static int MaxStringLength
{
get { return maxStringLength; }
}
private static int maxCombinedWidth;
public static int MaxCombinedWidth
{
get { return maxCombinedWidth; }
}
private static Object locker = new Object();
public static void Refresh()
{
maxCombinedWidth = 0;
maxStringLength = 0;
if (parentStrip == null)
{
return;
}
lock (locker)
{
int maxImageWidth = 0;
foreach (ToolStripItem item in parentStrip.DropDownItems)
{
VisualMenuItem visItem;
if ((visItem = item as VisualMenuItem) != null)
{
int w = visItem.ImageWidth();
if (w > maxImageWidth)
{
maxImageWidth = w;
}
if (visItem.TextWidth > maxStringLength)
{
maxStringLength = visItem.TextWidth;
}
}
}
maxCombinedWidth = maxImageWidth + maxStringLength;
}
}
}
}