xenadmin/XenAdmin/TabPages/SnapshotsPage.cs
Konstantina Chremmou ae22560ce8 Converted all extension get properties of the API classes to methods in order to
prevent them from being serialised alongside the API properties. This will also
be useful for moving the API bindings out of XenModel.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
2017-09-03 03:35:30 +01:00

1523 lines
59 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.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.Windows.Forms;
using XenAdmin.Actions;
using XenAdmin.Controls;
using XenAdmin.CustomFields;
using XenAdmin.Dialogs;
using XenAdmin.Model;
using XenAPI;
using System.Diagnostics;
using XenAdmin.Properties;
using XenAdmin.Core;
using XenAdmin.Commands;
namespace XenAdmin.TabPages
{
public sealed partial class SnapshotsPage : BaseTabPage
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private VM m_VM = null;
private bool m_NeedToUpdate = false;
private float defaultWidthProperties;
private readonly ToolTip toolTipDescriptionLabel = new ToolTip();
private readonly ToolTip toolTipFolderLabel = new ToolTip();
private readonly ToolTip toolTipTagsLabel = new ToolTip();
private enum SnapshotsView
{
ListView,
TreeView
}
private Dictionary<string, SnapshotsView> _storedViewsPerVm = new Dictionary<string, SnapshotsView>();
public SnapshotsPage()
{
InitializeComponent();
viewToolStripMenuItem.DropDown = contextMenuStripView;
this.DoubleBuffered = true;
base.Text = Messages.SNAPSHOTS_PAGE_TITLE;
dataGridView.TabIndex = snapshotTreeView.TabIndex;
dataGridView.Sorted += DataGridView_Sorted;
ConnectionsManager.History.CollectionChanged += History_CollectionChanged;
}
void DataGridView_Sorted(object sender, EventArgs e)
{
switch (dataGridView.SortedColumn.Index)
{
case 0:
sortByTypeToolStripMenuItem.Checked = true;
sortByNameToolStripMenuItem.Checked = false;
sortByCreatedOnToolStripMenuItem.Checked = false;
sortBySizeToolStripMenuItem.Checked = false;
break;
case 1:
sortByTypeToolStripMenuItem.Checked = false;
sortByNameToolStripMenuItem.Checked = true;
sortByCreatedOnToolStripMenuItem.Checked = false;
sortBySizeToolStripMenuItem.Checked = false;
break;
case 2:
sortByTypeToolStripMenuItem.Checked = false;
sortByNameToolStripMenuItem.Checked = false;
sortByCreatedOnToolStripMenuItem.Checked = true;
sortBySizeToolStripMenuItem.Checked = false;
break;
case 3:
sortByTypeToolStripMenuItem.Checked = false;
sortByNameToolStripMenuItem.Checked = false;
sortByCreatedOnToolStripMenuItem.Checked = false;
sortBySizeToolStripMenuItem.Checked = true;
break;
}
}
public VM VM
{
set
{
UnregisterHandlers();
if (value != null)
{
m_VM = value;
Program.Invoke(Program.MainWindow, () => snapshotTreeView.ChangeVMToSpinning(false, null));
m_VM.Connection.Cache.RegisterBatchCollectionChanged<VM>(
VM_BatchCollectionChanged);
m_VM.PropertyChanged += snapshot_PropertyChanged;
//Version setup
toolStripMenuItemScheduledSnapshots.Available = toolStripSeparatorView.Available = !Helpers.FeatureForbidden(VM.Connection, Host.RestrictVMSnapshotSchedule);
if (_storedViewsPerVm.ContainsKey(m_VM.opaque_ref) && _storedViewsPerVm[m_VM.opaque_ref] != SnapshotsView.ListView)
TreeViewChecked();
else
GridViewChecked();
toolStripButtonTreeView.Enabled = true;
toolStripButtonTreeView.ToolTipText = "";
revertButton.Enabled = true;
toolTipContainerRevertButton.SetToolTip("");
//toolStripButtonListView.Enabled = toolStripButtonTreeView.Enabled = true;
//Refresh items
BuildList();
RefreshDetailsGroupBox(true);
RefreshToolStripButtons();
RefreshVMSSPanel();
}
}
get
{
return m_VM;
}
}
private void RefreshVMSSPanel()
{
if (Helpers.FalconOrGreater(VM.Connection))
{
panelVMPP.Visible = true;
var vmss = VM.Connection.Resolve(VM.snapshot_schedule);
if (vmss == null || Helpers.FeatureForbidden(VM.Connection, Host.RestrictVMSnapshotSchedule))
{
labelVMPPInfo.Text = Messages.THIS_VM_IS_NOT_IN_VMSS;
pictureBoxVMPPInfo.Image = Resources._000_BackupMetadata_h32bit_16;
linkLabelVMPPInfo.Text = Helpers.FeatureForbidden(VM.Connection, Host.RestrictVMSnapshotSchedule) ? Messages.TELL_ME_MORE : Messages.VIEW_VMSS_POLICIES;
}
else
{
labelVMPPInfo.Text = string.Format(Messages.THIS_VM_IS_IN_VMSS, vmss.Name());
pictureBoxVMPPInfo.Image = Resources._000_Tick_h32bit_16;
linkLabelVMPPInfo.Text = Messages.VIEW_VMSS_POLICIES;
}
}
else
{
panelVMPP.Visible = false;
}
}
private void UpdateSpinningIcon()
{
ActionBase action = ConnectionsManager.History.Find(SpinningPredicate());
if (action != null)
{
string message = action is VMSnapshotCreateAction ? Messages.SNAPSHOTTING : Messages.VM_REVERTING_ELLIPSIS;
Program.Invoke(Program.MainWindow, () => snapshotTreeView.ChangeVMToSpinning(true, message));
}
}
private Predicate<ActionBase> SpinningPredicate()
{
return a => a.VM == VM && !a.IsCompleted && (a is VMSnapshotCreateAction || a is VMSnapshotRevertAction);
}
private void History_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
//Program.AssertOnEventThread();
Program.BeginInvoke(Program.MainWindow, () =>
{
if (e.Action == CollectionChangeAction.Add &&
(e.Element is VMSnapshotCreateAction ||
e.Element is VMSnapshotRevertAction))
{
ActionBase createAction = (ActionBase)e.Element;
createAction.Completed += CreateActionCompleted;
string message = createAction is VMSnapshotCreateAction
? Messages.SNAPSHOTTING
: Messages.VM_REVERTING_ELLIPSIS;
if (snapshotTreeView.SpinningMessage != Messages.SNAPSHOTTING)
Program.Invoke(Program.MainWindow,
() =>
snapshotTreeView.ChangeVMToSpinning(true,
message));
}
});
}
private void CreateActionCompleted(ActionBase senderAction)
{
senderAction.Completed -= CreateActionCompleted;
ActionBase action = ConnectionsManager.History.Find(SpinningPredicate());
if (action == null)
{
Program.Invoke(Program.MainWindow, () => snapshotTreeView.ChangeVMToSpinning(false, null));
}
}
private void VM_BatchCollectionChanged(object sender, EventArgs e)
{
if (m_NeedToUpdate)
{
BuildList();
RefreshDetailsGroupBox(true);
#if DEBUG
Debug.WriteLine("Refreshing the list of snapshots...");
#endif
}
m_NeedToUpdate = false;
}
private void UnregisterHandlers()
{
if (m_VM == null)
return;
m_VM.Connection.Cache.DeregisterBatchCollectionChanged<VM>(VM_BatchCollectionChanged);
m_VM.PropertyChanged -= snapshot_PropertyChanged;
foreach (VM snapshot in m_VM.Connection.ResolveAll<VM>(m_VM.snapshots))
{
snapshot.PropertyChanged -= snapshot_PropertyChanged;
}
}
public override void PageHidden()
{
UnregisterHandlers();
}
private void BuildList()
{
if (!this.Visible)
return;
lock (snapshotTreeView)
{
if (VM == null || VM.snapshots == null)
return;
var snapshots = VM.Connection.ResolveAll(VM.snapshots);
if (snapshots.Count == 0)
{
snapshotTreeView.Clear();
TreeViewChecked();
RefreshDetailsGroupBox(true);
toolStripButtonTreeView.Enabled = toolStripButtonListView.Enabled = false; ;
return;
}
toolStripButtonListView.Enabled = true;
IList<VM> roots = RefreshDataGridView(snapshots);
toolStripButtonTreeView.Enabled = true;
RefreshTreeView(roots);
SelectPreviousItemVMTreeView();
UpdateSpinningIcon();
}
}
private void SelectPreviousItemVMTreeView()
{
if (snapshotTreeView.Items.Count > 0)
{
snapshotTreeView.Select();
foreach (ListViewItem item in snapshotTreeView.Items)
{
if (item.ImageIndex == SnapshotIcon.VMImageIndex)
{
SnapshotIcon icon = item as SnapshotIcon;
if (icon == null) continue;
if (icon.Parent.Selectable)
{
icon.Parent.Selected = true;
icon.Parent.Focused = true;
break;
}
else
{
foreach (SnapshotIcon sibling in icon.Parent.Children)
{
if (sibling.Selectable)
{
sibling.Selected = true;
sibling.Focused = true;
break;
}
}
break;
}
}
}
}
else
{
RefreshDetailsGroupBox(true);
}
}
private void RefreshTreeView(IList<VM> roots)
{
if (snapshotTreeView.Parent == null) return;
snapshotTreeView.SuspendLayout();
snapshotTreeView.BeginUpdate();
snapshotTreeView.Clear();
Debug.WriteLine("Start refreshing Tree");
SnapshotIcon rootIcon = null;
rootIcon = new SnapshotIcon(VM.Name(), Messages.BASE, null, snapshotTreeView, SnapshotIcon.Template);
snapshotTreeView.AddSnapshot(rootIcon);
//Set VM
VM vmParent = VM.Connection.Resolve<VM>(VM.parent);
if (vmParent == null || !vmParent.is_a_snapshot)
{
SnapshotIcon vmIcon = new SnapshotIcon(Messages.NOW, "", rootIcon, snapshotTreeView, SnapshotIcon.VMImageIndex);
snapshotTreeView.AddSnapshot(vmIcon);
}
foreach (VM root in roots)
{
if (!((root.is_snapshot_from_vmpp || root.is_vmss_snapshot) && !toolStripMenuItemScheduledSnapshots.Checked))
{
int icon;
if (root.is_snapshot_from_vmpp || root.is_vmss_snapshot)
icon = root.power_state == vm_power_state.Suspended ? SnapshotIcon.ScheduledDiskMemorySnapshot : SnapshotIcon.ScheduledDiskSnapshot;
else
icon = root.power_state == vm_power_state.Suspended ? SnapshotIcon.DiskAndMemorySnapshot : SnapshotIcon.DiskSnapshot;
DateTime time = root.snapshot_time.ToLocalTime() + root.Connection.ServerTimeOffset;
SnapshotIcon currentIcon = new SnapshotIcon(root.name_label, HelpersGUI.DateTimeToString(time, Messages.DATEFORMAT_DMY_HMS, true), rootIcon, snapshotTreeView, icon);
snapshotTreeView.AddSnapshot(currentIcon);
currentIcon.Tag = root;
BuildTree(root, currentIcon);
}
else
BuildTree(root, rootIcon);
}
if (snapshotTreeView.Items.Count < 4)
snapshotTreeView.Clear();
snapshotTreeView.EndUpdate();
snapshotTreeView.ResumeLayout();
snapshotTreeView.PerformLayout();
}
private void RefreshDataGridView()
{
IList<VM> snapshots = VM.Connection.ResolveAll(VM.snapshots);
if (snapshots.Count == 0)
{
snapshotTreeView.Clear();
TreeViewChecked();
return;
}
RefreshDataGridView(snapshots);
}
private IList<VM> RefreshDataGridView(IList<VM> snapshots)
{
dataGridView.Rows.Clear();
IList<VM> roots = new List<VM>();
for (int i = 0; i < snapshots.Count; i++)
{
VM snapshot = snapshots[i];
if (!(snapshot.is_snapshot_from_vmpp || snapshot.is_vmss_snapshot) || toolStripMenuItemScheduledSnapshots.Checked)
{
snapshot.PropertyChanged -= snapshot_PropertyChanged;
snapshot.PropertyChanged += snapshot_PropertyChanged;
//Build DataGridView
SnapshotDataGridViewRow row = new SnapshotDataGridViewRow(snapshot);
row.Tag = snapshot;
dataGridView.Rows.Add(row);
}
VM parent = VM.Connection.Resolve<VM>(snapshot.parent);
if (parent == null)
roots.Add(snapshot);
else if (!snapshots.Contains(parent) && !roots.Contains(parent))
roots.Add(snapshot);
}
if (dataGridView.SortedColumn == null)
dataGridView.Sort(dataGridView.Columns[1], ListSortDirection.Ascending);
return roots;
}
private class SnapshotDataGridViewRow : DataGridViewRow
{
private DataGridViewTextBoxCell _type = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _name = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _creationTime = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _size = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _tags = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _description = new DataGridViewTextBoxCell();
private DataGridViewTextBoxCell _sortType = new DataGridViewTextBoxCell();
public SnapshotDataGridViewRow(VM snapshot)
{
//Icon
this.Cells.Add(_type);
_type.Value = snapshot.power_state == vm_power_state.Suspended
? Messages.DISKS_AND_MEMORY
: Messages.DISKS_ONLY;
//Name
Cells.Add(_name);
_name.Value = snapshot.name_label;
//Created On
Cells.Add(_creationTime);
_creationTime.Value = HelpersGUI.DateTimeToString(snapshot.snapshot_time.ToLocalTime() + snapshot.Connection.ServerTimeOffset, Messages.DATEFORMAT_DMY_HMS, true);
//Size
Cells.Add(_size);
_size.Value = GetStringSnapshotSize(snapshot);
//Tags
Cells.Add(_tags);
_tags.Value = ConcatWithSeparator(Tags.GetTags(snapshot), ", ");
//Description
Cells.Add(_description);
_description.Value = snapshot.Description() != ""
? snapshot.Description()
: Messages.NONE;
}
}
void snapshot_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "current_operations")
{
VM vm = null;
if (sender is VM)
vm = ((VM)sender);
else
vm = (VM)sender;
if (vm.current_operations.Count == 0 && !vm.is_a_snapshot)
m_NeedToUpdate = true;
#if DEBUG
foreach (KeyValuePair<string, vm_operations> op in vm.current_operations)
{
Debug.WriteLine(vm.name_label + " " + op.Value);
}
if (vm.current_operations.Count == 0)
Debug.WriteLine("End of operation");
#endif
}
switch (e.PropertyName)
{
case "name_label":
BuildList();
RefreshDetailsGroupBox(true);
break;
case "name_description":
case "tags":
case "other_config":
case "Path":
RefreshDetailsGroupBox(true);
RefreshDataGridView();
RefreshToolStripButtons();
break;
case "snapshots":
m_NeedToUpdate = true;
break;
}
}
private static string GetStringSnapshotSize(VM snapshot)
{
long size = GetSnapshotSize(snapshot);
return Util.DiskSizeString(size);
}
private static long GetSnapshotSize(VM snapshot)
{
long size = 0;
foreach (VBD vbd in snapshot.Connection.ResolveAll(snapshot.VBDs))
{
if (vbd.type == vbd_type.Disk)
{
VDI vdi = snapshot.Connection.Resolve(vbd.VDI);
if (vdi == null || vdi.physical_utilisation == -1)
continue;
size += vdi.physical_utilisation;
}
}
VDI suspendedVdi = snapshot.Connection.Resolve(snapshot.suspend_VDI);
if (suspendedVdi != null && suspendedVdi.physical_utilisation > 0)
size += suspendedVdi.physical_utilisation;
return size;
}
private void BuildTree(VM currentNode, SnapshotIcon currentIcon)
{
//Set VM
if (VM.Connection.Resolve<VM>(VM.parent) == currentNode)
{
SnapshotIcon vmIcon = new SnapshotIcon(Messages.NOW, "", currentIcon, snapshotTreeView, SnapshotIcon.VMImageIndex);
snapshotTreeView.AddSnapshot(vmIcon);
}
//Do childs
foreach (XenRef<VM> child in currentNode.children)
{
if (VM.snapshots.Contains(child))
{
VM childSnapshot = VM.Connection.Resolve<VM>(child);
if (!((childSnapshot.is_snapshot_from_vmpp || childSnapshot.is_vmss_snapshot) && !toolStripMenuItemScheduledSnapshots.Checked))
{
int icon;
if (childSnapshot.is_snapshot_from_vmpp || childSnapshot.is_vmss_snapshot)
icon = childSnapshot.power_state == vm_power_state.Suspended ? SnapshotIcon.ScheduledDiskMemorySnapshot : SnapshotIcon.ScheduledDiskSnapshot;
else
icon = childSnapshot.power_state == vm_power_state.Suspended ? SnapshotIcon.DiskAndMemorySnapshot : SnapshotIcon.DiskSnapshot;
DateTime time = childSnapshot.snapshot_time.ToLocalTime() + childSnapshot.Connection.ServerTimeOffset;
SnapshotIcon childIcon = new SnapshotIcon(childSnapshot.name_label, HelpersGUI.DateTimeToString(time, Messages.DATEFORMAT_DMY_HMS, true), currentIcon, snapshotTreeView, icon);
snapshotTreeView.AddSnapshot(childIcon);
childIcon.Tag = childSnapshot;
BuildTree(childSnapshot, childIcon);
}
else
BuildTree(childSnapshot, currentIcon);
}
}
}
private void view_SelectionChanged(object sender, System.EventArgs e)
{
RefreshDetailsGroupBox(false);
RefreshToolStripButtons();
snapshotTreeView.Invalidate();
}
private void RefreshToolStripButtons()
{
IList<VM> snapshots = GetSelectedSnapshots();
if (snapshots != null && snapshots.Count == 1)
EnableAllButtons();
else if (snapshots != null && snapshots.Count > 1)
EnableDelete();
else
DisableAllButtons();
}
private void DisableAllButtons()
{
revertButton.Enabled = false;
toolTipContainerRevertButton.SetToolTip("");
saveButton.Enabled = false;
deleteButton.Enabled = false;
}
private void EnableAllButtons()
{
revertButton.Enabled = true;
saveButton.Enabled = true;
deleteButton.Enabled = true;
}
private void EnableDelete()
{
revertButton.Enabled = false;
toolTipContainerRevertButton.SetToolTip("");
saveButton.Enabled = false;
deleteButton.Enabled = true;
}
private void RefreshDetailsGroupBox(bool force)
{
IList<VM> selectedSnaps = GetSelectedSnapshots();
if (selectedSnaps == null || selectedSnaps.Count == 0)
{
ShowDisabledPanel();
}
else if (toolStripButtonListView.Checked && selectedSnaps.Count == 1)
{
ShowDetailsPanel(selectedSnaps[0], force);
}
else if (toolStripButtonTreeView.Checked && selectedSnaps.Count == 1)
{
ShowDetailsPanel(selectedSnaps[0], force);
}
else if (selectedSnaps.Count > 1)
{
ShowDetailsPanelMultipleSelection(selectedSnaps);
}
else
{
ShowDisabledPanel();
}
}
private void ShowDisabledPanel()
{
propertiesGroupBox.Enabled = false;
propertiesGroupBox.Tag = null;
propertiesTableLayoutPanel.Controls.Remove(tableLayoutPanelMultipleSelection);
propertiesTableLayoutPanel.Controls.Add(tableLayoutPanelSimpleSelection, 0, 2);
propertiesGroupBox.Text = String.Format(Messages.SNAPSHOT_CREATED_ON, "");
nameLabel.Text = "";
sizeLabel.Text = "";
labelMode.Text = "";
descriptionLabel.Text = "";
tagsLabel.Text = "";
folderLabel.Text = "";
screenshotPictureBox.Image = GetNoScreenshotImage();
tableLayoutPanelSimpleSelection.RowStyles[5].Height = 0;
tableLayoutPanelSimpleSelection.RowStyles[6].Height = 0;
}
private void ShowDetailsPanel(VM snapshot, bool force)
{
propertiesGroupBox.Enabled = true;
if (propertiesGroupBox.Tag != snapshot || force || !propertiesGroupBox.Enabled)
{
propertiesTableLayoutPanel.SuspendLayout();
tableLayoutPanelSimpleSelection.SuspendLayout();
propertiesTableLayoutPanel.Controls.Remove(tableLayoutPanelMultipleSelection);
List<CustomField> customFields = CustomFieldsManager.CustomFieldValues(snapshot);
if (customFields.Count > 0)
{
tableLayoutPanelSimpleSelection.RowStyles[5].Height = 30;
customFieldTitle1.Text = String.Format("{0}:", customFields[0].Definition.Name.ToString());
customFieldContent1.Text = customFields[0].Value.ToString();
tableLayoutPanelSimpleSelection.RowStyles[6].Height = 0;
if (customFields.Count >= 2)
{
tableLayoutPanelSimpleSelection.RowStyles[6].Height = 30;
customFieldTitle2.Text = String.Format("{0}:",customFields[1].Definition.Name.ToString());
customFieldContent2.Text = customFields[1].Value.ToString();
}
}
else
{
tableLayoutPanelSimpleSelection.RowStyles[5].Height = 0;
tableLayoutPanelSimpleSelection.RowStyles[6].Height = 0;
}
propertiesTableLayoutPanel.Controls.Add(tableLayoutPanelSimpleSelection, 0, 2);
tableLayoutPanelSimpleSelection.ResumeLayout();
propertiesTableLayoutPanel.ResumeLayout();
DateTime time = snapshot.snapshot_time.ToLocalTime() + snapshot.Connection.ServerTimeOffset;
propertiesGroupBox.Text = String.Format(Messages.SNAPSHOT_CREATED_ON,
HelpersGUI.DateTimeToString(time, Messages.DATEFORMAT_DMY_HMS, true));
nameLabel.Text = snapshot.name_label;
sizeLabel.Text = GetStringSnapshotSize(snapshot);
labelMode.Text = snapshot.power_state == vm_power_state.Halted ? Messages.DISKS_ONLY : Messages.DISKS_AND_MEMORY;
var descr = snapshot.Description();
descriptionLabel.Text = string.IsNullOrEmpty(descr) ? Messages.NONE : descr;
toolTipDescriptionLabel.SetToolTip(descriptionLabel,
descriptionLabel.Height == descriptionLabel.MaximumSize.Height ? descriptionLabel.Text : "");
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
backgroundWorker.RunWorkerAsync(snapshot);
tagsLabel.Text = ConcatWithSeparator(Tags.GetTags(snapshot), ", ");
toolTipTagsLabel.SetToolTip(tagsLabel,
tagsLabel.Height == tagsLabel.MaximumSize.Height ? tagsLabel.Text : "");
Folder folder = Folders.GetFolder(snapshot);
if (folder != null)
folderLabel.Text = folder.name_label;
else
folderLabel.Text = Messages.NONE;
toolTipFolderLabel.SetToolTip(folderLabel,
folderLabel.Height == folderLabel.MaximumSize.Height ? folderLabel.Text : "");
propertiesGroupBox.Tag = snapshot;
propertiesButton.Enabled = true;
}
}
private void ShowDetailsPanelMultipleSelection(IList<VM> snapshots)
{
propertiesTableLayoutPanel.Controls.Remove(tableLayoutPanelSimpleSelection);
propertiesTableLayoutPanel.Controls.Add(tableLayoutPanelMultipleSelection, 0, 2);
nameLabel.Text = String.Format(Messages.SNAPSHOTS_SELECTED, snapshots.Count);
long totalSize = 0;
List<string> tags = new List<string>();
DateTime bigger = DateTime.MinValue;
DateTime smaller = DateTime.MaxValue;
foreach (VM snapshot in snapshots)
{
totalSize += GetSnapshotSize(snapshot);
foreach (string tag in Tags.GetTags(snapshot))
{
if (!tags.Contains(tag))
tags.Add(tag);
}
DateTime time = snapshot.snapshot_time.ToLocalTime() + snapshot.Connection.ServerTimeOffset;
if (smaller > time)
smaller = time;
if (bigger < time)
bigger = time;
}
propertiesGroupBox.Text = String.Format("{0} - {1}",
HelpersGUI.DateTimeToString(smaller, Messages.DATEFORMAT_DMY_HMS, true),
HelpersGUI.DateTimeToString(bigger, Messages.DATEFORMAT_DMY_HMS, true));
multipleSelectionTotalSize.Text = Util.DiskSizeString(totalSize);
multipleSelectionTags.Text = ConcatWithSeparator(tags.ToArray(), ", ");
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
backgroundWorker.RunWorkerAsync(snapshots[0]);
propertiesButton.Enabled = false;
propertiesGroupBox.Tag = null;
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((TreeViewButtonsChecked && snapshotTreeView.SelectedIndices.Count >= 1) || (GridViewButtonsChecked && dataGridView.SelectedRows.Count >= 1))
screenshotPictureBox.Image = (Image)e.Result;
else
{
screenshotPictureBox.Image = GetNoScreenshotImage();
}
}
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
try
{
VM snapshot = (VM)e.Argument;
Image image = GetSnapshotImage(snapshot, false);
if (image == null)
{
image = GetNoScreenshotImage();
}
e.Result = image;
}
catch (Exception)
{
log.Debug("Error creating the screenshot for simple selection");
}
}
private Image GetNoScreenshotImage()
{
Image image;
image = new Bitmap(100, 75);
using (Graphics g = Graphics.FromImage(image))
{
g.FillRectangle(Brushes.Black, new Rectangle(0, 0, 100, 75));
g.DrawString(Messages.NO_SCREENSHOT, Font, Brushes.White, 10, 30);
}
return image;
}
private static string ConcatWithSeparator(string[] strings, string separator)
{
StringBuilder sb = new StringBuilder();
foreach (string str in strings)
{
sb.Append(str);
sb.Append(separator);
}
if (strings.Length > 0)
sb.Remove(sb.Length - separator.Length, separator.Length);
else
sb.Append(Messages.NONE);
return sb.ToString();
}
#region ScreenShot methods
private Image GetSnapshotImage(VM snapshot, bool style)
{
Image image = GetBlobImage(snapshot);
if (image == null)
image = GetOtherConfigImage(snapshot);
if (style)
return ChangeStyle(image);
else
return image;
}
private Image ChangeStyle(Image image)
{
int SHADOW_OFFSET = 3;
try
{
Image finalImage = new Bitmap(image.Width + SHADOW_OFFSET,
image.Height + SHADOW_OFFSET);
Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height);
using (Graphics g = Graphics.FromImage(finalImage))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.CompositingQuality = CompositingQuality.HighQuality;
//// Draw drop shadow
Rectangle shadow = new Rectangle(rectangle.Location, rectangle.Size);
shadow.Offset(SHADOW_OFFSET, SHADOW_OFFSET);
using (GraphicsPath path = GetRoundedPath(shadow, 4f))
using (PathGradientBrush brush = new PathGradientBrush(path))
{
brush.FocusScales = new PointF(0.8f, 0.8f);
brush.SurroundColors = new Color[] { Color.FromArgb(0, Color.Black) };
brush.CenterColor = Color.Black;
g.FillPath(brush, path);
}
// Draw image with rounded corners
g.SetClip(GetRoundedPath(rectangle, 4f));
g.DrawImageUnscaled(image, 0, 0, image.Width, image.Height);
//// Darken image
using (Brush brush = new LinearGradientBrush(rectangle,
Color.FromArgb(100, Color.Black),
Color.FromArgb(140, Color.Black),
LinearGradientMode.Vertical))
g.FillRectangle(brush, rectangle);
// Draw shimmer
using (GraphicsPath path = GetShimmer(rectangle))
using (Brush brush = new LinearGradientBrush(rectangle,
Color.FromArgb(100, Color.White),
Color.FromArgb(0, Color.White),
LinearGradientMode.Vertical))
g.FillPath(brush, path);
return finalImage;
}
}
finally
{
image.Dispose();
}
}
private static GraphicsPath GetShimmer(Rectangle bounds)
{
GraphicsPath path = new GraphicsPath();
int sweepHeight = bounds.Height / 3;
int rightHeight = bounds.X + sweepHeight;
int leftHeight = bounds.X + sweepHeight * 2;
int border = 3;
path.StartFigure();
path.AddArc(bounds.Left + border, bounds.Top + border,
2 * border, 2 * border, 180, 90);
path.AddLine(bounds.Left + 2 * border, bounds.Top + border,
bounds.Right - 2 * border, bounds.Top + border);
path.AddArc(bounds.Right - (3 * border) - 1, bounds.Top + border,
2 * border, 2 * border, 270, 90);
path.AddLine(bounds.Right - border - 1, rightHeight,
bounds.Left + border, leftHeight);
path.CloseFigure();
return path;
}
private static Image GetOtherConfigImage(VM snapshot)
{
try
{
string imageStr;
if (!snapshot.other_config.TryGetValue(VMSnapshotCreateAction.VNC_SNAPSHOT, out imageStr))
return null;
byte[] imageBuffer = Convert.FromBase64String(imageStr);
using (MemoryStream imageStream = new MemoryStream(imageBuffer))
return Image.FromStream(imageStream);
}
catch
{
return null;
}
}
private static GraphicsPath GetRoundedPath(RectangleF rect, float radius)
{
float diameter = 2 * radius;
GraphicsPath path = new GraphicsPath();
path.StartFigure();
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
path.AddArc(rect.Right - diameter, rect.Bottom - diameter - 1, diameter, diameter, 0, 90);
path.AddArc(rect.X, rect.Bottom - diameter - 1, diameter, diameter, 90, 90);
path.CloseFigure();
return path;
}
private Image GetBlobImage(VM snapshot)
{
try
{
XenRef<Blob> blobRef;
if (!snapshot.blobs.TryGetValue(VMSnapshotCreateAction.VNC_SNAPSHOT, out blobRef))
return null;
Blob blob = VM.Connection.Resolve(blobRef);
if (blob == null)
return null;
using (Stream imageStream = blob.Load())
return Image.FromStream(imageStream);
}
catch
{
return null;
}
}
#endregion
private void treeToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!TreeViewButtonsChecked)
{
TreeViewChecked();
BuildList();
}
}
private bool GridViewButtonsChecked
{
get
{
return toolStripButtonListView.Checked;
}
set
{
toolStripButtonListView.Checked = value;
}
}
private bool TreeViewButtonsChecked
{
get
{
return toolStripButtonTreeView.Checked;
}
set
{
toolStripButtonTreeView.Checked = value;
}
}
private void TreeViewChecked()
{
viewPanel.Controls.Clear();
viewPanel.Controls.Add(snapshotTreeView);
snapshotTreeView.Dock = DockStyle.Fill;
TreeViewButtonsChecked = true;
_storedViewsPerVm[VM.opaque_ref] = SnapshotsView.TreeView;
GridViewButtonsChecked = false;
snapshotTreeView.SelectedItems.Clear();
foreach (DataGridViewRow row in dataGridView.SelectedRows)
{
foreach (ListViewItem item in snapshotTreeView.Items)
{
if (row.Tag == item.Tag)
{
item.Selected = true;
break;
}
}
}
RefreshToolStripButtons();
}
private void GridViewChecked()
{
viewPanel.Controls.Clear();
viewPanel.Controls.Add(dataGridView);
dataGridView.Dock = DockStyle.Fill;
GridViewButtonsChecked = true;
_storedViewsPerVm[VM.opaque_ref] = SnapshotsView.ListView;
TreeViewButtonsChecked = false;
RefreshToolStripButtons();
}
private void takeSnapshotToolStripButton_Click(object sender, EventArgs e)
{
TakeSnapshotCommand command = new TakeSnapshotCommand(Program.MainWindow, VM);
command.Execute();
}
private void deleteToolStripButton_Click(object sender, EventArgs e)
{
List<VM> snapshots = GetSelectedSnapshots();
if (snapshots != null)
DeleteSnapshots(snapshots);
}
private VM GetSelectedSnapshot()
{
if (TreeViewButtonsChecked)
{
if (snapshotTreeView.SelectedItems.Count == 1)
{
return (VM)snapshotTreeView.SelectedItems[0].Tag;
}
}
else if (GridViewButtonsChecked)
{
if (dataGridView.SelectedRows.Count == 1)
{
return (VM)dataGridView.SelectedRows[0].Tag;
}
}
return null;
}
private List<VM> GetSelectedSnapshots()
{
if (TreeViewButtonsChecked)
{
if (snapshotTreeView.SelectedItems.Count > 0)
{
List<VM> snapshots = new List<VM>();
foreach (ListViewItem item in snapshotTreeView.SelectedItems)
{
VM snap = (VM)item.Tag;
if (snap != null && snap.is_a_snapshot)
{
if(!(snap.is_snapshot_from_vmpp || snap.is_vmss_snapshot) || toolStripMenuItemScheduledSnapshots.Checked)
snapshots.Add(snap);
}
}
return snapshots;
}
}
else if (GridViewButtonsChecked)
{
if (dataGridView.SelectedRows.Count > 0)
{
List<VM> snapshots = new List<VM>();
foreach (DataGridViewRow row in dataGridView.SelectedRows)
{
VM snap = (VM)row.Tag;
if (snap != null && snap.is_a_snapshot)
{
if (!(snap.is_snapshot_from_vmpp || snap.is_vmss_snapshot) || toolStripMenuItemScheduledSnapshots.Checked)
snapshots.Add(snap);
}
}
return snapshots;
}
}
return null;
}
private void restoreToolStripButton_Click(object sender, EventArgs e)
{
VM snapshot = GetSelectedSnapshot();
if (snapshot != null)
RevertVM(VM, snapshot);
}
private void propertiesButton_Click(object sender, EventArgs e)
{
VM snapshot = (VM)propertiesGroupBox.Tag;
if (snapshot != null)
{
PropertiesDialog dialog = new PropertiesDialog(snapshot);
dialog.ShowDialog();
}
}
private void SetContextMenuMultiSelection()
{
contextMenuStrip.Items.Clear();
contextMenuStrip.Items.AddRange(new ToolStripItem[]
{
viewToolStripMenuItem,
sortToolStripSeparator,
deleteToolStripMenuItem
});
}
private void SetContextMenuSnapshot()
{
contextMenuStrip.Items.Clear();
contextMenuStrip.Items.AddRange(new ToolStripItem[]
{
revertToolStripMenuItem,
saveVMToolStripSeparator
});
contextMenuStrip.Items.AddRange(new ToolStripItem[]
{
saveVMToolStripMenuItem,
saveTemplateToolStripMenuItem,
exportToolStripMenuItem
});
contextMenuStrip.Items.AddRange(new ToolStripItem[]
{
separatorDeleteToolStripSeparator,
viewToolStripMenuItem
});
if (toolStripButtonListView.Checked)
contextMenuStrip.Items.Add(sortByToolStripMenuItem);
contextMenuStrip.Items.AddRange(new ToolStripItem[]
{
sortToolStripSeparator,
deleteToolStripMenuItem,
propertiesToolStripMenuItem
});
}
private void SetContextMenuNoneSelected()
{
contextMenuStrip.Items.Clear();
contextMenuStrip.Items.Add(TakeSnapshotToolStripMenuItem);
if (VM.snapshots.Count > 0)
contextMenuStrip.Items.Add(viewToolStripMenuItem);
}
private void saveAsATemplateToolStripMenuItem_Click(object sender, EventArgs e)
{
new NewTemplateFromSnapshotCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void saveAsAVirtualMachineToolStripMenuItem_Click(object sender, EventArgs e)
{
new NewVMFromSnapshotCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void exportSnapshotToolStripMenuItem_Click(object sender, EventArgs e)
{
new ExportSnapshotAsTemplateCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void snapshotTreeView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
ListViewHitTestInfo test = snapshotTreeView.HitTest(e.Location);
SnapshotIcon snapIcon = test.Item as SnapshotIcon;
if (snapIcon != null && snapIcon.Selectable)
revertButton_Click(sender, e);
}
private void sortByToolStripMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = (ToolStripMenuItem)sender;
switch (item.Name)
{
case "sortByTypeToolStripMenuItem":
dataGridView.Sort(dataGridView.Columns[0], ListSortDirection.Ascending);
dataGridView.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
break;
case "sortByNameToolStripMenuItem":
dataGridView.Sort(dataGridView.Columns[1], ListSortDirection.Ascending);
break;
case "sortByCreatedOnToolStripMenuItem":
dataGridView.Sort(dataGridView.Columns[2], ListSortDirection.Ascending);
break;
//case "sortBySizeToolStripMenuItem":
// DataGridView.Sort(DataGridView.Columns[3], ListSortDirection.Ascending);
// break;
}
if (item.Name != "sortByTypeToolStripMenuItem")
dataGridView.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.None;
}
private void screenshotPictureBox_Click(object sender, EventArgs e)
{
VM snapshot = (VM)propertiesGroupBox.Tag;
if (snapshot != null && screenshotPictureBox.Image.Size.Width > 100)
new ScreenShotDialog(snapshot.name_label, screenshotPictureBox.Image).ShowDialog();
}
private void chevronButton1_ButtonClick(object sender, EventArgs e)
{
if (contentTableLayoutPanel.ColumnStyles[1].Width == 0)
{
contentTableLayoutPanel.ColumnStyles[1].Width = defaultWidthProperties;
chevronButton1.Text = Messages.HIDE_DETAILS;
chevronButton1.Image = Resources.PDChevronRight;
}
else
{
defaultWidthProperties = contentTableLayoutPanel.ColumnStyles[1].Width;
contentTableLayoutPanel.ColumnStyles[1].Width = 0;
chevronButton1.Text = Messages.SHOW_DETAILS;
chevronButton1.Image = Resources.PDChevronLeft;
}
snapshotTreeView.Invalidate();
}
private void revertButton_Click(object sender, EventArgs e)
{
VM snapshot = GetSelectedSnapshot();
if (snapshot != null)
RevertVM(VM, snapshot);
}
private void deleteButton_Click(object sender, EventArgs e)
{
List<VM> snapshots = GetSelectedSnapshots();
if (snapshots != null)
DeleteSnapshots(snapshots);
}
private void saveButton_Click(object sender, EventArgs e)
{
saveMenuStrip.Show(saveButton, 0, saveButton.Height);
}
private void saveAsTemplateToolStripMenuItem_Click(object sender, EventArgs e)
{
new NewTemplateFromSnapshotCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
new NewVMFromSnapshotCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void exportAsBackupToolStripMenuItem_Click(object sender, EventArgs e)
{
new ExportSnapshotAsTemplateCommand(Program.MainWindow, GetSelectedSnapshot()).Execute();
}
private void gridToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!GridViewButtonsChecked)
{
GridViewChecked();
}
}
private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
{
if (GridViewButtonsChecked)
{
if (dataGridView.SelectedRows.Count > 1)
{
SetContextMenuMultiSelection();
}
else if (dataGridView.SelectedRows.Count == 1)
SetContextMenuSnapshot();
else
SetContextMenuNoneSelected();
}
else if (TreeViewButtonsChecked)
{
if (snapshotTreeView.SelectedItems.Count > 1)
{
SetContextMenuMultiSelection();
}
else if (snapshotTreeView.SelectedItems.Count < 1)
{
SetContextMenuNoneSelected();
}
else if (snapshotTreeView.SelectedItems.Count == 1)
{
VM snapshot = (VM)snapshotTreeView.SelectedItems[0].Tag;
if (snapshot != null && snapshot.is_a_snapshot)
{
SetContextMenuSnapshot();
}
}
}
}
private void chevronButton1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Space)
chevronButton1_ButtonClick(sender, e);
}
private static void DeleteSnapshots(List<VM> snapshots)
{
DeleteSnapshotCommand deleteSnapshotCommand = new DeleteSnapshotCommand(
Program.MainWindow, snapshots.ConvertAll<SelectedItem>(input => new SelectedItem(input)));
deleteSnapshotCommand.Execute();
}
private void RevertVM(VM vm, VM snapshot)
{
if (vm.current_operations.Count == 0)
{
RevertToSnapshotCommand cmd = new RevertToSnapshotCommand(Program.MainWindow, vm, snapshot);
cmd.Execute();
}
}
private void dataGridView_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
DataGridView.HitTestInfo hitTestInfo = dataGridView.HitTest(e.X, e.Y);
if (hitTestInfo.RowIndex >= 0)
{
if (dataGridView.SelectedRows.Count == 1)
dataGridView.ClearSelection();
dataGridView.Rows[hitTestInfo.RowIndex].Selected = true;
}
else
{
dataGridView.ClearSelection();
}
contextMenuStrip.Show(dataGridView, e.X, e.Y);
}
}
private void snapshotTreeView_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ListViewHitTestInfo hitTestInfo = snapshotTreeView.HitTest(e.X, e.Y);
if (hitTestInfo.Item != null)
{
SnapshotIcon snapshotIcon = hitTestInfo.Item as SnapshotIcon;
if (snapshotIcon != null && snapshotIcon.Selectable)
{
if (snapshotTreeView.SelectedItems.Count == 1)
snapshotTreeView.SelectedItems.Clear();
hitTestInfo.Item.Selected = true;
}
else
{
snapshotTreeView.SelectedItems.Clear();
}
}
else
{
snapshotTreeView.SelectedItems.Clear();
}
contextMenuStrip.Show(snapshotTreeView, e.X, e.Y);
}
}
private void snapshotTreeView_ItemDrag(object sender, ItemDragEventArgs e)
{
SnapshotIcon icon = e.Item as SnapshotIcon;
if (icon != null && icon.ImageIndex == SnapshotIcon.VMImageIndex)
{
snapshotTreeView.DoDragDrop(e.Item, DragDropEffects.Move);
}
}
private void snapshotTreeView_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
Point hitPoint = snapshotTreeView.PointToClient(new Point(e.X, e.Y));
ListViewHitTestInfo info = snapshotTreeView.HitTest(hitPoint);
SnapshotIcon icon = info.Item as SnapshotIcon;
if (icon != null && (icon.ImageIndex == SnapshotIcon.DiskAndMemorySnapshot || icon.ImageIndex == SnapshotIcon.DiskSnapshot))
{
icon.Selected = true;
if (snapshotTreeView.SelectedItems.Count > 1)
snapshotTreeView.SelectedItems.Clear();
}
}
private void snapshotTreeView_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void snapshotTreeView_DragDrop(object sender, DragEventArgs e)
{
Point hitPoint = snapshotTreeView.PointToClient(new Point(e.X, e.Y));
ListViewHitTestInfo info = snapshotTreeView.HitTest(hitPoint);
SnapshotIcon icon = info.Item as SnapshotIcon;
if (icon != null && (icon.ImageIndex == SnapshotIcon.DiskAndMemorySnapshot || icon.ImageIndex == SnapshotIcon.DiskSnapshot))
{
VM snapshot = icon.Tag as VM;
if (snapshot != null)
RevertVM(VM, snapshot);
}
}
private void snapshotTreeView_MouseMove(object sender, MouseEventArgs e)
{
SnapshotIcon icon = snapshotTreeView.HitTest(e.X, e.Y).Item as SnapshotIcon;
if (icon != null && icon.ImageIndex == SnapshotIcon.VMImageIndex)
{
this.Cursor = Cursors.Hand;
}
else
{
this.Cursor = Cursors.Default;
}
}
private void button1_Click(object sender, EventArgs e)
{
contextMenuStripView.Show(buttonView, 0, buttonView.Height);
}
private void toolStripMenuItemScheduledSnapshots_Click(object sender, EventArgs e)
{
toolStripMenuItemScheduledSnapshots.Checked = !toolStripMenuItemScheduledSnapshots.Checked;
BuildList();
}
private void linkLabelVMPPInfo_Click(object sender, LinkLabelLinkClickedEventArgs e)
{
if (Helpers.FeatureForbidden(VM.Connection, Host.RestrictVMSnapshotSchedule))
{
VMGroupCommand<VMSS>.ShowUpsellDialog(this);
}
else
{
var command = new VMGroupCommand<VMSS>(Program.MainWindow, VM);
command.Execute();
}
}
private void snapshotTreeView_Leave(object sender, EventArgs e)
{
snapshotTreeView.Invalidate();
}
private void snapshotTreeView_Enter(object sender, EventArgs e)
{
snapshotTreeView.Invalidate();
}
}
}