xenadmin/XenAdmin/Controls/XenSearch/QueryElement.cs
Konstantina Chremmou 8f51089efe CP-5752: Use Action delegate instead of EventHandler when there is no need to
pass in parameters when the event is fired. Moved QueryElement.Dispose method
from the Designer.cs to the main file (it needs visibility since it contains more
code than the autogenerated method).

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
2013-08-03 01:04:40 +01:00

2531 lines
101 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.Windows.Forms;
using XenAdmin.CustomFields;
using XenAdmin.XenSearch;
using XenAPI;
using XenAdmin.Core;
using XenAdmin.Network;
using XenAdmin.Model;
namespace XenAdmin.Controls.XenSearch
{
public partial class QueryElement : UserControl
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly List<QueryType> queryTypes = new List<QueryType>();
private static readonly List<CustomFieldQueryTypeBase> customFields = new List<CustomFieldQueryTypeBase>();
private static readonly QueryType DefaultQueryType;
static QueryElement()
{
DefaultQueryType = new DummyQueryType(0, ObjectTypes.None);
queryTypes.Add(DefaultQueryType);
queryTypes.Add(new GroupQueryType(0, ObjectTypes.AllIncFolders, GroupQuery.GroupQueryType.And));
queryTypes.Add(new GroupQueryType(0, ObjectTypes.AllIncFolders, GroupQuery.GroupQueryType.Or));
queryTypes.Add(new GroupQueryType(0, ObjectTypes.AllIncFolders, GroupQuery.GroupQueryType.Nor));
queryTypes.Add(new EnumPropertyQueryType<ObjectTypes>(1, ObjectTypes.None, PropertyNames.type));
queryTypes.Add(new UuidQueryType(1, ObjectTypes.AllIncFolders & ~ObjectTypes.VDI | ObjectTypes.Appliance)); // but only actually shown for parent/child queries (see WantQueryType()). Too slow for VDIs and not very useful.
queryTypes.Add(new StringPropertyQueryType(1, ObjectTypes.AllIncFolders | ObjectTypes.Appliance, PropertyNames.label));
queryTypes.Add(new StringPropertyQueryType(1, ObjectTypes.AllExcFolders | ObjectTypes.Appliance, PropertyNames.description));
queryTypes.Add(new TagQueryType(1, ObjectTypes.AllExcFolders));
// Replaced by new ParentChildQueryTypes below
queryTypes.Add(new XenModelObjectPropertyQueryType<Pool>(2, ObjectTypes.None, PropertyNames.pool));
queryTypes.Add(new HostQueryType(2, ObjectTypes.None));
queryTypes.Add(new LongQueryType(3, ObjectTypes.VM, Messages.MEMORY, PropertyNames.memory, Util.BINARY_MEGA, Messages.VAL_MEGB));
queryTypes.Add(new IPAddressQueryType(3, ObjectTypes.VM | ObjectTypes.Server | ObjectTypes.LocalSR | ObjectTypes.RemoteSR, PropertyNames.ip_address));
queryTypes.Add(new DatePropertyQueryType(3, ObjectTypes.VM, PropertyNames.start_time));
queryTypes.Add(new EnumPropertyQueryType<vm_power_state>(3, ObjectTypes.VM, PropertyNames.power_state));
queryTypes.Add(new EnumPropertyQueryType<VM.VirtualisationStatus>(3, ObjectTypes.VM, PropertyNames.virtualisation_status));
queryTypes.Add(new ValuePropertyQueryType(3, ObjectTypes.VM, PropertyNames.os_name));
queryTypes.Add(new EnumPropertyQueryType<VM.HA_Restart_Priority>(3, ObjectTypes.VM, PropertyNames.ha_restart_priority));
queryTypes.Add(new EnumPropertyQueryType<SR.SRTypes>(3, /*ObjectTypes.LocalSR | ObjectTypes.RemoteSR*/ ObjectTypes.None, PropertyNames.sr_type));
queryTypes.Add(new LongQueryType(4, ObjectTypes.VDI, Messages.SIZE, PropertyNames.size, Util.BINARY_GIGA, Messages.VAL_GIGB));
queryTypes.Add(new BooleanQueryType(4, ObjectTypes.LocalSR | ObjectTypes.RemoteSR | ObjectTypes.VDI, PropertyNames.shared));
queryTypes.Add(new BooleanQueryType(4, ObjectTypes.Pool, PropertyNames.ha_enabled));
queryTypes.Add(new NullQueryType<Pool>(4, ObjectTypes.Server | ObjectTypes.VM, PropertyNames.pool, false, Messages.IS_IN_A_POOL));
queryTypes.Add(new NullQueryType<Pool>(4, ObjectTypes.Server | ObjectTypes.VM, PropertyNames.pool, true, Messages.IS_STANDALONE));
// Replaced by new ParentChildQueryTypes below
queryTypes.Add(new XenModelObjectListContainsQueryType<XenAPI.Network>(5, ObjectTypes.None, PropertyNames.networks));
queryTypes.Add(new DiskQueryType(5, ObjectTypes.None, Messages.DISKS));
// Any new recursive ones should be added to GetSearchForResourceSelectButton() too
queryTypes.Add(new RecursiveXMOQueryType<Pool>(6, ObjectTypes.AllExcFolders, PropertyNames.pool, ObjectTypes.Pool));
queryTypes.Add(new RecursiveXMOListQueryType<Host>(6, ObjectTypes.AllExcFolders & ~ObjectTypes.Pool, PropertyNames.host, ObjectTypes.Server)); // i.e. everything except Pool
queryTypes.Add(new RecursiveXMOListQueryType<VM>(6, ObjectTypes.AllExcFolders, PropertyNames.vm, ObjectTypes.VM));
queryTypes.Add(new RecursiveXMOListQueryType<XenAPI.Network>(6, ObjectTypes.Network | ObjectTypes.VM, PropertyNames.networks, ObjectTypes.Network));
queryTypes.Add(new RecursiveXMOListQueryType<SR>(6, ObjectTypes.LocalSR | ObjectTypes.RemoteSR | ObjectTypes.VM | ObjectTypes.VDI,
PropertyNames.storage, ObjectTypes.LocalSR | ObjectTypes.RemoteSR));
queryTypes.Add(new RecursiveXMOListQueryType<VDI>(6, ObjectTypes.VM | ObjectTypes.VDI, PropertyNames.disks, ObjectTypes.VDI));
queryTypes.Add(new RecursiveXMOQueryType<VM_appliance>(7, ObjectTypes.VM, PropertyNames.appliance, ObjectTypes.Appliance));
queryTypes.Add(new BooleanQueryType(7, ObjectTypes.VM, PropertyNames.in_any_appliance));
queryTypes.Add(new RecursiveXMOQueryType<Folder>(8, ObjectTypes.AllIncFolders, PropertyNames.folder, ObjectTypes.Folder));
queryTypes.Add(new RecursiveXMOListQueryType<Folder>(8, ObjectTypes.AllIncFolders, PropertyNames.folders, ObjectTypes.Folder));
queryTypes.Add(new NullQueryType<Folder>(8, ObjectTypes.AllExcFolders, PropertyNames.folder, true, Messages.NOT_IN_A_FOLDER));
queryTypes.Add(new BooleanQueryType(9, ObjectTypes.AllExcFolders, PropertyNames.has_custom_fields));
OtherConfigAndTagsWatcher.OtherConfigChanged += OtherConfigWatcher_OtherConfigChanged;
CustomFieldsManager.CustomFieldsChanged += OtherConfigWatcher_OtherConfigChanged;
}
private static void OtherConfigWatcher_OtherConfigChanged(object sender, EventArgs e)
{
List<CustomFieldDefinition> customFieldDefinitions = CustomFieldsManager.GetCustomFields();
// Add new custom fields
foreach (CustomFieldDefinition definition in customFieldDefinitions)
{
if (!CustomFieldExists(definition))
{
if (definition.Type == CustomFieldDefinition.Types.String)
customFields.Add(new CustomFieldStringQueryType(8, ObjectTypes.AllExcFolders, definition));
else
customFields.Add(new CustomFieldDateQueryType(8, ObjectTypes.AllExcFolders, definition));
}
}
// Remove old ones
List<CustomFieldQueryTypeBase> toRemove = new List<CustomFieldQueryTypeBase>();
foreach (CustomFieldQueryTypeBase customFieldQueryType in customFields)
{
if (!CustomFieldDefinitionExists(customFieldDefinitions, customFieldQueryType))
toRemove.Add(customFieldQueryType);
}
foreach (CustomFieldQueryTypeBase t in toRemove)
{
customFields.Remove(t);
}
}
private static bool CustomFieldExists(CustomFieldDefinition definition)
{
return customFields.Exists(delegate(CustomFieldQueryTypeBase c) { return c.definition.Equals(definition); });
}
private static bool CustomFieldDefinitionExists(List<CustomFieldDefinition> l, CustomFieldQueryTypeBase queryType)
{
return l.Exists(delegate(CustomFieldDefinition d) { return d.Equals(queryType.definition); });
}
private readonly List<QueryElement> subQueryElements;
private QueryElement parentQueryElement;
private Searcher searcher;
private QueryScope queryScope; // Normally null, meaning use the scope from searcher (see WantQueryType). Set for the subquery of a parent-child query.
private QueryFilter lastQueryFilter;
public event EventHandler QueryChanged;
protected virtual void OnQueryChanged()
{
try
{
if (QueryChanged != null)
QueryChanged(this, new EventArgs());
}
catch (Exception e)
{
log.Debug("Exception firing OnQueryChanged in QueryElement", e);
log.Debug(e, e);
}
}
public QueryElement()
: this(null)
{
}
public QueryElement(Searcher searcher, QueryScope queryScope, QueryElement parentQueryElement, QueryFilter query)
: this(searcher, queryScope, parentQueryElement)
{
SelectQueryTypeFor(query);
}
public QueryElement(Searcher searcher, QueryScope queryScope, QueryElement parentQueryElement)
: this(parentQueryElement)
{
this.Searcher = searcher;
this.queryScope = queryScope;
}
private QueryElement(QueryElement parentQueryElement) // only use internally because it doesn't set searcher
{
subQueryElements = new List<QueryElement>();
this.parentQueryElement = parentQueryElement;
InitializeComponent();
queryTypeComboButton.BeforePopup += new EventHandler(queryTypeComboButton_BeforePopup);
resourceSelectButton.BeforePopup += new EventHandler(resourceSelectButton_BeforePopup);
SelectDefaultQueryType();
Setup();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
CurrentQueryType = null;
foreach (QueryElement subQueryElement in subQueryElements)
{
subQueryElement.Resize -= subQueryElement_Resize;
subQueryElement.QueryChanged -= subQueryElement_QueryChanged;
subQueryElement.searcher.SearchForChanged -= subQueryElement.searcher_SearchForChanged;
subQueryElement.Dispose();
}
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
void queryTypeComboButton_BeforePopup(object sender, EventArgs e)
{
PopulateGroupTypesComboButton(false);
}
void resourceSelectButton_BeforePopup(object sender, EventArgs e)
{
PopulateResourceSelectButton();
}
private QueryType CurrentQueryType
{
get
{
ToolStripItem selectedItem = queryTypeComboButton.SelectedItem;
if (selectedItem == null)
return null;
return (QueryType)selectedItem.Tag;
}
set
{
if (CurrentQueryType != null)
CurrentQueryType.SomeThingChanged -= queryType_SomeThingChanged;
if (value == null)
return;
// We have to include all types in the drop-down temporarily, in case
// we are deserializing from a type which is now forbidden (CA-25965).
PopulateGroupTypesComboButton(true);
queryTypeComboButton.SelectItem<QueryType>(delegate(QueryType queryType)
{
return queryType == value;
});
PopulateGroupTypesComboButton(false);
if (CurrentQueryType != null)
{
queryTypeComboButton.Text = CurrentQueryType.ToString();
CurrentQueryType.SomeThingChanged += queryType_SomeThingChanged;
Setup();
}
}
}
private bool IsSubQueryElement
{
get
{
return parentQueryElement != null;
}
}
private void PopulateGroupTypesComboButton(bool showAll)
{
int queryTypeGroup = -1;
queryTypeComboButton.ClearItems();
List<QueryType> allQueryTypes = new List<QueryType>(queryTypes);
foreach (QueryType qt in customFields)
allQueryTypes.Add(qt); // can't use AddRange() because customFields is List<CustomFieldQueryType> not List<QueryType>!
foreach (QueryType queryType in allQueryTypes)
{
if (!showAll && !WantQueryType(queryType)) // only add relevant items to the drop-down
continue;
if (queryTypeGroup != -1 && queryType.Group != queryTypeGroup)
{
queryTypeComboButton.AddItem(new ToolStripSeparator());
}
queryTypeGroup = queryType.Group;
ToolStripMenuItem queryTypeMenuItem = new ToolStripMenuItem();
queryTypeMenuItem.Text = queryType.ToString();
queryTypeMenuItem.Tag = queryType;
queryTypeComboButton.AddItem(queryTypeMenuItem);
}
}
private void SelectDefaultQueryType()
{
CurrentQueryType = DefaultQueryType;
}
void queryType_SomeThingChanged(object sender, EventArgs e)
{
Program.Invoke(this, Setup);
}
private void RefreshSubQueryElements()
{
if (CurrentQueryType == null)
return;
QueryType.Category category = CurrentQueryType.GetCategory;
int topOffset = queryTypeComboButton.Height + 2;
foreach (QueryElement subQueryElement in subQueryElements)
{
subQueryElement.Resize -= new EventHandler(subQueryElement_Resize);
subQueryElement.Resize += new EventHandler(subQueryElement_Resize);
subQueryElement.QueryChanged -= new EventHandler(subQueryElement_QueryChanged);
subQueryElement.QueryChanged += new EventHandler(subQueryElement_QueryChanged);
if (category == QueryType.Category.ParentChild)
{
int indent = matchTypeComboButton.Left - queryTypeComboButton.Left; // need to push everything in the subQuery this far right
subQueryElement.Left = indent;
subQueryElement.Width = this.Width - indent;
subQueryElement.Top = 0;
}
else // must be Category.Group
{
subQueryElement.Left = 30;
subQueryElement.Width = this.Width - 30;
subQueryElement.Top = topOffset;
topOffset += subQueryElement.Height;
}
if (!Controls.Contains(subQueryElement))
Controls.Add(subQueryElement);
}
// This line causes OnResize(), which calls this function again recursively
// (with the same "this"). I haven't messed with it yet because although this
// function is called far more often than necessary, the number of query elements
// is typically small, so it's not too painful. SRET 2009-01-09.
this.Height = topOffset;
}
void subQueryElement_QueryChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void ClearSubQueryElements()
{
foreach (QueryElement subQueryElement in subQueryElements.ToArray())
RemoveSubQueryElement(subQueryElement);
}
void subQueryElement_Resize(object sender, EventArgs e)
{
RefreshSubQueryElements();
if (parentQueryElement == null)
Invalidate();
}
protected override void OnResize(EventArgs e)
{
RefreshSubQueryElements();
// The following line shouldn't be necessary, but the right-anchoring doesn't seem to work
// in one situation: when you have a parent-child query, and you change it into a group
// query, so the parent-child query becomes the first child of the group, then the [-] button
// appears in the wrong place. SRET 2009-01-09.
removeButton.Left = this.Width - 25;
base.OnResize(e);
}
private bool populatingComboButton = false;
/// <summary>
/// Populate a combo box, trying to preserve the selected index
/// </summary>
/// <param name="comboButton"></param>
/// <param name="values"></param>
/// <param name="imageDelegate"></param>
private void PopulateComboButton(DropDownComboButton comboButton, Object[] values, ImageDelegate<Object> imageDelegate)
{
populatingComboButton = true;
try
{
bool selected = false;
ToolStripItem selectedItem = comboButton.SelectedItem;
comboButton.ClearItems();
ToolStripMenuItem firstMenuItem = null;
foreach (Object value in values)
{
ToolStripMenuItem menuItem = new ToolStripMenuItem();
String text = value.ToString();
menuItem.Text = text.EscapeAmpersands().Ellipsise(100);
menuItem.Tag = value;
if (imageDelegate != null)
menuItem.Image = Images.GetImage16For(imageDelegate(value));
comboButton.AddItem(menuItem);
if (firstMenuItem == null)
firstMenuItem = menuItem;
if (selectedItem != null && value.Equals(selectedItem.Tag))
{
selected = true;
comboButton.SelectedItem = menuItem;
}
}
if (!selected)
comboButton.SelectedItem = firstMenuItem;
}
finally
{
populatingComboButton = false;
}
}
private void PopulateResourceSelectButton()
{
Search search = GetSearchForResourceSelectButton();
if (search == null)
resourceSelectButton.ClearItems(); // shouldn't happen
else
resourceSelectButton.Populate(search);
}
private Search GetSearchForResourceSelectButton()
{
if (queryScope == null)
return null;
Query query = new Query(queryScope, null);
Sort sort = new Sort("name", true);
Sort[] sorts = { sort };
Grouping grouping = null;
switch (queryScope.ObjectTypes)
{
// The same list of recursive types as defined in static QueryElement()
case ObjectTypes.Pool:
grouping = null;
break;
case ObjectTypes.Appliance:
case ObjectTypes.Server:
grouping = new XenModelObjectPropertyGrouping<Pool>(PropertyNames.pool, null);
break;
case ObjectTypes.VM:
case ObjectTypes.Network:
case ObjectTypes.LocalSR | ObjectTypes.RemoteSR:
{
Grouping serverGrouping = new XenModelObjectPropertyGrouping<Host>(PropertyNames.host, null);
grouping = new XenModelObjectPropertyGrouping<Pool>(PropertyNames.pool, serverGrouping);
break;
}
case ObjectTypes.VDI:
{
Grouping srGrouping = new XenModelObjectPropertyGrouping<SR>(PropertyNames.storage, null);
Grouping serverGrouping = new XenModelObjectPropertyGrouping<Host>(PropertyNames.host, srGrouping);
grouping = new XenModelObjectPropertyGrouping<Pool>(PropertyNames.pool, serverGrouping);
break;
}
case ObjectTypes.Folder:
grouping = new FolderGrouping((Grouping)null);
break;
}
return new Search(query, grouping, false, "", "", null, sorts);
}
private void Setup()
{
Setup(false);
}
private void Setup(bool queryTypeDropDownChanged)
{
if (populatingComboButton)
return;
// no remove button for "Select a filter",
// nor for parent/child subqueries (where the main query already has a remove button on the same row)
removeButton.Visible = !(CurrentQueryType is DummyQueryType) &&
!(IsSubQueryElement && parentQueryElement.CurrentQueryType.GetCategory == QueryType.Category.ParentChild);
matchTypeComboButton.Visible = CurrentQueryType.ShowMatchTypeComboButton;
if (CurrentQueryType.ShowMatchTypeComboButton)
PopulateComboButton(matchTypeComboButton, CurrentQueryType.MatchTypeComboButtonEntries, null);
QueryType.Category category = CurrentQueryType.GetCategory;
if (category == QueryType.Category.Group)
{
// if we are changing from non-boolean to boolean, use the old query as the first child
// of the new boolean query (CA-25127)
if (queryTypeDropDownChanged && !(lastQueryFilter is GroupQuery))
{
ClearSubQueryElements();
subQueryElements.Add(new QueryElement(this.Searcher, null, this, lastQueryFilter));
}
}
else if (category == QueryType.Category.ParentChild && queryTypeDropDownChanged)
ClearSubQueryElements();
if (category != QueryType.Category.Single)
{
// if we don't have a "Select a filter...", then add one now
if (!HasDummySubQuery())
AddDummySubQuery(CurrentQueryType.SubQueryScope);
}
else
{
ClearSubQueryElements();
}
RefreshSubQueryElements();
// also if our parent doesn't have a "Select a filter...", then add one now
// (This only occurs when changing from "Select a filter..." to something else).
if (queryTypeDropDownChanged && lastQueryFilter is DummyQuery &&
IsSubQueryElement && parentQueryElement.CurrentQueryType is GroupQueryType &&
parentQueryElement.subQueryElements.Contains(this) && // this excludes the case where the subquery is still being initialized
!parentQueryElement.HasDummySubQuery())
{
parentQueryElement.AddDummySubQuery(null);
parentQueryElement.RefreshSubQueryElements();
}
Setup2();
}
private void Setup2()
{
textBox.Visible = CurrentQueryType.ShowTextBox(this);
dateTimePicker.Visible = CurrentQueryType.ShowDateTimePicker(this);
unitsLabel.Visible = numericUpDown.Visible = CurrentQueryType.ShowNumericUpDown(this);
unitsLabel.Text = CurrentQueryType.Units(this);
ComboButton.Visible = CurrentQueryType.ShowComboButton(this);
if (CurrentQueryType.ShowComboButton(this))
PopulateComboButton(ComboButton, CurrentQueryType.GetComboButtonEntries(this), null);
resourceSelectButton.Visible = CurrentQueryType.ShowResourceSelectButton(this);
if (CurrentQueryType.ShowResourceSelectButton(this))
PopulateResourceSelectButton();
OnQueryChanged();
}
QueryFilter[] GetSubQueries()
{
List<QueryFilter> subQueries = new List<QueryFilter>();
foreach (QueryElement subQueryElement in subQueryElements)
{
QueryFilter query = subQueryElement.QueryFilter;
if (query != null)
subQueries.Add(query);
}
return subQueries.ToArray();
}
private bool HasDummySubQuery()
{
foreach (QueryElement subQueryElement in subQueryElements)
{
if (subQueryElement.CurrentQueryType is DummyQueryType)
return true;
}
return false;
}
private void AddDummySubQuery(QueryScope queryScope)
{
subQueryElements.Add(new QueryElement(this.Searcher, queryScope, this));
}
public Searcher Searcher
{
get { return searcher; }
set
{
searcher = value;
if (searcher != null)
searcher.SearchForChanged += searcher_SearchForChanged;
}
}
public QueryFilter QueryFilter
{
get
{
return (CurrentQueryType == null ? null : CurrentQueryType.GetQuery(this));
}
set
{
SelectQueryTypeFor(value);
}
}
private void SelectQueryTypeFor(QueryFilter query)
{
if (query == null)
{
SelectDefaultQueryType();
return;
}
if (CurrentQueryType.ForQuery(query))
{
Setup2();
CurrentQueryType.FromQuery(query, this);
return;
}
foreach (QueryType queryType in queryTypes)
{
if (!queryType.ForQuery(query))
continue;
CurrentQueryType = queryType;
queryType.FromQuery(query, this);
return;
}
foreach (QueryType queryType in customFields)
{
if (!queryType.ForQuery(query))
continue;
CurrentQueryType = queryType;
queryType.FromQuery(query, this);
return;
}
SelectDefaultQueryType();
}
// Do we want this query type, based on the search-for?
private bool WantQueryType(QueryType qt)
{
QueryScope scope;
bool recursive; // is this element the subquery of a parent-child query?
if (queryScope != null)
{
scope = queryScope;
recursive = true;
}
else
{
scope = (searcher == null ? null : searcher.QueryScope);
recursive = false;
}
if (scope == null)
return true;
// If this is the subquery of a parent-child query, it can't have children
if (recursive && qt.GetCategory != QueryType.Category.Single)
return false;
// Conversely, the UuidQueryType only shows up as the subquery of a parent-child query
// (no point in a search for one object)
if (!recursive && qt is UuidQueryType)
return false;
// If this is itself a parent-child query, we only allow it if the global scope
// includes something other than this element's scope. For example, it's permissible
// to search for Servers and VMs with a constraint on the Servers, but it's not
// permissible to search for just Servers and put a constraint on the Servers.
// Folders are an exception because the search is then for the parent folder, not
// the folder itself.
if (scope.WantSubsetOf(qt.SubQueryScope) &&
!qt.SubQueryScope.Equals(ObjectTypes.Folder))
return false;
return scope.WantSubsetOf(qt.AppliesTo);
}
private void RemoveUnwantedFilters()
{
QueryType qt = CurrentQueryType;
bool wanted = WantQueryType(qt);
if (wanted && qt.GetCategory == QueryType.Category.Group)
{
// For group queries, remove subqueries recursively
foreach (QueryElement subQueryElement in subQueryElements.ToArray())
subQueryElement.RemoveUnwantedFilters();
// This element is now unwanted if we've deleted all its children
if (subQueryElements.Count == 0)
wanted = false;
// If this is an AND or OR (not a NONE), and there is only one
// child left, remove the conjunction by promoting the child.
if (subQueryElements.Count == 1)
{
GroupQueryType gqt = qt as GroupQueryType;
if (gqt != null && (gqt.Type == GroupQuery.GroupQueryType.And ||
gqt.Type == GroupQuery.GroupQueryType.Or))
{
this.QueryFilter = subQueryElements[0].QueryFilter;
RefreshSubQueryElements();
}
}
}
if (!wanted)
{
if (IsSubQueryElement)
{
parentQueryElement.RemoveSubQueryElement(this);
parentQueryElement.RefreshSubQueryElements();
}
else
SelectDefaultQueryType();
}
}
private void searcher_SearchForChanged()
{
// We only run this for the outermost query because subqueries
// are removed by their parent (RemoveUnwantedFilters() is recursive).
if (!IsSubQueryElement)
{
RemoveUnwantedFilters();
Setup();
OnQueryChanged();
}
}
private void queryTypeComboButton_BeforeItemSelected(object sender, EventArgs e)
{
lastQueryFilter = this.QueryFilter;
if (CurrentQueryType != null)
{
CurrentQueryType.SomeThingChanged -= queryType_SomeThingChanged;
}
}
private void queryTypeComboButton_ItemSelected(object sender, EventArgs e)
{
if (CurrentQueryType != null)
{
CurrentQueryType.SomeThingChanged += queryType_SomeThingChanged;
}
}
private void queryTypeComboButton_SelectedItemChanged(object sender, EventArgs e)
{
Setup(true);
}
private void matchTypeComboButton_SelectedItemChanged(object sender, EventArgs e)
{
Setup2();
}
private void ComboButton_SelectedIndexChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void resourceSelectButton_SelectedIndexChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void numericUpDown_ValueChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void numericUpDown_KeyUp(object sender, KeyEventArgs e)
{
OnQueryChanged();
}
private void dateTimePicker_ValueChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void textBox_TextChanged(object sender, EventArgs e)
{
OnQueryChanged();
}
private void removeButton_Click(object sender, EventArgs e)
{
if (IsSubQueryElement)
{
parentQueryElement.RemoveSubQueryElement(this);
parentQueryElement.RefreshSubQueryElements();
parentQueryElement.OnQueryChanged();
}
else
{
SelectDefaultQueryType();
OnQueryChanged();
}
}
// Remove subquery element. Caller needs to call parent.RefreshSubQueryElements() and
// parent.OnQueryChanged() -- or parent.Setup() which calls both -- afterwards.
private void RemoveSubQueryElement(QueryElement subQueryElement)
{
Controls.Remove(subQueryElement);
subQueryElements.Remove(subQueryElement);
subQueryElement.Resize -= subQueryElement_Resize;
subQueryElement.QueryChanged -= subQueryElement_QueryChanged;
subQueryElement.searcher.SearchForChanged -= subQueryElement.searcher_SearchForChanged;
subQueryElement.Dispose();
}
#region Nested classes
internal abstract class QueryType
{
private readonly int group = 0;
private readonly ObjectTypes appliesTo;
protected QueryType(int group, ObjectTypes appliesTo)
{
this.group = group;
this.appliesTo = appliesTo;
}
/// <summary>
/// If this query type is correct for this query, return true;
/// Call FromQuery to populate the correct combo boxes etc
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public abstract bool ForQuery(QueryFilter query);
public abstract void FromQuery(QueryFilter query, QueryElement queryElement);
/// <summary>
/// May return null if this query element is not ready yet
/// </summary>
public abstract QueryFilter GetQuery(QueryElement queryElement);
public enum Category
{
Single, // match the object itself
ParentChild, // match ancestor or descendant object
Group // a group query
}
public virtual Category GetCategory { get { return Category.Single; } }
public virtual QueryScope SubQueryScope { get { return null; } } // QueryScope for subquery (if category == ParentChild)
public virtual bool ShowMatchTypeComboButton { get { return false; } }
public virtual Object[] MatchTypeComboButtonEntries { get { return null; } }
public virtual bool ShowTextBox(QueryElement queryElement) { return false; }
public virtual bool ShowDateTimePicker(QueryElement queryElement) { return false; }
public virtual bool ShowComboButton(QueryElement queryElement) { return false; }
public virtual bool ShowNumericUpDown(QueryElement queryElement) { return false; }
public virtual bool ShowResourceSelectButton(QueryElement queryElement) { return false; }
public virtual String Units(QueryElement queryElement) { return String.Empty; }
public virtual Object[] GetComboButtonEntries(QueryElement queryElement) { return null; }
public event EventHandler SomeThingChanged;
public int Group { get { return group; } }
public ObjectTypes AppliesTo
{
get { return appliesTo; }
}
/// <summary>
/// "Something changed" means that some external thing changed, usually in the cache,
/// and we need to repopulate the drop-downs for this QueryElement as a result.
/// </summary>
protected void OnSomeThingChanged()
{
if (SomeThingChanged != null)
SomeThingChanged(this, new EventArgs());
}
}
// A dummy query type which doesn't contribute to the search
internal class DummyQueryType : QueryType
{
internal DummyQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo)
{ }
public override String ToString()
{
return Messages.SELECT_A_FILTER;
}
public override bool ForQuery(QueryFilter query)
{
return (query is DummyQuery);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{ }
public override QueryFilter GetQuery(QueryElement queryElement)
{
return new DummyQuery();
}
}
internal class GroupQueryType : QueryType
{
private readonly GroupQuery.GroupQueryType type;
internal GroupQueryType(int group, ObjectTypes appliesTo, GroupQuery.GroupQueryType type)
: base(group, appliesTo)
{
this.type = type;
}
public GroupQuery.GroupQueryType Type
{
get { return type; }
}
public override String ToString()
{
switch (type)
{
case GroupQuery.GroupQueryType.And:
return Messages.ALL_OF;
case GroupQuery.GroupQueryType.Or:
return Messages.ANY_OF;
case GroupQuery.GroupQueryType.Nor:
return Messages.NONE_OF;
default:
return "";
}
}
public override Category GetCategory { get { return Category.Group; } }
public override QueryFilter GetQuery(QueryElement queryElement)
{
return new GroupQuery(queryElement.GetSubQueries(), type);
}
public override bool ForQuery(QueryFilter query)
{
GroupQuery groupQuery = query as GroupQuery;
if (groupQuery == null)
return false;
if (groupQuery.type != type)
return false;
return true;
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
GroupQuery groupQuery = query as GroupQuery;
for (int i = 0; i < groupQuery.subqueries.Length; i++)
{
QueryFilter subquery = groupQuery.subqueries[i];
if (queryElement.subQueryElements.Count > i)
queryElement.subQueryElements[i].SelectQueryTypeFor(subquery);
else
queryElement.subQueryElements.Add(new QueryElement(queryElement.Searcher, null, queryElement, subquery));
}
while (queryElement.subQueryElements.Count > groupQuery.subqueries.Length)
queryElement.RemoveSubQueryElement(
queryElement.subQueryElements[queryElement.subQueryElements.Count - 1]);
queryElement.Setup();
}
}
internal abstract class PropertyQueryType<T> : QueryType
{
protected readonly PropertyNames property;
protected readonly PropertyAccessor propertyAccessor;
protected readonly String i18n;
protected PropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property, String i18n)
: base(group, appliesTo)
{
this.property = property;
this.propertyAccessor = PropertyAccessors.Get(property);
this.i18n = (i18n == null ? PropertyAccessors.PropertyNames_i18n[property] : i18n);
}
protected PropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: this(group, appliesTo, property, null)
{
}
public override String ToString()
{
return i18n;
}
// Note: This function only tests the values of T and property.
// This is good enough for most cases and avoids each derived class
// having to define its own ForQuery. But in some cases there are
// clashes (particularly when T is XMO<U> or List<XMO<u>>) and in
// that case we do have to override this function in both derived
// classes. Derived classes of MatchType may lead to clashes too.
public override bool ForQuery(QueryFilter query)
{
PropertyQuery<T> propertyQuery = query as PropertyQuery<T>;
if (propertyQuery == null)
return false;
return (propertyQuery.property == this.property);
}
}
internal class StringPropertyQueryType : PropertyQueryType<String>
{
internal StringPropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override bool ShowTextBox(QueryElement queryElement) { return true; }
public class ExtraComboEntry
{
public StringPropertyQuery.PropertyQueryType type;
public ExtraComboEntry(StringPropertyQuery.PropertyQueryType type)
{
this.type = type;
}
public override string ToString()
{
switch (type)
{
case StringPropertyQuery.PropertyQueryType.contains:
return Messages.CONTAINS;
case StringPropertyQuery.PropertyQueryType.exactmatch:
return Messages.EXACT_MATCH;
case StringPropertyQuery.PropertyQueryType.endswith:
return Messages.ENDS_WITH;
case StringPropertyQuery.PropertyQueryType.startswith:
return Messages.STARTS_WITH;
case StringPropertyQuery.PropertyQueryType.notcontain:
return Messages.NOT_CONTAINS;
default:
return "";
}
}
public override bool Equals(object obj)
{
ExtraComboEntry other = obj as ExtraComboEntry;
if (other == null)
return false;
return type == other.type;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public override object[] MatchTypeComboButtonEntries
{
get { return MatchTypeEntries; }
}
public static object[] MatchTypeEntries
{
get
{
return new ExtraComboEntry[] {
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.contains),
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.notcontain),
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.startswith),
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.endswith),
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.exactmatch)
};
}
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
ExtraComboEntry extraComboEntry = (ExtraComboEntry)queryElement.matchTypeComboButton.SelectedItem.Tag;
return new StringPropertyQuery(property, queryElement.textBox.Text,
extraComboEntry.type, false);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
StringPropertyQuery stringQuery = query as StringPropertyQuery;
queryElement.matchTypeComboButton.SelectItem<ExtraComboEntry>(delegate(ExtraComboEntry entry)
{
return entry.type == stringQuery.type;
});
queryElement.textBox.Text = stringQuery.query;
}
}
internal class UuidQueryType : PropertyQueryType<String>
{
internal UuidQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo, PropertyNames.uuid)
{
}
public override bool ShowResourceSelectButton(QueryElement queryElement) { return true; }
public override QueryFilter GetQuery(QueryElement queryElement)
{
ToolStripItem item = queryElement.resourceSelectButton.SelectedItem;
IXenObject ixmo = (item == null ? null : item.Tag as IXenObject);
String uuid = (string)propertyAccessor(ixmo);
return new StringPropertyQuery(property, uuid, StringPropertyQuery.PropertyQueryType.exactmatch, true);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
StringPropertyQuery stringQuery = query as StringPropertyQuery;
queryElement.resourceSelectButton.SelectItem<IXenObject>(delegate(IXenObject entry)
{
return ((string)propertyAccessor(entry) == stringQuery.query);
});
}
}
internal class IPAddressQueryType : PropertyQueryType<List<ComparableAddress>>
{
internal IPAddressQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override bool ShowTextBox(QueryElement queryElement) { return true; }
public override Object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.IS };
}
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
ComparableAddress address;
if (!ComparableAddress.TryParse(queryElement.textBox.Text, true, true, out address))
return null;
return new IPAddressQuery(property, address);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
IPAddressQuery ipAddressQuery = query as IPAddressQuery;
queryElement.textBox.Text = ipAddressQuery.address.ToString();
}
}
internal class DatePropertyQueryType : PropertyQueryType<DateTime>
{
internal DatePropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override bool ShowDateTimePicker(QueryElement queryElement)
{
return ShouldShowDateTimePicker(queryElement);
}
public static bool ShouldShowDateTimePicker(QueryElement queryElement)
{
ExtraComboEntry extraComboEntry = (ExtraComboEntry)queryElement.matchTypeComboButton.SelectedItem.Tag;
switch (extraComboEntry.type)
{
case DatePropertyQuery.PropertyQueryType.before:
case DatePropertyQuery.PropertyQueryType.after:
case DatePropertyQuery.PropertyQueryType.exact:
return true;
default:
return false;
}
}
internal class ExtraComboEntry
{
public DatePropertyQuery.PropertyQueryType type;
public ExtraComboEntry(DatePropertyQuery.PropertyQueryType type)
{
this.type = type;
}
public override string ToString()
{
switch (type)
{
case DatePropertyQuery.PropertyQueryType.after:
return Messages.AFTER;
case DatePropertyQuery.PropertyQueryType.before:
return Messages.BEFORE;
case DatePropertyQuery.PropertyQueryType.exact:
return Messages.EXACT_MATCH;
case DatePropertyQuery.PropertyQueryType.lastweek:
return Messages.LAST_WEEK;
case DatePropertyQuery.PropertyQueryType.thisweek:
return Messages.THIS_WEEK;
case DatePropertyQuery.PropertyQueryType.today:
return Messages.TODAY;
case DatePropertyQuery.PropertyQueryType.yesterday:
return Messages.YESTERDAY;
default:
return "";
}
}
public override bool Equals(object obj)
{
ExtraComboEntry other = obj as ExtraComboEntry;
if (other == null)
return false;
return type == other.type;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public override object[] MatchTypeComboButtonEntries
{
get { return MatchTypeEntries; }
}
public static object[] MatchTypeEntries
{
get
{
return new ExtraComboEntry[] {
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.today),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.yesterday),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.thisweek),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.lastweek),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.before),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.after),
new ExtraComboEntry(DatePropertyQuery.PropertyQueryType.exact)
};
}
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
ExtraComboEntry extraComboEntry = (ExtraComboEntry)queryElement.matchTypeComboButton.SelectedItem.Tag;
return new DatePropertyQuery(property, queryElement.dateTimePicker.Value, extraComboEntry.type);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
DatePropertyQuery dateQuery = query as DatePropertyQuery;
queryElement.matchTypeComboButton.SelectItem<ExtraComboEntry>(delegate(ExtraComboEntry entry)
{
return entry.type == dateQuery.type;
});
queryElement.dateTimePicker.Value = dateQuery.query;
}
}
internal class EnumPropertyQueryType<T> : PropertyQueryType<T>
{
private readonly Dictionary<String, T> i18ns;
internal EnumPropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
this.i18ns = (Dictionary<String, T>)PropertyAccessors.Geti18nFor(property);
System.Diagnostics.Trace.Assert(typeof(T).IsEnum);
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override Object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.IS, Messages.IS_NOT };
}
}
public override bool ShowComboButton(QueryElement queryElement) { return true; }
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
String[] enumStrings = new String[i18ns.Count];
i18ns.Keys.CopyTo(enumStrings, 0);
return enumStrings;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
bool equals = queryElement.matchTypeComboButton.SelectedItem.Tag.Equals(Messages.IS);
T query = i18ns[(String)queryElement.ComboButton.SelectedItem.Tag];
return new EnumPropertyQuery<T>(property, query, equals);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
EnumPropertyQuery<T> enumQuery = query as EnumPropertyQuery<T>;
if (enumQuery == null) // This should never happen, but is the
return; // only cause of CA-18166 reopening
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == (enumQuery.equals ? Messages.IS : Messages.IS_NOT);
});
queryElement.ComboButton.SelectItem<String>(delegate(String entry)
{
return Enum.Equals(i18ns[entry], enumQuery.query);
});
}
}
// This class is currently only used for the OS, which is only available for VMs.
// If this changes, we may need to alter the loop in populateCollectedValues() to
// iterate over other objects. SRET 2010-11-01.
internal class ValuePropertyQueryType : PropertyQueryType<String>
{
private readonly Dictionary<String, Object> collectedValues;
public ValuePropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
collectedValues = new Dictionary<String, Object>();
ConnectionsManager.XenConnections.CollectionChanged += CollectionChanged;
populateCollectedValues();
}
// This object is static for the life of the GUI, so we never have to unhook these events.
private void populateCollectedValues()
{
collectedValues.Clear();
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.RegisterBatchCollectionChanged<VM_guest_metrics>(CollectionChanged);
// Only iterate over VMs: see comments at the top of this class.
foreach (VM vm in connection.Cache.VMs)
{
String value = propertyAccessor(vm) as String;
if (value == null)
continue;
if (collectedValues.ContainsKey(value))
continue;
collectedValues[value] = null;
}
}
OnSomeThingChanged();
}
void CollectionChanged(object sender, EventArgs e)
{
Program.BeginInvoke(Program.MainWindow,populateCollectedValues);
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override Object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.IS, Messages.IS_NOT };
}
}
public override bool ShowComboButton(QueryElement queryElement) { return true; }
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
String[] entries = new String[collectedValues.Keys.Count];
collectedValues.Keys.CopyTo(entries, 0);
// Sort the list in alphabetical order, but put "Unknown" at the bottom
Array.Sort(entries, (a, b) =>
{
if (a == Messages.UNKNOWN)
return (b == Messages.UNKNOWN ? 0 : 1);
else if (b == Messages.UNKNOWN)
return -1;
else
return a.CompareTo(b);
}
);
return entries;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
if (queryElement.ComboButton.SelectedItem == null)
return null;
bool equals = queryElement.matchTypeComboButton.SelectedItem.Tag.Equals(Messages.IS);
String query = queryElement.ComboButton.SelectedItem.Tag as String;
return new ValuePropertyQuery(property, query, equals);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
ValuePropertyQuery valueQuery = query as ValuePropertyQuery;
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == (valueQuery.equals ? Messages.IS : Messages.IS_NOT);
});
queryElement.ComboButton.SelectItem<String>(delegate(String entry)
{
return entry.Equals(valueQuery.query);
});
}
}
internal abstract class RecursiveQueryType<T, O, Q> : PropertyQueryType<T>
where O : XenObject<O>
where Q : RecursivePropertyQuery<T>
{
QueryScope subQueryScope;
public RecursiveQueryType(int group, ObjectTypes appliesTo, PropertyNames property, ObjectTypes subQueryScope)
: base(group, appliesTo, property)
{
this.subQueryScope = new QueryScope(subQueryScope);
ConnectionsManager.XenConnections.CollectionChanged += XenConnections_CollectionChanged;
XenConnections_CollectionChanged(null, null);
}
public override Category GetCategory
{
get
{
return Category.ParentChild;
}
}
public override QueryScope SubQueryScope
{
get
{
return subQueryScope;
}
}
void XenConnections_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.RegisterBatchCollectionChanged<O>(dict_BatchCollectionChanged);
}
}
void dict_BatchCollectionChanged(object sender, EventArgs e)
{
OnSomeThingChanged();
}
protected abstract RecursivePropertyQuery<T> newQuery(PropertyNames property, QueryFilter qf);
public override QueryFilter GetQuery(QueryElement queryElement)
{
QueryFilter qf;
QueryFilter[] subQueries = queryElement.GetSubQueries();
if (subQueries == null || subQueries.Length == 0) // shouldn't happen, but let's be safe
qf = new DummyQuery();
else
qf = subQueries[0];
// Special case for CA-30595: interpret "parent folder is (blank)" as "parent folder is /".
if (property == PropertyNames.folder && qf is StringPropertyQuery &&
(qf as StringPropertyQuery).property == PropertyNames.uuid && (qf as StringPropertyQuery).query == null)
{
qf = new StringPropertyQuery(PropertyNames.uuid, "/", StringPropertyQuery.PropertyQueryType.exactmatch, true);
}
return newQuery(property, qf); // this should just be new Q(property, qf) but that's illegal syntax: can only use default constructor because there's no way to specify that all derived classes must implement new(property, qf)
}
public override bool ForQuery(QueryFilter query)
{
RecursivePropertyQuery<T> recursivePropertyQuery = query as RecursivePropertyQuery<T>;
return (recursivePropertyQuery != null &&
recursivePropertyQuery.property == property);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
Q recursiveQuery = query as Q;
QueryFilter subQuery = recursiveQuery.subQuery;
queryElement.ClearSubQueryElements();
queryElement.subQueryElements.Add(new QueryElement(queryElement.Searcher, SubQueryScope, queryElement, subQuery));
queryElement.Setup();
}
}
internal class RecursiveXMOQueryType<T> : RecursiveQueryType<T, T, RecursiveXMOPropertyQuery<T>> where T : XenObject<T>
{
public RecursiveXMOQueryType(int group, ObjectTypes appliesTo, PropertyNames property, ObjectTypes subQueryScope)
: base(group, appliesTo, property, subQueryScope)
{ }
protected override RecursivePropertyQuery<T> newQuery(PropertyNames property, QueryFilter qf)
{
return new RecursiveXMOPropertyQuery<T>(property, qf);
}
}
internal class RecursiveXMOListQueryType<T> : RecursiveQueryType<List<T>, T, RecursiveXMOListPropertyQuery<T>> where T : XenObject<T>
{
public RecursiveXMOListQueryType(int group, ObjectTypes appliesTo, PropertyNames property, ObjectTypes subQueryScope)
: base(group, appliesTo, property, subQueryScope)
{ }
protected override RecursivePropertyQuery<List<T>> newQuery(PropertyNames property, QueryFilter qf)
{
return new RecursiveXMOListPropertyQuery<T>(property, qf);
}
}
// NOT USED FOR NEW QUERIES
internal class XenModelObjectPropertyQueryType<T> : PropertyQueryType<T> where T : XenObject<T>
{
public XenModelObjectPropertyQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
ConnectionsManager.XenConnections.CollectionChanged += XenConnections_CollectionChanged;
XenConnections_CollectionChanged(null, null);
}
void XenConnections_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.RegisterBatchCollectionChanged<T>(dict_BatchCollectionChanged);
}
}
void dict_BatchCollectionChanged(object sender, EventArgs e)
{
OnSomeThingChanged();
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override Object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.IS, Messages.IS_NOT };
}
}
public override bool ShowComboButton(QueryElement queryElement) { return true; }
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
List<T> entries = new List<T>();
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.AddAll(entries, null);
}
// CA-17132: Special case pools because they're silly
if (typeof(T) == typeof(Pool))
{
entries.RemoveAll((Predicate<T>)delegate(T m)
{
return Helpers.GetPool(m.Connection) == null;
});
}
return entries.ToArray();
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
ToolStripItem i = queryElement.ComboButton.SelectedItem;
if (i == null || !(i.Tag is T))
return null;
bool equals = queryElement.matchTypeComboButton.SelectedItem.Tag.Equals(Messages.IS);
T query = (T)i.Tag;
return new XenModelObjectPropertyQuery<T>(property, query, equals);
}
public override bool ForQuery(QueryFilter query)
{
XenModelObjectPropertyQuery<T> xmoPropertyQuery = query as XenModelObjectPropertyQuery<T>;
if (xmoPropertyQuery == null)
return false;
return (xmoPropertyQuery.property == this.property);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
XenModelObjectPropertyQuery<T> xmoPropertyQuery = query as XenModelObjectPropertyQuery<T>;
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == (xmoPropertyQuery.equals ? Messages.IS : Messages.IS_NOT);
});
queryElement.ComboButton.SelectItem<T>(delegate(T entry)
{
return entry.opaque_ref.Equals(xmoPropertyQuery.query.opaque_ref);
});
}
}
// NOT USED FOR NEW QUERIES
internal class XenModelObjectListContainsQueryType<T> : PropertyQueryType<List<T>> where T : XenObject<T>
{
public XenModelObjectListContainsQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
ConnectionsManager.XenConnections.CollectionChanged += XenConnections_CollectionChanged;
XenConnections_CollectionChanged(null, null);
}
void XenConnections_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.RegisterBatchCollectionChanged<T>(dict_BatchCollectionChanged);
}
}
void dict_BatchCollectionChanged(object sender, EventArgs e)
{
OnSomeThingChanged();
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override Object[] MatchTypeComboButtonEntries
{
get
{
if (property == PropertyNames.networks)
return new String[] {
Messages.USES,
Messages.DOES_NOT_USE,
Messages.STARTS_WITH,
Messages.ENDS_WITH,
Messages.CONTAINS,
Messages.NOT_CONTAINS
};
return new String[] {
Messages.IS,
Messages.IS_NOT,
Messages.STARTS_WITH,
Messages.ENDS_WITH,
Messages.CONTAINS,
Messages.NOT_CONTAINS
};
}
}
public override bool ShowComboButton(QueryElement queryElement)
{
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
return matchType == Messages.USES
|| matchType == Messages.CONTAINED_IN
|| matchType == Messages.IS
|| matchType == Messages.DOES_NOT_USE
|| matchType == Messages.NOT_CONTAINED_IN
|| matchType == Messages.IS_NOT;
}
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
List<T> entries = new List<T>();
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
{
connection.Cache.AddAll(entries, null);
}
// CA-24314: Filter networks that should be hidden
if (typeof(T) == typeof(XenAPI.Network))
{
foreach (T entry in entries.ToArray())
{
XenAPI.Network e = entry as XenAPI.Network;
if (!e.Show(XenAdmin.Properties.Settings.Default.ShowHiddenVMs))
entries.Remove(entry);
}
}
return entries.ToArray();
}
public override bool ShowTextBox(QueryElement queryElement)
{
return !ShowComboButton(queryElement);
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
if (ShowComboButton(queryElement))
{
T t = queryElement.ComboButton.SelectedItem == null ? null : queryElement.ComboButton.SelectedItem.Tag as T;
if (matchType == Messages.USES ||
matchType == Messages.CONTAINED_IN ||
matchType == Messages.IS)
{
return new XenModelObjectListContainsQuery<T>(property, t, true);
}
else
{
System.Diagnostics.Trace.Assert(matchType == Messages.DOES_NOT_USE ||
matchType == Messages.NOT_CONTAINED_IN ||
matchType == Messages.IS_NOT);
return new XenModelObjectListContainsQuery<T>(property, t, false);
}
}
else
{
String query = queryElement.textBox.Text;
if (matchType == Messages.STARTS_WITH)
{
return new XenModelObjectListContainsNameQuery<T>(property,
StringPropertyQuery.PropertyQueryType.startswith, query);
}
else if (matchType == Messages.ENDS_WITH)
{
return new XenModelObjectListContainsNameQuery<T>(property,
StringPropertyQuery.PropertyQueryType.endswith, query);
}
else if (matchType == Messages.CONTAINS)
{
return new XenModelObjectListContainsNameQuery<T>(property,
StringPropertyQuery.PropertyQueryType.contains, query);
}
else if (matchType == Messages.NOT_CONTAINS)
{
return new XenModelObjectListContainsNameQuery<T>(property,
StringPropertyQuery.PropertyQueryType.notcontain, query);
}
else
{
return null;
}
}
}
public override bool ForQuery(QueryFilter query)
{
ListContainsQuery<T> listQuery = query as ListContainsQuery<T>; // includes both XenModelObjectListContainsQuery<T> and XenModelObjectListContainsNameQuery<T>
if (listQuery == null)
return false;
return (listQuery.property == this.property);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
XenModelObjectListContainsQuery<T> listContainsQuery = query as XenModelObjectListContainsQuery<T>;
if (listContainsQuery == null)
{
XenModelObjectListContainsNameQuery<T> nameQuery = query as XenModelObjectListContainsNameQuery<T>;
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
if (entry == Messages.STARTS_WITH)
{
return nameQuery.type == StringPropertyQuery.PropertyQueryType.startswith;
}
else if (entry == Messages.ENDS_WITH)
{
return nameQuery.type == StringPropertyQuery.PropertyQueryType.endswith;
}
else if (entry == Messages.CONTAINS)
{
return nameQuery.type == StringPropertyQuery.PropertyQueryType.contains;
}
else if (entry == Messages.NOT_CONTAINS)
{
return nameQuery.type == StringPropertyQuery.PropertyQueryType.notcontain;
}
return false;
});
queryElement.textBox.Text = nameQuery.query;
}
else
{
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
if (entry == Messages.USES
|| entry == Messages.CONTAINED_IN
|| entry == Messages.IS)
{
return listContainsQuery.contains;
}
else if (entry == Messages.DOES_NOT_USE
|| entry == Messages.NOT_CONTAINED_IN
|| entry == Messages.IS_NOT)
{
return !listContainsQuery.contains;
}
return false;
});
queryElement.ComboButton.SelectItem<T>(delegate(T entry)
{
return Helpers.GetUuid(entry).Equals(listContainsQuery.queryUUID);
});
}
}
}
// NOT USED FOR NEW QUERIES
internal class HostQueryType : XenModelObjectListContainsQueryType<Host>
{
public HostQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo, PropertyNames.host)
{
}
public override Object[] MatchTypeComboButtonEntries
{
get
{
List<Object> matchTypes = new List<Object>(base.MatchTypeComboButtonEntries);
matchTypes.Add(Messages.IS_STANDALONE);
matchTypes.Add(Messages.IS_IN_A_POOL);
return matchTypes.ToArray();
}
}
public override bool ShowTextBox(QueryElement queryElement)
{
if (ShowComboButton(queryElement))
return false;
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
return matchType != Messages.IS_STANDALONE &&
matchType != Messages.IS_IN_A_POOL;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
if (ShowComboButton(queryElement) || ShowTextBox(queryElement))
return base.GetQuery(queryElement);
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
return new NullQuery<Pool>(PropertyNames.pool, matchType == Messages.IS_STANDALONE);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
NullQuery<Pool> nullQuery = query as NullQuery<Pool>;
if (nullQuery != null)
{
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == Messages.IS_STANDALONE == nullQuery.query;
});
}
else
{
base.FromQuery(query, queryElement);
}
}
}
internal class TagQueryType : PropertyQueryType<List<String>>
{
private String[] tags = new String[] { };
private String deletedTag = null;
public TagQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo, PropertyNames.tags)
{
OtherConfigAndTagsWatcher.TagsChanged += OtherConfigAndTagsWatcher_TagsChanged;
}
void OtherConfigAndTagsWatcher_TagsChanged(object sender, EventArgs e)
{
tags = Tags.GetAllTags();
OnSomeThingChanged();
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override Object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.CONTAINS, Messages.NOT_CONTAINS,
Messages.ARE_EMPTY, Messages.ARE_NOT_EMPTY };
}
}
public override bool ShowComboButton(QueryElement queryElement)
{
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
return matchType == Messages.CONTAINS ||
matchType == Messages.NOT_CONTAINS;
}
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
if (deletedTag != null)
{
List<String> newTags = new List<String>(tags);
newTags.Add(deletedTag);
return newTags.ToArray();
}
return tags;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
if (!ShowComboButton(queryElement))
{
String matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as String;
return new ListEmptyQuery<String>(property, matchType == Messages.ARE_EMPTY);
}
if (queryElement.ComboButton.SelectedItem == null)
return null;
bool contains = queryElement.matchTypeComboButton.SelectedItem.Tag.Equals(Messages.CONTAINS);
String query = queryElement.ComboButton.SelectedItem.Tag as String;
return new StringListContainsQuery(property, query, contains);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
StringListContainsQuery listContainsQuery = query as StringListContainsQuery;
if (listContainsQuery != null)
{
if (Array.BinarySearch<String>(tags, listContainsQuery.query) < 0)
{
deletedTag = listContainsQuery.query;
OnSomeThingChanged();
}
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == (listContainsQuery.contains ? Messages.CONTAINS : Messages.NOT_CONTAINS);
});
queryElement.ComboButton.SelectItem<String>(delegate(String entry)
{
return entry.Equals(listContainsQuery.query);
});
return;
}
ListEmptyQuery<String> listEmptyQuery = query as ListEmptyQuery<String>;
if (listEmptyQuery != null)
{
queryElement.matchTypeComboButton.SelectItem<String>(delegate(String entry)
{
return entry == (listEmptyQuery.empty ? Messages.ARE_EMPTY : Messages.ARE_NOT_EMPTY);
});
}
}
}
internal abstract class CustomFieldQueryTypeBase : QueryType
{
public readonly CustomFieldDefinition definition;
public CustomFieldQueryTypeBase(int group, ObjectTypes appliesTo, CustomFieldDefinition definition)
: base(group, appliesTo)
{
this.definition = definition;
}
public override string ToString()
{
return definition.Name;
}
public override bool ForQuery(QueryFilter query)
{
CustomFieldQueryBase customFieldQuery = query as CustomFieldQueryBase;
if (customFieldQuery == null)
return false;
return customFieldQuery.definition.Equals(definition);
}
}
internal class CustomFieldStringQueryType : CustomFieldQueryTypeBase
{
public CustomFieldStringQueryType(int group, ObjectTypes appliesTo, CustomFieldDefinition definition)
: base(group, appliesTo, definition)
{ }
public override bool ShowMatchTypeComboButton { get { return true; } }
public override bool ShowTextBox(QueryElement queryElement) { return true; }
public override object[] MatchTypeComboButtonEntries
{
get { return StringPropertyQueryType.MatchTypeEntries; }
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
StringPropertyQueryType.ExtraComboEntry extraComboEntry
= (StringPropertyQueryType.ExtraComboEntry)queryElement.matchTypeComboButton.SelectedItem.Tag;
return new CustomFieldQuery(definition, queryElement.textBox.Text, extraComboEntry.type);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
CustomFieldQuery customFieldQuery = query as CustomFieldQuery;
queryElement.matchTypeComboButton.SelectItem<StringPropertyQueryType.ExtraComboEntry>(
delegate(StringPropertyQueryType.ExtraComboEntry entry)
{
return entry.type == customFieldQuery.type;
});
queryElement.textBox.Text = customFieldQuery.query;
}
}
internal class CustomFieldDateQueryType : CustomFieldQueryTypeBase
{
public CustomFieldDateQueryType(int group, ObjectTypes appliesTo, CustomFieldDefinition definition)
: base(group, appliesTo, definition)
{ }
public override bool ShowMatchTypeComboButton { get { return true; } }
public override bool ShowDateTimePicker(QueryElement queryElement)
{
return DatePropertyQueryType.ShouldShowDateTimePicker(queryElement);
}
public override object[] MatchTypeComboButtonEntries
{
get { return DatePropertyQueryType.MatchTypeEntries; }
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
DatePropertyQueryType.ExtraComboEntry extraComboEntry
= (DatePropertyQueryType.ExtraComboEntry)queryElement.matchTypeComboButton.SelectedItem.Tag;
return new CustomFieldDateQuery(definition, queryElement.dateTimePicker.Value, extraComboEntry.type);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
CustomFieldDateQuery customFieldQuery = query as CustomFieldDateQuery;
queryElement.matchTypeComboButton.SelectItem<DatePropertyQueryType.ExtraComboEntry>(
delegate(DatePropertyQueryType.ExtraComboEntry entry)
{
return entry.type == customFieldQuery.type;
});
queryElement.dateTimePicker.Value = customFieldQuery.query;
}
}
internal class BooleanQueryType : PropertyQueryType<bool>
{
public BooleanQueryType(int group, ObjectTypes appliesTo, PropertyNames property)
: base(group, appliesTo, property)
{
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
BooleanQuery booleanQuery = query as BooleanQuery;
queryElement.ComboButton.SelectItem<String>(delegate(String item)
{
return (item == Messages.TRUE) == booleanQuery.query;
});
}
public override bool ShowMatchTypeComboButton { get { return true; } }
public override object[] MatchTypeComboButtonEntries
{
get
{
return new String[] { Messages.IS };
}
}
public override bool ShowComboButton(QueryElement queryElement) { return true; }
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
return new String[] { Messages.TRUE, Messages.FALSE };
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
bool query = queryElement.ComboButton.SelectedItem.Tag as String == Messages.TRUE;
return new BooleanQuery(property, query);
}
}
internal class NullQueryType<T> : PropertyQueryType<T> where T : XenObject<T>
{
bool isNull;
public NullQueryType(int group, ObjectTypes appliesTo, PropertyNames property, bool isNull, String i18n) :
base(group, appliesTo, property, i18n)
{
this.isNull = isNull;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
return new NullQuery<T>(property, isNull);
}
public override bool ForQuery(QueryFilter query)
{
NullQuery<T> nullQuery = query as NullQuery<T>;
return (nullQuery != null &&
nullQuery.property == property &&
nullQuery.query == isNull);
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
// nothing to do because there are no further choices
}
}
internal abstract class MatchQueryType : QueryType
{
private String i18n;
public MatchQueryType(int group, ObjectTypes appliesTo, String i18n)
: base(group, appliesTo)
{
this.i18n = i18n;
}
public override String ToString()
{
return i18n;
}
protected abstract MatchType[] MatchTypes { get; }
public override bool ShowMatchTypeComboButton { get { return true; } }
public override object[] MatchTypeComboButtonEntries { get { return MatchTypes; } }
public override bool ShowComboButton(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return false;
return matchType.ShowComboButton(queryElement);
}
public override bool ShowNumericUpDown(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return false;
return matchType.ShowNumericUpDown(queryElement);
}
public override Object[] GetComboButtonEntries(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return null;
return matchType.ComboButtonEntries;
}
public override bool ShowTextBox(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return false;
return matchType.ShowTextBox(queryElement);
}
public override string Units(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return String.Empty;
return matchType.Units(queryElement);
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
MatchType matchType = queryElement.matchTypeComboButton.SelectedItem.Tag as MatchType;
if (matchType == null)
return null;
return matchType.GetQuery(queryElement);
}
public override bool ForQuery(QueryFilter query)
{
foreach (MatchType matchType in MatchTypes)
if (matchType.ForQuery(query))
return true;
return false;
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
foreach (MatchType matchType in MatchTypes)
if (matchType.ForQuery(query))
{
queryElement.matchTypeComboButton.SelectItem<MatchType>(delegate(MatchType entry)
{
return entry == matchType;
});
matchType.FromQuery(query, queryElement);
return;
}
}
}
public abstract class MatchType
{
private String matchText;
protected MatchType(String matchText)
{
this.matchText = matchText;
}
public override string ToString() { return matchText; }
public virtual bool ShowComboButton(QueryElement queryElement) { return false; }
public virtual bool ShowTextBox(QueryElement queryElement) { return false; }
public virtual bool ShowNumericUpDown(QueryElement queryElement) { return false; }
public virtual String Units(QueryElement queryElement) { return String.Empty; }
public virtual Object[] ComboButtonEntries { get { return null; } }
public abstract QueryFilter GetQuery(QueryElement queryElement);
public abstract bool ForQuery(QueryFilter query);
public abstract void FromQuery(QueryFilter query, QueryElement queryElement);
}
internal class XMOListContains<T> : MatchType where T : XenObject<T>
{
private PropertyNames property;
private bool contains;
private Predicate<T> filter;
public XMOListContains(PropertyNames property, bool contains, String matchText,
Predicate<T> filter)
: base(matchText)
{
this.property = property;
this.contains = contains;
this.filter = filter;
}
public override bool ShowComboButton(QueryElement queryElement) { return true; }
public override object[] ComboButtonEntries
{
get
{
List<T> entries = new List<T>();
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
connection.Cache.AddAll(entries, filter);
return entries.ToArray();
}
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
T t = queryElement.ComboButton.SelectedItem.Tag as T;
if (t == null)
return null;
return new XenModelObjectListContainsQuery<T>(property, t, contains);
}
public override bool ForQuery(QueryFilter query)
{
XenModelObjectListContainsQuery<T> xmoQuery = query as XenModelObjectListContainsQuery<T>;
if (xmoQuery == null)
return false;
return xmoQuery.property == property && xmoQuery.contains == contains;
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
XenModelObjectListContainsQuery<T> xmoQuery = query as XenModelObjectListContainsQuery<T>;
queryElement.ComboButton.SelectItem<T>(delegate(T t)
{
return Helpers.GetUuid(t) == xmoQuery.queryUUID;
});
}
}
internal class IntMatch : MatchType
{
private readonly PropertyNames property;
private readonly IntPropertyQuery.PropertyQueryType type;
private readonly String units;
private readonly long multiplier;
public IntMatch(PropertyNames property, String matchText,
String units, long multiplier, IntPropertyQuery.PropertyQueryType type)
: base(matchText)
{
this.property = property;
this.type = type;
this.units = units;
this.multiplier = multiplier;
}
public override bool ShowNumericUpDown(QueryElement queryElement) { return true; }
public override string Units(QueryElement queryElement)
{
return units;
}
public override QueryFilter GetQuery(QueryElement queryElement)
{
long value = multiplier * (long)queryElement.numericUpDown.Value;
return new IntPropertyQuery(property, value, type);
}
public override bool ForQuery(QueryFilter query)
{
IntPropertyQuery intQuery = query as IntPropertyQuery;
if (intQuery == null)
return false;
return intQuery.property == property && intQuery.type == type;
}
public override void FromQuery(QueryFilter query, QueryElement queryElement)
{
IntPropertyQuery intQuery = query as IntPropertyQuery;
if (intQuery == null)
return;
queryElement.numericUpDown.Value = intQuery.query / multiplier;
}
}
// NOT USED FOR NEW QUERIES
internal class DiskQueryType : MatchQueryType
{
private readonly MatchType[] matchType = new MatchType[] {
new XMOListContains<SR>(PropertyNames.storage, true,
Messages.CONTAINED_IN, null),
new XMOListContains<SR>(PropertyNames.storage, false,
Messages.NOT_CONTAINED_IN, null),
new XMOListContains<VM>(PropertyNames.vm, true,
Messages.ATTACHED_TO, VmFilter),
new XMOListContains<VM>(PropertyNames.vm, false,
Messages.NOT_ATTACHED_TO, VmFilter),
new IntMatch(PropertyNames.size, Messages.SIZE_IS, Messages.VAL_GIGB,
Util.BINARY_GIGA, IntPropertyQuery.PropertyQueryType.exactmatch),
new IntMatch(PropertyNames.size, Messages.BIGGER_THAN, Messages.VAL_GIGB,
Util.BINARY_GIGA, IntPropertyQuery.PropertyQueryType.gt),
new IntMatch(PropertyNames.size, Messages.SMALLER_THAN, Messages.VAL_GIGB,
Util.BINARY_GIGA, IntPropertyQuery.PropertyQueryType.lt),
};
public DiskQueryType(int group, ObjectTypes appliesTo, String i18n)
: base(group, appliesTo, i18n)
{
}
protected override MatchType[] MatchTypes { get { return matchType; } }
private static bool VmFilter(VM vm)
{
return !(vm.is_a_template || vm.is_control_domain)
&& vm.VBDs.Count > 0;
}
}
internal class LongQueryType : MatchQueryType
{
private readonly MatchType[] matchType;
public LongQueryType(int group, ObjectTypes appliesTo, String i18n, PropertyNames property, long multiplier, String unit)
: base(group, appliesTo, i18n)
{
matchType = new MatchType[] {
new IntMatch(property, Messages.BIGGER_THAN, unit,
multiplier, IntPropertyQuery.PropertyQueryType.gt),
new IntMatch(property, Messages.SMALLER_THAN, unit,
multiplier, IntPropertyQuery.PropertyQueryType.lt),
new IntMatch(property, Messages.IS_EXACTLY, unit,
multiplier, IntPropertyQuery.PropertyQueryType.exactmatch),
};
}
protected override MatchType[] MatchTypes { get { return matchType; } }
}
#endregion
}
}