xenadmin/XenAdmin/Controls/XenSearch/QueryElement.cs
Konstantina Chremmou fb8434819d Namespace tidy 3/several: replaced XenAdmin.Core (instances in XenCenterLib) with XenCenterLib.
Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
2017-11-30 13:56:32 +00:00

2566 lines
103 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;
using XenCenterLib;
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 UuidStringQueryType(1, ObjectTypes.AllExcFolders));
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 BooleanQueryType(3, ObjectTypes.VM, PropertyNames.read_caching_enabled));
queryTypes.Add(new BooleanQueryType(3, ObjectTypes.VM, PropertyNames.vendor_device_state));
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 BooleanQueryType(4, ObjectTypes.Pool, PropertyNames.isNotFullyUpgraded));
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()
{
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 Action QueryChanged;
protected virtual void OnQueryChanged()
{
try
{
if (QueryChanged != null)
QueryChanged();
}
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);
queryTypeComboButton.SelectedItemChanged += OnQueryTypeComboButton_OnSelectedItemChanged;
SelectDefaultQueryType();
Setup();
}
private void OnQueryTypeComboButton_OnSelectedItemChanged(object sender, EventArgs e)
{
var selectedItem = queryTypeComboButton.SelectedItem;
if (selectedItem.Tag is CustomFieldQueryTypeBase)
{
queryTypeComboButton.Text = selectedItem.ToString().Ellipsise(24);
}
}
/// <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);
}
}
public 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 -= subQueryElement_QueryChanged;
subQueryElement.QueryChanged += 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()
{
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;
}
}
// The object "Is" query, selected from a list of objects.
// Internally implemented using UUIDs.
internal class UuidQueryType : PropertyQueryType<String>
{
internal UuidQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo, PropertyNames.uuid, Messages.UUID_SEARCH)
{
}
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);
});
}
}
// Search for UUID as a string
internal class UuidStringQueryType: StringPropertyQueryType
{
internal UuidStringQueryType(int group, ObjectTypes appliesTo)
: base(group, appliesTo, PropertyNames.uuid)
{ }
public override object[] MatchTypeComboButtonEntries
{
get {
return new ExtraComboEntry[] {
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.startswith),
new ExtraComboEntry(StringPropertyQuery.PropertyQueryType.exactmatch)
};
}
}
}
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()
{
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
}
}