xenadmin/XenAdmin/Dialogs/NewTagDialog.cs

464 lines
16 KiB
C#
Raw Normal View History

/* 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.Windows.Forms;
using XenAdmin.Model;
using XenAPI;
using System.Drawing;
using XenAdmin.Core;
using XenAdmin.Actions;
using System.Windows.Forms.VisualStyles;
namespace XenAdmin.Dialogs
{
public partial class NewTagDialog : XenDialogBase
{
public NewTagDialog(List<string> tags)
: this(tags, new List<string>())
{
}
public NewTagDialog(List<string> tags, List<string> indeterminateTags)
{
InitDialog();
LoadTags(tags, indeterminateTags);
}
public List<string> GetSelectedTags()
{
return GetTags(CheckState.Checked);
}
public List<string> GetIndeterminateTags()
{
return GetTags(CheckState.Indeterminate);
}
private List<string> GetTags(CheckState checkState)
{
Program.AssertOnEventThread();
List<string> items = new List<string>();
foreach (TagsListViewItem item in tagsListView.Items)
{
if (item.Checked == checkState)
{
items.Add(item.Text);
}
}
return items;
}
private void InitDialog()
{
InitializeComponent();
// CheckBoxes is false as we draw them ourselves for tri-state.
tagsListView.CheckBoxes = false;
tagsListView.HideSelection = false;
tagsListView.MultiSelect = true;
tagsListView.LabelEdit = true;
tagsListView.AfterLabelEdit += tagsListView_AfterLabelEdit;
tagsListView.Activation = ItemActivation.TwoClick;
textBox1.KeyPress += textBox1_KeyPress;
// populate state image list for tri-state checkboxes
using (Graphics listViewGraphics = Graphics.FromHwnd(tagsListView.Handle))
{
stateImageList.ImageSize = CheckBoxRenderer.GetGlyphSize(listViewGraphics, CheckBoxState.CheckedNormal);
}
foreach (CheckBoxState state in new CheckBoxState[] { CheckBoxState.UncheckedNormal, CheckBoxState.CheckedNormal, CheckBoxState.MixedNormal })
{
Bitmap bitmap = new Bitmap(stateImageList.ImageSize.Width, stateImageList.ImageSize.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.Clear(Color.Transparent);
CheckBoxRenderer.DrawCheckBox(g, new Point(0, 0), state);
}
stateImageList.Images.Add(bitmap);
}
}
private void tagsListView_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
okButton.Enabled = true;
TagsListViewItem itemRenaming = (TagsListViewItem)tagsListView.Items[e.Item];
if (itemRenaming != null)
{
string oldName = itemRenaming.Text;
string newName = (e.Label == null ? oldName : e.Label.Trim()); // null indicates no change
if (newName == "")
{
e.CancelEdit = true;
return;
}
foreach (TagsListViewItem currentItem in tagsListView.Items)
{
if (currentItem != itemRenaming && currentItem.Text == newName)
{
e.CancelEdit = true;
return;
}
}
// Rename the tag in the list view ourselves (necessary if we've trimmed whitespace from the ends of the name)
itemRenaming.Text = newName;
e.CancelEdit = true;
// Rename the tag on all the servers
DelegatedAsyncAction action = new DelegatedAsyncAction(null,
String.Format(Messages.RENAME_TAG, oldName),
String.Format(Messages.RENAMING_TAG, oldName),
String.Format(Messages.RENAMED_TAG, oldName),
delegate(Session session)
{
Tags.RenameTagGlobally(oldName, newName);
});
action.RunAsync();
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter && addButton.Enabled)
{
e.Handled = true;
AddTag();
}
}
private void SortList()
{
List<TagsListViewItem> listChecked = new List<TagsListViewItem>();
List<TagsListViewItem> listIndeterminate = new List<TagsListViewItem>();
List<TagsListViewItem> listNonChecked = new List<TagsListViewItem>();
foreach (TagsListViewItem item in tagsListView.Items)
{
if (item.Checked == CheckState.Checked)
{
listChecked.Add(item);
}
else if (item.Checked == CheckState.Unchecked)
{
listNonChecked.Add(item);
}
else
{
listIndeterminate.Add(item);
}
}
listNonChecked.Sort(Comparison());
listChecked.Sort(Comparison());
listIndeterminate.Sort(Comparison());
tagsListView.Items.Clear();
foreach (TagsListViewItem item in listChecked)
{
tagsListView.Items.Add(item);
}
foreach (TagsListViewItem item in listIndeterminate)
{
tagsListView.Items.Add(item);
}
foreach (TagsListViewItem item in listNonChecked)
{
tagsListView.Items.Add(item);
}
}
private Comparison<TagsListViewItem> Comparison()
{
return delegate(TagsListViewItem x, TagsListViewItem y)
{
return x.Text.CompareTo(y.Text);
};
}
private bool TagPresent(string tag)
{
// Used to use tagsListView.Items.ContainsKey(tag), but that uses the Name
// instead of the Text, and is also not case sensitive, which caused a bug.
foreach (TagsListViewItem item in tagsListView.Items)
{
if (item.Text == tag)
return true;
}
return false;
}
private void AddTag()
{
string text = this.textBox1.Text.Trim();
if (!TagPresent(text))
{
TagsListViewItem item = (TagsListViewItem)tagsListView.Items.Add(new TagsListViewItem(text));
item.Checked = CheckState.Checked;
item.Text = text;
}
else
{
foreach (TagsListViewItem item in tagsListView.Items)
{
if (item.Text == text)
{
item.Checked = CheckState.Checked;
break;
}
}
}
this.textBox1.Text = "";
addButton.Enabled = false;
SortList();
}
private void LoadTags(List<string> tags, List<string> indeterminateTags)
{
Program.AssertOnEventThread();
tagsListView.Items.Clear();
foreach (string tag in Tags.GetAllTags())
{
TagsListViewItem item = (TagsListViewItem)tagsListView.Items.Add(new TagsListViewItem(tag));
if (tags.Contains(tag))
{
item.Checked = CheckState.Checked;
}
else if (indeterminateTags.Contains(tag))
{
item.Checked = CheckState.Indeterminate;
}
item.Text = tag;
}
foreach (string tag in tags) // We need to include these too, because they may have been recently added and not yet got into GetAllTags()
{
if (!TagPresent(tag))
{
TagsListViewItem item = (TagsListViewItem)tagsListView.Items.Add(new TagsListViewItem(tag));
item.Checked = CheckState.Checked;
item.Text = tag;
}
}
SortList();
}
private void NewTagDialog_Activated(object sender, EventArgs e)
{
textBox1.Focus();
}
private void CancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
this.Close();
}
private void saveButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
this.Close();
}
private void addButton_Click(object sender, EventArgs e)
{
AddTag();
}
private void renameButton_Click(object sender, EventArgs e)
{
if (tagsListView.SelectedItems.Count == 1)
{
tagsListView.SelectedItems[0].BeginEdit();
}
}
private void deleteButton_Click(object sender, EventArgs e)
{
if (tagsListView.SelectedItems.Count == 1)
{
string tag = tagsListView.SelectedItems[0].Text;
DialogResult result;
using (var tbd = new ThreeButtonDialog(
new ThreeButtonDialog.Details(SystemIcons.Warning, String.Format(Messages.CONFIRM_DELETE_TAG, tag), Messages.CONFIRM_DELETE_TAG_TITLE),
new ThreeButtonDialog.TBDButton(Messages.OK, DialogResult.OK),
ThreeButtonDialog.ButtonCancel))
{
result = tbd.ShowDialog(this);
}
if (result != DialogResult.OK)
return;
// Remove the tag from the tagsListView
tagsListView.Items.Remove(tagsListView.SelectedItems[0]);
setButtonEnablement();
// Delete the tag from all resources on all servers
DelegatedAsyncAction action = new DelegatedAsyncAction(null,
String.Format(Messages.DELETE_ALL_TAG, tag),
String.Format(Messages.DELETING_ALL_TAG, tag),
String.Format(Messages.DELETED_ALL_TAG, tag),
delegate(Session session)
{
Tags.RemoveTagGlobally(tag);
});
action.RunAsync();
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
addButton.Enabled = (this.textBox1.Text.Trim() != string.Empty);
}
private void tagsListView_SelectedIndexChanged(object sender, EventArgs e)
{
setButtonEnablement();
}
private void setButtonEnablement()
{
renameButton.Enabled = tagsListView.SelectedItems.Count == 1;
deleteButton.Enabled = tagsListView.SelectedItems.Count == 1;
}
private void tagsListView_MouseClick(object sender, MouseEventArgs e)
{
TagsListViewItem item = (TagsListViewItem)tagsListView.GetItemAt(e.X, e.Y);
if (item != null)
{
Rectangle iconRect = tagsListView.GetItemRect(item.Index, ItemBoundsPortion.Icon);
Rectangle checkRect = new Rectangle(0, iconRect.Top, iconRect.Left, iconRect.Height);
// if there's a selection and the clicked item is in the selection, then toggle the
// entire selection
if (checkRect.Contains(e.Location))
{
if (tagsListView.SelectedItems.Count > 0 && tagsListView.SelectedItems.Contains(item))
{
ToggleItems(tagsListView.SelectedItems);
}
else
{
item.Toggle();
}
}
}
}
private void tagsListView_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Enter)
{
ToggleItems(tagsListView.SelectedItems);
}
}
private void ToggleItems(System.Collections.IList items)
{
if(items.Count < 1)
return;
CheckState firstCheckState = ((TagsListViewItem)items[0]).Checked;
foreach (TagsListViewItem item in items)
{
item.Toggle(firstCheckState);
}
}
private class TagsListViewItem : ListViewItem
{
public TagsListViewItem(string text)
: base(text)
{
Checked = CheckState.Unchecked;
}
public void Toggle()
{
Toggle(Checked);
}
public void Toggle(CheckState stateToToggleFrom)
{
StateImageIndex = Convert.ToInt32(!Convert.ToBoolean(stateToToggleFrom));
}
public new CheckState Checked
{
get
{
if (StateImageIndex == 0)
{
return CheckState.Unchecked;
}
else if (StateImageIndex == 1)
{
return CheckState.Checked;
}
else
{
return CheckState.Indeterminate;
}
}
set
{
if (value == CheckState.Unchecked)
{
StateImageIndex = 0;
}
else if (value == CheckState.Checked)
{
StateImageIndex = 1;
}
else
{
StateImageIndex = 2;
}
}
}
}
}
}