/* Copyright (c) Cloud Software Group, Inc. * * 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.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using XenAdmin.Actions; using XenAdmin.Dialogs; using XenAPI; namespace XenAdmin.Commands { /// /// An interface used to hide the SetSelection and SetMainWindow methods on the class. /// These methods are used only by the Command framework and are potentially confusing if seen by Command consumers. /// internal interface ICommand { void SetSelection(IEnumerable selection); void SetMainWindow(IMainWindow mainWindow); } /// /// A class which represents a user's task in XenCenter. Classes derived from can be easily /// assigned to menu items and toolbar buttons. /// [TypeConverter(typeof(CommandConverter))] internal abstract class Command : ICommand { private SelectedItemCollection _selection = new SelectedItemCollection(); private IMainWindow _mainWindow; private Control _parent; /// /// Initializes a new instance of this Command. The parameter-less constructor is required in the derived /// class if it is to be attached to a ToolStrip menu item or button. It should not be used in any other scenario. /// protected Command() { } /// /// Initializes a new instance of the class. /// /// The application main window. protected Command(IMainWindow mainWindow) { Util.ThrowIfParameterNull(mainWindow, "mainWindow"); _mainWindow = mainWindow; } /// /// Initializes a new instance of the class. /// /// The application main window. /// The selection context for the Command. protected Command(IMainWindow mainWindow, IEnumerable selection) : this(mainWindow) { Util.ThrowIfParameterNull(selection, "selection"); _selection = new SelectedItemCollection(selection); } /// /// Initializes a new instance of the class. /// /// The application main window. /// The selection context for the Command. protected Command(IMainWindow mainWindow, SelectedItem selection) : this(mainWindow, new[] { selection }) { } /// /// Initializes a new instance of the class. /// /// The application main window. /// The selection context for the Command. protected Command(IMainWindow mainWindow, IXenObject xenObject) : this(mainWindow, new SelectedItem(xenObject)) { } /// /// Gets the current selection context for the Command. /// public SelectedItemCollection GetSelection() { return _selection; } /// /// Determines whether this instance can run with the current selection context. /// /// /// true if this instance can run; otherwise, false. /// public bool CanRun() { return MainWindowCommandInterface != null && CanRunCore(GetSelection()); } /// /// Determines whether this instance can run with the current selection context. /// /// The selection context. /// /// true if this instance can run with the specified selection; otherwise, false. /// protected virtual bool CanRunCore(SelectedItemCollection selection) { return true; } /// /// Runs this Command on the current selection. /// public void Run() { if (Confirm()) { var cantRunReasons = GetCantRunReasons(); var errorDialog = cantRunReasons.Count > 0 ? GetErrorDialogCore(cantRunReasons) : null; RunCore(GetSelection()); if (errorDialog != null) { errorDialog.ShowDialog(Parent); } } } /// /// Runs this Command. /// /// The selection the Command should operate on. protected virtual void RunCore(SelectedItemCollection selection) { } /// /// Gets the text for a menu item which launches this Command. /// public virtual string MenuText => null; /// /// Gets the text for a context menu item which launches this Command. /// public virtual string ContextMenuText => null; /// /// Gets the image for a menu item which launches this Command. /// public virtual Image MenuImage => null; /// /// Gets the image for a context menu item which launches this Command. /// public virtual Image ContextMenuImage => null; /// /// Gets the text for the toolbar button which launches this Command. /// public virtual string ToolBarText => null; /// /// Gets the image for a toolbar button which launches this Command. /// public virtual Image ToolBarImage => null; /// /// Gets the text for a button which launches this Command. /// public virtual string ButtonText => null; /// /// Gets the tool tip text when running is not possible. This is the /// can't run reason for single selection, and null otherwise. /// public virtual string DisabledToolTipText { get { var selection = GetSelection(); if (selection.Count == 1) { var item = selection[0]; if (item?.XenObject == null) return null; string reason = GetCantRunReasonCore(item.XenObject); return reason == Messages.UNKNOWN ? null : reason; } return null; } } /// /// Gets the tool tip text when the command is able to run. Null by default. /// public virtual string EnabledToolTipText => null; /// /// Gets the shortcut key display string. This is only used if this Command is used on the main menu. /// public virtual string ShortcutKeyDisplayString => null; /// /// Gets the shortcut keys. This is only used if this Command is used on the main menu. /// public virtual Keys ShortcutKeys => Keys.None; /// /// Gets a value indicating whether a confirmation dialog should be shown. /// protected virtual bool ConfirmationRequired => false; /// /// Gets the confirmation dialog title. The default for this is Messages.MESSAGEBOX_CONFIRM. /// protected virtual string ConfirmationDialogTitle => null; /// /// Gets the confirmation dialog text. /// protected virtual string ConfirmationDialogText => null; /// /// Gets the help id for the confirmation dialog. /// protected virtual string ConfirmationDialogHelpId => null; protected virtual string ConfirmationDialogYesButtonLabel => null; protected virtual string ConfirmationDialogNoButtonLabel => null; protected virtual bool ConfirmationDialogNoButtonSelected => false; /// /// Shows a confirmation dialog. /// /// True if the user clicked Yes. private bool ShowConfirmationDialog() { if (Program.RunInAutomatedTestMode) return true; var buttonYes = new ThreeButtonDialog.TBDButton( string.IsNullOrEmpty(ConfirmationDialogYesButtonLabel) ? Messages.YES_BUTTON_CAPTION : ConfirmationDialogYesButtonLabel, DialogResult.Yes); var buttonNo = new ThreeButtonDialog.TBDButton( string.IsNullOrEmpty(ConfirmationDialogNoButtonLabel) ? Messages.NO_BUTTON_CAPTION : ConfirmationDialogNoButtonLabel, DialogResult.No, selected: ConfirmationDialogNoButtonSelected); using (var dialog = new WarningDialog(ConfirmationDialogText, buttonYes, buttonNo) { WindowTitle = ConfirmationDialogTitle }) { if (!string.IsNullOrEmpty(ConfirmationDialogHelpId)) dialog.HelpNameSetter = ConfirmationDialogHelpId; return dialog.ShowDialog(Parent ?? Program.MainWindow) == DialogResult.Yes; } } /// /// Shows a confirmation dialog if required. /// /// True if the operation should proceed. protected virtual bool Confirm() { return !ConfirmationRequired || ShowConfirmationDialog(); } /// /// Gets all of the reasons that items in the selection can't run. /// /// A dictionary of reasons keyed by the item name. public Dictionary GetCantRunReasons() { var cantRunReasons = new Dictionary(); foreach (SelectedItem item in GetSelection()) { if (item == null || item.XenObject == null) continue; if (MainWindowCommandInterface != null && CanRunCore(new SelectedItemCollection(item))) continue; string reason = GetCantRunReasonCore(item.XenObject); if (reason != null) cantRunReasons.Add(item.XenObject, reason); } return cantRunReasons; } /// /// Gets the reason that the specified item from the selection can't run. This is displayed in the error dialog. /// The default is "Unknown". /// protected virtual string GetCantRunReasonCore(IXenObject item) { return Messages.UNKNOWN; } /// /// Gets the error dialog to be displayed if one or more items in the selection couldn't be run. Returns null by /// default i.e. An error dialog isn't displayed by default. /// /// The reasons for why the items couldn't run. protected virtual CommandErrorDialog GetErrorDialogCore(IDictionary cantRunReasons) { return null; } /// /// Gets the main window to be used by the Command. /// public IMainWindow MainWindowCommandInterface => _mainWindow; /// /// Gets or sets the parent control for any dialogs launched during the /// running of the command. Defaults to the MainWindow Form. /// public Control Parent { get => _parent ?? _mainWindow?.Form; set => _parent = value; } /// /// Runs the specified s such that they are synchronous per connection but asynchronous across connections. /// /// /// Whether the actions should be run simultaneously /// /// /// public void RunMultipleActions(IEnumerable actions, string title, string startDescription, string endDescription, bool runActionsInParallel) { MultipleActionLauncher launcher = new MultipleActionLauncher(actions, title, startDescription, endDescription, runActionsInParallel); launcher.Run(); } #region ICommand Members /// /// Sets the selection context for the Command. This is hidden as it is only for use by the Command framework. /// void ICommand.SetSelection(IEnumerable selection) { Util.ThrowIfParameterNull(selection, "selection"); _selection = new SelectedItemCollection(selection); } /// /// Sets the main window for the Command. This is hidden as it is only for use by the Command framework. /// /// The main window. void ICommand.SetMainWindow(IMainWindow mainWindow) { Util.ThrowIfParameterNull(mainWindow, "mainWindow"); _mainWindow = mainWindow; } #endregion } }