xenadmin/XenAdmin/Controls/PDSection.cs
Konstantina Chremmou 9a006f3fbf CA-380723: Do not allow sync if an update repo is not configured.
Also, corrections to the sync button/link enabled state.

Signed-off-by: Konstantina Chremmou <Konstantina.Chremmou@cloud.com>
2023-08-07 15:15:38 +01:00

495 lines
17 KiB
C#

/* 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.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using XenAdmin.Controls.DataGridViewEx;
using XenAdmin.Core;
using System.Linq;
using XenAdmin.Commands;
namespace XenAdmin.Controls
{
public partial class PDSection : UserControl
{
#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();
SectionTitle = Messages.PDSECTION_TITLE;
IsExpanded = true;
Collapse();
MinimumSize = new Size(0, Height);
dataGridViewEx1.LostFocus += dataGridViewEx1_LostFocus;
dataGridViewEx1.GotFocus += dataGridViewEx1_GotFocus;
if (!Application.RenderWithVisualStyles)
{
panel1.BackColor = SystemColors.Control;
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)
RunCellCommandOrAction(dataGridViewEx1.Rows[e.RowIndex].Cells[e.ColumnIndex]);
}
private void dataGridViewEx1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
RunCellCommandOrAction(dataGridViewEx1.CurrentCell);
}
private void dataGridViewEx1_LostFocus(object sender, EventArgs e)
{
dataGridViewEx1.HideSelection = true;
}
private void dataGridViewEx1_GotFocus(object sender, EventArgs e)
{
dataGridViewEx1.HideSelection = false;
ContentReceivedFocus?.Invoke(this);
}
private void dataGridViewEx1_SelectionChanged(object sender, EventArgs e)
{
if (inLayout)
return;
ContentChangedSelection?.Invoke(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);
if (row.Tag is ToolStripMenuItem[] menuItems && menuItems.Length > 0)
{
contextMenuStrip1.Items.Add(new ToolStripSeparator());
contextMenuStrip1.Items.AddRange(menuItems.Cast<ToolStripItem>().ToArray());
}
contextMenuStrip1.Show(dataGridViewEx1, dataGridViewEx1.PointToClient(MousePosition));
}
private void dataGridViewEx1_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0 &&
e.ColumnIndex < dataGridViewEx1.ColumnCount && e.RowIndex < dataGridViewEx1.RowCount)
{
var row = dataGridViewEx1.Rows[e.RowIndex] as DataGridViewExRow;
var cell = row?.Cells[e.ColumnIndex];
if (row != null && row.Enabled && cell is DataGridViewLinkCell)
dataGridViewEx1.Cursor = Cursors.Hand;
else
dataGridViewEx1.Cursor = Cursors.Default;
}
}
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)
Collapse();
else
{
Expand();
dataGridViewEx1.Focus();
}
}
private void chevron_Click(object sender, EventArgs e)
{
if (IsExpanded)
Collapse();
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 RunCellCommandOrAction(DataGridViewCell cell)
{
if (cell == null)
return;
if (cell.Tag is Command command)
command.Run();
else if (cell.Tag is Action action)
action.Invoke();
}
private void RefreshHeight()
{
if (IsExpanded)
{
int newHeight = dataGridViewEx1.Rows.GetRowsHeight(DataGridViewElementStates.Visible);
int actualWidth = dataGridViewEx1.Width - KeyColumn.Width;
int preferredWidth = ValueColumn.GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true) +
ColumnNotes.GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);
int horizontalScrollBarHeight = preferredWidth - 2 >= actualWidth
? 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 ? Images.StaticImages.PDChevronUpOver : Images.StaticImages.PDChevronUp;
}
else
{
chevron.Image = chevronHot ? Images.StaticImages.PDChevronDownOver : Images.StaticImages.PDChevronDown;
}
}
private void AddRow(DataGridViewCell keyCell, DataGridViewCell valueCell, DataGridViewCell noteCell, bool enabled, params ToolStripMenuItem[] contextMenuItems)
{
var r = new DataGridViewExRow();
r.Cells.AddRange(keyCell, valueCell, noteCell ?? new DataGridViewTextBoxCell());
r.Tag = contextMenuItems;
dataGridViewEx1.Rows.Add(r);
r.Enabled = enabled;
if (inLayout)
return;
RefreshHeight();
}
private static DataGridViewTextBoxCell CreateKeyCell(string key)
{
if (!string.IsNullOrEmpty(key))
key += Messages.GENERAL_PAGE_KVP_SEPARATOR;
var cell = new DataGridViewTextBoxCell { Value = key };
return cell;
}
private void ToggleExpandedState(bool expand)
{
if (IsExpanded == expand)
return;
IsExpanded = expand;
dataGridViewEx1.Visible = expand;
RefreshHeight();
RefreshChevron();
if (ExpandedChanged != null)
ExpandedChanged(this);
}
#endregion
public void Collapse()
{
ToggleExpandedState(false);
}
public void Expand()
{
ToggleExpandedState(true);
}
public void AddEntry(string key, string value, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewTextBoxCell { Value = value };
AddRow(CreateKeyCell(key), valueCell, null, true, contextMenuItems);
}
public void AddEntry(string key, string value, Color fontColor, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewTextBoxCell { Value = value };
AddRow(CreateKeyCell(key), valueCell, null, true, contextMenuItems);
valueCell.Style.ForeColor = fontColor;
}
public void AddEntry(string key, FolderListItem value, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new FolderCell(value); // CA-33311
AddRow(CreateKeyCell(key), valueCell, null, true, contextMenuItems);
}
internal void AddEntryLink(string key, string value, Command command, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewLinkCell { Value = value, Tag = command };
AddRow(CreateKeyCell(key), valueCell, null, true, contextMenuItems);
}
internal void AddEntryLink(string key, string value, Action action, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewLinkCell { Value = value, Tag = action };
AddRow(CreateKeyCell(key), valueCell, null, true, contextMenuItems);
}
internal void AddEntryWithNoteLink(string key, string value, string note, Action action, bool enabled, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewTextBoxCell { Value = value };
var noteCell = new DataGridViewLinkCell { Value = note, Tag = action };
if (!enabled)
noteCell.LinkColor = SystemColors.GrayText;
AddRow(CreateKeyCell(key), valueCell, noteCell, enabled, contextMenuItems);
}
internal void AddEntryWithNoteLink(string key, string value, string note, Action action, Color fontColor, params ToolStripMenuItem[] contextMenuItems)
{
var valueCell = new DataGridViewTextBoxCell { Value = value };
var noteCell = new DataGridViewLinkCell { Value = note, Tag = action };
valueCell.Style.ForeColor = fontColor;
valueCell.Style.SelectionForeColor = fontColor;
AddRow(CreateKeyCell(key), valueCell, noteCell, true, contextMenuItems);
}
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].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();
}
}
}