mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-11-25 14:27:26 +01:00
7c0bc50b4a
Inc. Signed-off-by: Gabor Apati-Nagy<gabor.apati-nagy@citrix.com>
540 lines
18 KiB
C#
540 lines
18 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.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using XenAdmin.Controls.DataGridViewEx;
|
|
using XenAdmin.Core;
|
|
using XenAdmin.Properties;
|
|
using System.Linq;
|
|
using XenAdmin.Commands;
|
|
|
|
|
|
namespace XenAdmin.Controls
|
|
{
|
|
public partial class PDSection : UserControl
|
|
{
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
#region Private fields
|
|
|
|
/// <summary>
|
|
/// Used to persist selection over a repaint, we set this when we clear the datagridview
|
|
/// </summary>
|
|
private string previousSelectionKey;
|
|
|
|
private bool inLayout;
|
|
|
|
/// <summary>
|
|
/// Whether the mouse is over the chevron
|
|
/// </summary>
|
|
private bool chevronHot;
|
|
|
|
#endregion
|
|
|
|
#region Delegates and Events
|
|
|
|
/// <summary>
|
|
/// Event for when the datagridview received focus
|
|
/// </summary>
|
|
public event Action<PDSection> contentReceivedFocus;
|
|
|
|
/// <summary>
|
|
/// Event for when the datagridview receives focus
|
|
/// </summary>
|
|
public event Action<PDSection> contentChangedSelection;
|
|
|
|
public event Action<PDSection> ExpandedChanged;
|
|
|
|
#endregion
|
|
|
|
public PDSection()
|
|
{
|
|
InitializeComponent();
|
|
SetDefaultValues();
|
|
Contract();
|
|
MinimumSize = new Size(0, Height);
|
|
dataGridViewEx1.LostFocus += dataGridViewEx1_LostFocus;
|
|
dataGridViewEx1.GotFocus += dataGridViewEx1_GotFocus;
|
|
|
|
if (!Application.RenderWithVisualStyles)
|
|
{
|
|
panel1.BackColor = SystemColors.Control;
|
|
this.BackColor = SystemColors.ControlDark;
|
|
}
|
|
}
|
|
|
|
#region Accessors
|
|
|
|
[Browsable(false)]
|
|
public bool DisableFocusEvent { private get; set; }
|
|
|
|
[DefaultValue("Title")]
|
|
[Browsable(true)]
|
|
[Localizable(true)]
|
|
public string SectionTitle
|
|
{
|
|
get { return label1.Text; }
|
|
set { label1.Text = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public bool IsEmpty()
|
|
{
|
|
return dataGridViewEx1.Rows.Count == 0;
|
|
}
|
|
|
|
[DefaultValue(true)]
|
|
[Browsable(false)]
|
|
public bool IsExpanded { get; private set; }
|
|
|
|
[Browsable(false)]
|
|
public bool HasNoSelection()
|
|
{
|
|
return dataGridViewEx1.SelectedRows.Count <= 0;
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public Rectangle SelectedRowBounds
|
|
{
|
|
get
|
|
{
|
|
if (HasNoSelection())
|
|
return new Rectangle(0, 0, 0, 0);
|
|
|
|
int x = dataGridViewEx1.Location.X;
|
|
int y = dataGridViewEx1.RowDepth(dataGridViewEx1.SelectedRows[0].Index) + dataGridViewEx1.Location.Y;
|
|
int w = dataGridViewEx1.Width;
|
|
int h = dataGridViewEx1.SelectedRows[0].Height;
|
|
return new Rectangle(x, y, w, h);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public bool ShowCellToolTips
|
|
{
|
|
get { return dataGridViewEx1.ShowCellToolTips; }
|
|
set { dataGridViewEx1.ShowCellToolTips = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected override void OnGotFocus(EventArgs e)
|
|
{
|
|
base.OnGotFocus(e);
|
|
|
|
// For keyboard access
|
|
if (DisableFocusEvent)
|
|
return;
|
|
|
|
if (!IsExpanded)
|
|
Expand();
|
|
}
|
|
|
|
#region Control Event Handlers
|
|
|
|
private void dataGridViewEx1_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
|
{
|
|
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
|
|
ExecuteCellCommandOrAction(dataGridViewEx1.Rows[e.RowIndex].Cells[e.ColumnIndex]);
|
|
}
|
|
|
|
private void dataGridViewEx1_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (e.KeyChar == (char)Keys.Enter)
|
|
ExecuteCellCommandOrAction(dataGridViewEx1.CurrentCell);
|
|
}
|
|
|
|
private void dataGridViewEx1_LostFocus(object sender, EventArgs e)
|
|
{
|
|
dataGridViewEx1.HideSelection = true;
|
|
}
|
|
|
|
private void dataGridViewEx1_GotFocus(object sender, EventArgs e)
|
|
{
|
|
dataGridViewEx1.HideSelection = false;
|
|
if (contentReceivedFocus != null)
|
|
contentReceivedFocus(this);
|
|
}
|
|
|
|
private void dataGridViewEx1_SelectionChanged(object sender, EventArgs e)
|
|
{
|
|
if (inLayout)
|
|
return;
|
|
|
|
if (contentChangedSelection != null)
|
|
contentChangedSelection(this);
|
|
}
|
|
|
|
private void dataGridViewEx1_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button != MouseButtons.Right)
|
|
return;
|
|
|
|
DataGridView.HitTestInfo i = dataGridViewEx1.HitTest(e.X, e.Y);
|
|
|
|
if (i.RowIndex < 0 || i.RowIndex > dataGridViewEx1.RowCount)
|
|
return;
|
|
if (i.ColumnIndex < 0 || i.ColumnIndex > dataGridViewEx1.ColumnCount)
|
|
return;
|
|
|
|
dataGridViewEx1.Focus();
|
|
var row = dataGridViewEx1.Rows[i.RowIndex];
|
|
row.Selected = true;
|
|
|
|
contextMenuStrip1.Items.Clear();
|
|
contextMenuStrip1.Items.Add(copyToolStripMenuItem);
|
|
|
|
var menuItems = row.Tag as IEnumerable<ToolStripMenuItem>;
|
|
if (menuItems != null)
|
|
{
|
|
contextMenuStrip1.Items.Add(new ToolStripSeparator());
|
|
contextMenuStrip1.Items.AddRange(menuItems.ToArray());
|
|
}
|
|
contextMenuStrip1.Show(dataGridViewEx1, dataGridViewEx1.PointToClient(MousePosition));
|
|
}
|
|
|
|
|
|
private void CopyMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Clipboard.SetDataObject(dataGridViewEx1.SelectedRows[0].Cells[1].Value);
|
|
}
|
|
|
|
|
|
private void panel1_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (IsExpanded)
|
|
Contract();
|
|
else
|
|
{
|
|
Expand();
|
|
dataGridViewEx1.Focus();
|
|
}
|
|
}
|
|
|
|
private void chevron_Click(object sender, EventArgs e)
|
|
{
|
|
if (IsExpanded)
|
|
Contract();
|
|
else
|
|
{
|
|
Expand();
|
|
dataGridViewEx1.Focus();
|
|
}
|
|
}
|
|
|
|
private void chevron_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
chevronHot = true;
|
|
RefreshChevron();
|
|
}
|
|
|
|
private void chevron_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
chevronHot = false;
|
|
RefreshChevron();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void SetDefaultValues()
|
|
{
|
|
SectionTitle = Messages.PDSECTION_TITLE;
|
|
IsExpanded = true;
|
|
}
|
|
|
|
private void ExecuteCellCommandOrAction(DataGridViewCell cell)
|
|
{
|
|
if (cell == null)
|
|
return;
|
|
|
|
var command = cell.Tag as Command;
|
|
if (command != null)
|
|
command.Execute();
|
|
|
|
var action = cell.Tag as Action;
|
|
if (action != null)
|
|
action.Invoke();
|
|
}
|
|
|
|
private void RefreshHeight()
|
|
{
|
|
if (IsExpanded)
|
|
{
|
|
int newHeight = dataGridViewEx1.Rows.GetRowsHeight(DataGridViewElementStates.Visible);
|
|
|
|
int valueColWidth = dataGridViewEx1.Width - dataGridViewEx1.Columns[KeyColumn.Index].Width;
|
|
int preferredValueColWidth =
|
|
dataGridViewEx1.Columns[ValueColumn.Index].GetPreferredWidth(
|
|
DataGridViewAutoSizeColumnMode.AllCells, true);
|
|
|
|
int horizontalScrollBarHeight = preferredValueColWidth - 1 >= valueColWidth
|
|
? dataGridViewEx1.HorizontalScrollBarHeight
|
|
: 0;
|
|
|
|
// 3px added so we have a border (one at top of control, one between title and grid, one at bottom)
|
|
Height = panel1.Height + newHeight + horizontalScrollBarHeight + 3;
|
|
// this correction is needed because the anchor property of the grid drags it to fill the space we want to be a border
|
|
// when we go from contracted (2 borders) to expanded (3 borders)
|
|
}
|
|
else
|
|
{
|
|
Height = panel1.Height + 2;
|
|
}
|
|
}
|
|
|
|
private void RefreshChevron()
|
|
{
|
|
if (IsExpanded)
|
|
{
|
|
chevron.Image = chevronHot ? Resources.PDChevronUpOver : Resources.PDChevronUp;
|
|
}
|
|
else
|
|
{
|
|
chevron.Image = chevronHot ? Resources.PDChevronDownOver : Resources.PDChevronDown;
|
|
}
|
|
}
|
|
|
|
private void AddRow(DataGridViewRow r)
|
|
{
|
|
dataGridViewEx1.Rows.Add(r);
|
|
if (inLayout)
|
|
return;
|
|
|
|
RefreshHeight();
|
|
}
|
|
|
|
private void ToggleExpandedState(bool expand)
|
|
{
|
|
if (IsExpanded == expand)
|
|
return;
|
|
|
|
IsExpanded = expand;
|
|
dataGridViewEx1.Visible = expand;
|
|
RefreshHeight();
|
|
RefreshChevron();
|
|
|
|
if (ExpandedChanged != null)
|
|
ExpandedChanged(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void Contract()
|
|
{
|
|
ToggleExpandedState(false);
|
|
}
|
|
|
|
public void Expand()
|
|
{
|
|
ValueColumn.MinimumWidth = 5;
|
|
HelpersGUI.ResizeLastGridViewColumn(ValueColumn);
|
|
ToggleExpandedState(true);
|
|
}
|
|
|
|
private DataGridViewExRow CreateRow(string Key, string Value)
|
|
{
|
|
if (!String.IsNullOrEmpty(Key))
|
|
Key += Messages.GENERAL_PAGE_KVP_SEPARATOR;
|
|
DataGridViewExRow r = new DataGridViewExRow();
|
|
r.CreateCells(dataGridViewEx1);
|
|
r.Cells[0].Value = Key;
|
|
r.Cells[1].Value = Value;
|
|
return r;
|
|
}
|
|
public void AddEntry(string Key, string Value)
|
|
{
|
|
var r = CreateRow(Key, Value);
|
|
AddRow(r);
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, ToolStripMenuItem contextMenuItem)
|
|
{
|
|
AddEntry(Key, Value, new[] { contextMenuItem });
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems)
|
|
{
|
|
var r = CreateRow(Key, Value);
|
|
r.Tag = contextMenuItems;
|
|
AddRow(r);
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems, string toolTipText)
|
|
{
|
|
AddEntry(Key, Value, contextMenuItems);
|
|
if (toolTipText != Key)
|
|
dataGridViewEx1.Rows[dataGridViewEx1.RowCount - 1].Cells[0].ToolTipText = toolTipText;
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, Color fontColor)
|
|
{
|
|
var r = CreateRow(Key, Value);
|
|
r.Cells[1].Style.ForeColor = fontColor;
|
|
AddRow(r);
|
|
dataGridViewEx1.DefaultCellStyle = new DataGridViewCellStyle();
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems, Color fontColor)
|
|
{
|
|
var r = CreateRow(Key, Value);
|
|
r.Cells[1].Style.ForeColor = fontColor;
|
|
r.Tag = contextMenuItems;
|
|
AddRow(r);
|
|
dataGridViewEx1.DefaultCellStyle = new DataGridViewCellStyle();
|
|
}
|
|
|
|
public void AddEntry(string Key, FolderListItem Value, IEnumerable<ToolStripMenuItem> contextMenuItems)
|
|
{
|
|
// Special case for folders: CA-33311
|
|
|
|
if (!String.IsNullOrEmpty(Key))
|
|
Key += Messages.GENERAL_PAGE_KVP_SEPARATOR;
|
|
DataGridViewExRow r = new DataGridViewExRow();
|
|
r.Cells.Add(new DataGridViewTextBoxCell());
|
|
r.Cells[0].Value = Key;
|
|
r.Cells.Add(new FolderCell(Value));
|
|
r.Tag = contextMenuItems;
|
|
AddRow(r);
|
|
}
|
|
|
|
internal void AddEntryLink(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems, Command command)
|
|
{
|
|
if (!String.IsNullOrEmpty(Key))
|
|
Key += Messages.GENERAL_PAGE_KVP_SEPARATOR;
|
|
DataGridViewExRow r = new DataGridViewExRow();
|
|
r.CreateCells(dataGridViewEx1);
|
|
r.Cells[0].Value = Key;
|
|
r.Cells[1] = new DataGridViewLinkCell();
|
|
r.Cells[1].Value = Value;
|
|
r.Cells[1].Tag = command;
|
|
r.Tag = contextMenuItems;
|
|
AddRow(r);
|
|
}
|
|
|
|
internal void AddEntryLink(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems, Action action)
|
|
{
|
|
if (!String.IsNullOrEmpty(Key))
|
|
Key += Messages.GENERAL_PAGE_KVP_SEPARATOR;
|
|
DataGridViewExRow r = new DataGridViewExRow();
|
|
r.CreateCells(dataGridViewEx1);
|
|
r.Cells[0].Value = Key;
|
|
r.Cells[1] = new DataGridViewLinkCell();
|
|
r.Cells[1].Value = Value;
|
|
r.Cells[1].Tag = action;
|
|
r.Tag = contextMenuItems;
|
|
AddRow(r);
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, ToolStripMenuItem contextMenuItem, bool visible)
|
|
{
|
|
AddEntry(Key, Value, new[] { contextMenuItem }, visible);
|
|
}
|
|
|
|
public void AddEntry(string Key, string Value, IEnumerable<ToolStripMenuItem> contextMenuItems, bool visible)
|
|
{
|
|
var r = CreateRow(Key, Value);
|
|
r.Tag = contextMenuItems;
|
|
r.Visible = visible;
|
|
AddRow(r);
|
|
}
|
|
|
|
public void UpdateEntryValueWithKey(string Key, string newValue, bool visible)
|
|
{
|
|
List<DataGridViewExRow> matchingRows = (from DataGridViewExRow row in dataGridViewEx1.Rows
|
|
where row.Cells[0].Value.ToString().Contains(Key)
|
|
select row).ToList();
|
|
|
|
if (matchingRows.Count != 1 || matchingRows[0].Cells.Count < 2)
|
|
return;
|
|
|
|
matchingRows[0].Cells[1].Value = newValue;
|
|
|
|
if (matchingRows[0].Visible != visible)
|
|
{
|
|
matchingRows[0].Visible = visible;
|
|
RefreshHeight();
|
|
}
|
|
}
|
|
|
|
internal void fixFirstColumnWidth(int width)
|
|
{
|
|
dataGridViewEx1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
|
|
dataGridViewEx1.Columns[0].Width = width;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the rows in the data grid view. If performing a repaint, you can attempt to restore the previous selection with a call to RestoreSelection()
|
|
/// </summary>
|
|
public void ClearData()
|
|
{
|
|
if (dataGridViewEx1.SelectedRows.Count > 0)
|
|
previousSelectionKey = dataGridViewEx1.SelectedRows[0].Cells[0].Value.ToString();
|
|
|
|
dataGridViewEx1.Rows.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restores selection to the row stored from the last ClearData() call
|
|
/// </summary>
|
|
public void RestoreSelection()
|
|
{
|
|
if (string.IsNullOrEmpty(previousSelectionKey))
|
|
return;
|
|
|
|
foreach (DataGridViewRow r in dataGridViewEx1.Rows)
|
|
{
|
|
if (r.Cells[0].Value.ToString() == previousSelectionKey)
|
|
{
|
|
r.Cells[0].Selected = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void PauseLayout()
|
|
{
|
|
inLayout = true;
|
|
}
|
|
|
|
public void StartLayout()
|
|
{
|
|
inLayout = false;
|
|
RefreshHeight();
|
|
}
|
|
}
|
|
}
|