2016-09-26 18:44:17 +02:00
|
|
|
|
/* 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;
|
2016-10-05 15:12:24 +02:00
|
|
|
|
using System.ComponentModel;
|
2016-09-26 18:44:17 +02:00
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using XenAdmin.Actions;
|
|
|
|
|
using XenAdmin.Controls;
|
|
|
|
|
using XenAdmin.Core;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
using XenAdmin.Network;
|
|
|
|
|
using XenAdmin.SettingsPanels;
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.Dialogs
|
|
|
|
|
{
|
|
|
|
|
public partial class PvsCacheConfigurationDialog : VerticallyTabbedDialog
|
|
|
|
|
{
|
|
|
|
|
public PvsCacheConfigurationDialog(IXenConnection connection)
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
System.Diagnostics.Trace.Assert(connection != null);
|
|
|
|
|
this.connection = connection;
|
|
|
|
|
|
|
|
|
|
Text = string.Format(Messages.PVS_CACHE_CONFIG_DIALOG_TITLE, connection.Name);
|
|
|
|
|
|
|
|
|
|
Rebuild();
|
2016-10-05 15:12:24 +02:00
|
|
|
|
this.connection.Cache.RegisterCollectionChanged<PVS_site>(PvsSiteCollectionChanged);
|
2016-09-26 18:44:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override string GetTabTitle(VerticalTabs.VerticalTab verticalTab)
|
|
|
|
|
{
|
|
|
|
|
PvsCacheConfigurationPage page = verticalTab as PvsCacheConfigurationPage;
|
|
|
|
|
if (page != null)
|
|
|
|
|
{
|
|
|
|
|
return page.Text;
|
|
|
|
|
}
|
|
|
|
|
return base.GetTabTitle(verticalTab);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Rebuild()
|
|
|
|
|
{
|
|
|
|
|
ContentPanel.SuspendLayout();
|
|
|
|
|
verticalTabs.BeginUpdate();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
verticalTabs.Items.Clear();
|
|
|
|
|
|
|
|
|
|
var pvsSites = connection.Cache.PVS_sites.ToList();
|
|
|
|
|
pvsSites.Sort();
|
|
|
|
|
|
|
|
|
|
foreach (var pvsSite in pvsSites)
|
|
|
|
|
{
|
|
|
|
|
NewPage(pvsSite);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
ContentPanel.ResumeLayout();
|
|
|
|
|
verticalTabs.EndUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verticalTabs.Items.Count > 0)
|
|
|
|
|
verticalTabs.SelectedIndex = 0;
|
|
|
|
|
ResizeVerticalTabs(verticalTabs.Items.Count);
|
|
|
|
|
verticalTabs.AdjustItemTextBounds = GetItemTextBounds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Rectangle GetItemTextBounds(Rectangle itemBounds)
|
|
|
|
|
{
|
|
|
|
|
return new Rectangle(itemBounds.X, itemBounds.Y, itemBounds.Width - 20, itemBounds.Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PvsCacheConfigurationPage NewPage(PVS_site pvsSite)
|
|
|
|
|
{
|
|
|
|
|
var existingTabNames = (from PvsCacheConfigurationPage page in verticalTabs.Items select page.Text).ToList();
|
|
|
|
|
PvsCacheConfigurationPage editPage = new PvsCacheConfigurationPage(connection, existingTabNames);
|
|
|
|
|
var pvsSiteCopy = pvsSite != null ? pvsSite.Clone() : null;
|
|
|
|
|
editPage.SetXenObjects(pvsSite, pvsSiteCopy);
|
|
|
|
|
editPage.Changed += SomethingChangedOnPage;
|
2016-09-27 17:34:26 +02:00
|
|
|
|
editPage.DeleteButtonClicked += DeleteButtonClickedOnPage;
|
2016-09-26 18:44:17 +02:00
|
|
|
|
ShowTab(editPage);
|
|
|
|
|
RefreshButtons();
|
|
|
|
|
return editPage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ShowTab(IEditPage editPage)
|
|
|
|
|
{
|
|
|
|
|
var pageAsControl = (Control)editPage;
|
|
|
|
|
ContentPanel.Controls.Add(pageAsControl);
|
|
|
|
|
pageAsControl.BackColor = Color.Transparent;
|
|
|
|
|
pageAsControl.Dock = DockStyle.Fill;
|
|
|
|
|
|
|
|
|
|
verticalTabs.Items.Add(editPage);
|
|
|
|
|
}
|
2016-10-01 01:23:28 +02:00
|
|
|
|
|
2016-09-26 18:44:17 +02:00
|
|
|
|
void DeletePage(PvsCacheConfigurationPage page)
|
|
|
|
|
{
|
2016-10-05 10:51:23 +02:00
|
|
|
|
// try to delete the site (asks user for confirmation), also passing the site name, in case it has changed
|
|
|
|
|
if (!DeleteSite(page.PvsSite, page.Text))
|
2016-10-01 01:23:28 +02:00
|
|
|
|
return;
|
2016-09-26 18:44:17 +02:00
|
|
|
|
int selectedIndex = verticalTabs.SelectedIndex;
|
|
|
|
|
verticalTabs.Items.Remove(page);
|
|
|
|
|
verticalTabs.SelectedIndex = selectedIndex < verticalTabs.Items.Count - 1 ? selectedIndex : verticalTabs.Items.Count - 1;
|
|
|
|
|
page.Changed -= SomethingChangedOnPage;
|
2016-09-27 17:34:26 +02:00
|
|
|
|
page.DeleteButtonClicked -= DeleteButtonClickedOnPage;
|
2016-09-26 18:44:17 +02:00
|
|
|
|
ContentPanel.Controls.Remove(page);
|
|
|
|
|
RefreshButtons();
|
|
|
|
|
ResizeVerticalTabs(verticalTabs.Items.Count);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 10:51:23 +02:00
|
|
|
|
private bool DeleteSite(PVS_site site, string siteName)
|
2016-10-01 01:23:28 +02:00
|
|
|
|
{
|
2016-10-03 11:51:56 +02:00
|
|
|
|
// We cannot delete the site if there are running proxies
|
2016-10-05 10:51:23 +02:00
|
|
|
|
if (site != null)
|
|
|
|
|
{
|
|
|
|
|
var pvsProxies = connection.Cache.PVS_proxies.Where(s => s.site.opaque_ref == site.opaque_ref).ToList();
|
|
|
|
|
if (pvsProxies.Count > 0)
|
2016-10-03 11:51:56 +02:00
|
|
|
|
{
|
2016-10-05 10:51:23 +02:00
|
|
|
|
using (var dlg =
|
|
|
|
|
new ThreeButtonDialog(new ThreeButtonDialog.Details(SystemIcons.Warning, Messages.PVS_SITE_CANNOT_BE_REMOVED, Messages.XENCENTER)))
|
|
|
|
|
{
|
|
|
|
|
dlg.ShowDialog(Parent);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2016-10-03 11:51:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 10:51:23 +02:00
|
|
|
|
// show confirmation dialog
|
2016-10-28 17:58:15 +02:00
|
|
|
|
var message = site != null && !string.IsNullOrEmpty(site.PVS_uuid)
|
|
|
|
|
? string.Format(Messages.CONFIRM_DELETE_PVS_SITE_IN_USE, siteName)
|
|
|
|
|
: string.Format(Messages.CONFIRM_DELETE_PVS_SITE, siteName);
|
2016-10-01 01:23:28 +02:00
|
|
|
|
DialogResult dialogResult;
|
|
|
|
|
using (var dlg = new ThreeButtonDialog(
|
2016-10-28 17:58:15 +02:00
|
|
|
|
new ThreeButtonDialog.Details(SystemIcons.Warning, message, Messages.XENCENTER),
|
2016-10-01 01:23:28 +02:00
|
|
|
|
ThreeButtonDialog.ButtonOK,
|
|
|
|
|
ThreeButtonDialog.ButtonCancel))
|
|
|
|
|
{
|
|
|
|
|
dialogResult = dlg.ShowDialog(Parent);
|
|
|
|
|
}
|
|
|
|
|
if (dialogResult != DialogResult.OK)
|
|
|
|
|
return false;
|
2016-10-05 10:51:23 +02:00
|
|
|
|
|
|
|
|
|
// if it is a newly added site, then there's noting we need to do here (it does not exist on the server yet)
|
|
|
|
|
if (site == null)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// delete existing site
|
2016-10-01 01:23:28 +02:00
|
|
|
|
var action = new DeletePvsSiteAction(site);
|
|
|
|
|
new ActionProgressDialog(action, ProgressBarStyle.Blocks).ShowDialog(this);
|
|
|
|
|
return action.Succeeded;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 18:44:17 +02:00
|
|
|
|
private void ResizeVerticalTabs(int itemCount)
|
|
|
|
|
{
|
|
|
|
|
int maxHeight = splitContainer.Panel1.Height - AddButton.Height;
|
|
|
|
|
verticalTabs.Height = Math.Min(maxHeight, itemCount * verticalTabs.ItemHeight);
|
|
|
|
|
AddButton.Top = verticalTabs.Top + verticalTabs.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SomethingChangedOnPage(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
RefreshButtons();
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 17:34:26 +02:00
|
|
|
|
private void DeleteButtonClickedOnPage(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var page = sender as PvsCacheConfigurationPage;
|
|
|
|
|
if (page != null)
|
|
|
|
|
{
|
|
|
|
|
DeletePage(page);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 18:44:17 +02:00
|
|
|
|
void RefreshButtons()
|
|
|
|
|
{
|
|
|
|
|
okButton.Enabled = AllPagesValid();
|
2016-09-27 17:34:26 +02:00
|
|
|
|
addSiteButton.Visible = verticalTabs.Items.Count == 0;
|
2016-09-26 18:44:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool AllPagesValid()
|
|
|
|
|
{
|
|
|
|
|
return verticalTabs.Items.Cast<PvsCacheConfigurationPage>().All(page => page.ValidToSave);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void splitContainer_Panel1_Resize(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ResizeVerticalTabs(verticalTabs.Items.Count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void verticalTabs_DrawItem(object sender, DrawItemEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Index < 0 || e.Index >= verticalTabs.Items.Count)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PvsCacheConfigurationPage page = verticalTabs.Items[e.Index] as PvsCacheConfigurationPage;
|
|
|
|
|
if (page == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Graphics g = e.Graphics;
|
|
|
|
|
Rectangle b = e.Bounds;
|
|
|
|
|
|
|
|
|
|
// draw Delete icon
|
|
|
|
|
Image deleteIcon = Properties.Resources._000_Abort_h32bit_16;
|
|
|
|
|
if (deleteIcon != null)
|
|
|
|
|
{
|
|
|
|
|
page.DeleteIconBounds = new Rectangle(b.Right - deleteIcon.Width - ((32 - deleteIcon.Width) / 2),
|
|
|
|
|
b.Y + ((32 - deleteIcon.Height) / 2), deleteIcon.Width, deleteIcon.Height);
|
|
|
|
|
g.DrawImage(deleteIcon, page.DeleteIconBounds);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool MouseIsOnDeleteIcon(Point mouseLocation)
|
|
|
|
|
{
|
|
|
|
|
int pageIndex = verticalTabs.IndexFromPoint(mouseLocation);
|
|
|
|
|
if (pageIndex < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
PvsCacheConfigurationPage page = verticalTabs.Items[pageIndex] as PvsCacheConfigurationPage;
|
|
|
|
|
if (page == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var bounds = page.DeleteIconBounds;
|
|
|
|
|
return bounds.Contains(mouseLocation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void verticalTabs_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (MouseIsOnDeleteIcon(e.Location))
|
|
|
|
|
ShowTooltip(e.Location);
|
|
|
|
|
else
|
|
|
|
|
HideTooltip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void verticalTabs_MouseClick(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int pageIndex = verticalTabs.IndexFromPoint(e.Location);
|
|
|
|
|
if (pageIndex < 0 || !MouseIsOnDeleteIcon(e.Location))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
PvsCacheConfigurationPage page = verticalTabs.Items[pageIndex] as PvsCacheConfigurationPage;
|
|
|
|
|
if (page != null)
|
|
|
|
|
{
|
|
|
|
|
DeletePage(page);
|
|
|
|
|
HideTooltip();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private readonly ToolTip toolTipRemove = new ToolTip();
|
|
|
|
|
private bool tooltipVisible;
|
|
|
|
|
|
|
|
|
|
private void ShowTooltip(Point location)
|
|
|
|
|
{
|
|
|
|
|
if (!tooltipVisible)
|
|
|
|
|
{
|
|
|
|
|
toolTipRemove.Show(Messages.REMOVE, verticalTabs, location.X, location.Y + 20);
|
|
|
|
|
tooltipVisible = true;
|
|
|
|
|
Cursor = Cursors.Hand;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HideTooltip()
|
|
|
|
|
{
|
|
|
|
|
toolTipRemove.Hide(verticalTabs);
|
|
|
|
|
tooltipVisible = false;
|
|
|
|
|
Cursor = Cursors.Default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddButton_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
ResizeVerticalTabs(verticalTabs.Items.Count + 1);
|
|
|
|
|
verticalTabs.SelectedItem = NewPage(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void okButton_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
List<AsyncAction> actions = GetActions();
|
2016-10-01 01:23:28 +02:00
|
|
|
|
|
2016-09-26 18:44:17 +02:00
|
|
|
|
if (actions.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var multipleAction = new MultipleAction(
|
|
|
|
|
connection,
|
|
|
|
|
string.Format(Messages.UPDATE_PROPERTIES, Helpers.GetName(connection).Ellipsise(50)),
|
|
|
|
|
Messages.UPDATING_PROPERTIES,
|
|
|
|
|
Messages.UPDATED_PROPERTIES,
|
|
|
|
|
actions, true);
|
|
|
|
|
|
|
|
|
|
multipleAction.RunAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<AsyncAction> GetActions()
|
|
|
|
|
{
|
|
|
|
|
List<AsyncAction> actions = new List<AsyncAction>();
|
|
|
|
|
|
|
|
|
|
foreach (IEditPage editPage in verticalTabs.Items)
|
|
|
|
|
{
|
|
|
|
|
if (!editPage.HasChanged)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
AsyncAction action = editPage.SaveSettings();
|
|
|
|
|
if (action != null)
|
|
|
|
|
actions.Add(action);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return actions;
|
|
|
|
|
}
|
2016-10-05 15:12:24 +02:00
|
|
|
|
|
|
|
|
|
private void PvsSiteCollectionChanged(object sender, CollectionChangeEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Action == CollectionChangeAction.Add)
|
|
|
|
|
{
|
|
|
|
|
PVS_site addedSite = e.Element as PVS_site;
|
|
|
|
|
|
|
|
|
|
Program.Invoke(this, () =>
|
|
|
|
|
{
|
|
|
|
|
ResizeVerticalTabs(verticalTabs.Items.Count + 1);
|
|
|
|
|
NewPage(addedSite);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PvsCacheConfigurationDialog_FormClosed(object sender, FormClosedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
this.connection.Cache.DeregisterCollectionChanged<PVS_site>(PvsSiteCollectionChanged);
|
|
|
|
|
}
|
2016-09-26 18:44:17 +02:00
|
|
|
|
}
|
|
|
|
|
}
|