diff options
author | Vsevolod Kukol <sevoku@xamarin.com> | 2016-07-08 12:47:12 +0300 |
---|---|---|
committer | Vsevolod Kukol <sevoku@xamarin.com> | 2016-07-08 17:07:29 +0300 |
commit | 0d4aa037f5c9dda81183328a51a56a323a086ab1 (patch) | |
tree | 17d5a48b54dc7ef75f7ec7926cd2391cf66e6f7c /main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools | |
parent | 66d0294724ca11a7958a8addfde530314b5031af (diff) |
[Ide] Register ActionCommands for custom tools
Add custom tools to the global command system,
which allows to assign key bindings to custom tools
and makes them visible in the global search and
key bindings option panel.
(fixes bug #9222)
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools')
3 files changed, 220 insertions, 9 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalTool.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalTool.cs index 3481572852..448318f114 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalTool.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalTool.cs @@ -28,9 +28,11 @@ using System; using System.Diagnostics; +using System.Threading.Tasks; using System.Xml; - +using MonoDevelop.Components.Commands; using MonoDevelop.Core; +using MonoDevelop.Core.Execution; namespace MonoDevelop.Ide.ExternalTools { @@ -40,6 +42,7 @@ namespace MonoDevelop.Ide.ExternalTools string command; string arguments; string initialDirectory; + string accelKey; bool promptForArguments; bool useOutputPad = true; bool saveCurrentFile; @@ -80,6 +83,15 @@ namespace MonoDevelop.Ide.ExternalTools } } + public string AccelKey { + get { + return accelKey; + } + set { + accelKey = value; + } + } + public bool PromptForArguments { get { return promptForArguments; @@ -111,6 +123,62 @@ namespace MonoDevelop.Ide.ExternalTools { this.menuCommand = GettextCatalog.GetString ("New Tool"); } + + internal void Run () + { + string argumentsTool = StringParserService.Parse (Arguments, IdeApp.Workbench.GetStringTagModel ()); + + //Save current file checkbox + if (SaveCurrentFile && IdeApp.Workbench.ActiveDocument != null) + IdeApp.Workbench.ActiveDocument.Save (); + + if (PromptForArguments) { + string customerArguments = MessageService.GetTextResponse (GettextCatalog.GetString ("Enter any arguments you want to use while launching tool, {0}:", MenuCommand), GettextCatalog.GetString ("Command Arguments for {0}", MenuCommand), ""); + if (customerArguments != String.Empty) + argumentsTool = StringParserService.Parse (customerArguments, IdeApp.Workbench.GetStringTagModel ()); + } + + Task.Run (delegate { + RunExternalTool (this, argumentsTool); + }); + } + + static void RunExternalTool (ExternalTools.ExternalTool tool, string argumentsTool) + { + string commandTool = StringParserService.Parse (tool.Command, IdeApp.Workbench.GetStringTagModel ()); + string initialDirectoryTool = StringParserService.Parse (tool.InitialDirectory, IdeApp.Workbench.GetStringTagModel ()); + + //Execute tool + ProgressMonitor progressMonitor = IdeApp.Workbench.ProgressMonitors.GetRunProgressMonitor (); + try { + progressMonitor.Log.WriteLine (GettextCatalog.GetString ("Running: {0} {1}", (commandTool), (argumentsTool))); + progressMonitor.Log.WriteLine (); + + ProcessWrapper processWrapper; + if (tool.UseOutputPad) + processWrapper = Runtime.ProcessService.StartProcess (commandTool, argumentsTool, initialDirectoryTool, progressMonitor.Log, progressMonitor.Log, null); + else + processWrapper = Runtime.ProcessService.StartProcess (commandTool, argumentsTool, initialDirectoryTool, null); + + string processName = System.IO.Path.GetFileName (commandTool); + try { + processName = processWrapper.ProcessName; + } catch (SystemException) { + } + + processWrapper.WaitForOutput (); + + if (processWrapper.ExitCode == 0) { + progressMonitor.Log.WriteLine (GettextCatalog.GetString ("Process '{0}' has completed succesfully", processName)); + } else { + progressMonitor.Log.WriteLine (GettextCatalog.GetString ("Process '{0}' has exited with error code {1}", processName, processWrapper.ExitCode)); + } + } catch (Exception ex) { + progressMonitor.ReportError (GettextCatalog.GetString ("External program execution failed.\nError while starting:\n '{0} {1}'", commandTool, argumentsTool), ex); + } finally { + progressMonitor.Dispose (); + } + } #region I/O public const string Node = "ExternalTool"; @@ -119,6 +187,7 @@ namespace MonoDevelop.Ide.ExternalTools const string commandAttribute = "command"; const string argumentsAttribute = "arguments"; const string initialDirectoryAttribute = "initialDirectory"; + const string accelKeyAttribute = "accelKey"; const string promptForArgumentsAttribute = "promptForArguments"; const string useOutputPadAttribute = "useOutputPad"; const string saveCurrentFileAttribute = "saveCurrentFile"; @@ -130,6 +199,7 @@ namespace MonoDevelop.Ide.ExternalTools writer.WriteAttributeString (commandAttribute, this.command); writer.WriteAttributeString (argumentsAttribute, this.arguments); writer.WriteAttributeString (initialDirectoryAttribute, this.initialDirectory); + writer.WriteAttributeString (accelKeyAttribute, this.accelKey); writer.WriteAttributeString (promptForArgumentsAttribute, this.promptForArguments.ToString ()); writer.WriteAttributeString (useOutputPadAttribute, this.useOutputPad.ToString ()); writer.WriteAttributeString (saveCurrentFileAttribute, this.saveCurrentFile.ToString ()); @@ -145,7 +215,7 @@ namespace MonoDevelop.Ide.ExternalTools result.command = reader.GetAttribute (commandAttribute); result.arguments = reader.GetAttribute (argumentsAttribute); result.initialDirectory = reader.GetAttribute (initialDirectoryAttribute); - result.menuCommand = reader.GetAttribute (menuCommandAttribute); + result.accelKey = reader.GetAttribute (accelKeyAttribute); if (!String.IsNullOrEmpty (reader.GetAttribute (promptForArgumentsAttribute))) result.promptForArguments = Boolean.Parse (reader.GetAttribute (promptForArgumentsAttribute)); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolPanel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolPanel.cs index 2cbaa2c321..c53ad191ea 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolPanel.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolPanel.cs @@ -35,6 +35,8 @@ using MonoDevelop.Components; using MonoDevelop.Ide.ExternalTools; using MonoDevelop.Core; using MonoDevelop.Ide.Gui.Dialogs; +using MonoDevelop.Components.Commands; +using System.Linq; #pragma warning disable 612 @@ -72,6 +74,9 @@ namespace MonoDevelop.Ide.ExternalTools int toolListBoxItemCount = 0; bool lockStoreValues = false; + EventBoxTooltip keyBindingInfoTooltip; + string defaultKeyBindingTooltipText; + public ExternalToolPanelWidget () { Build (); @@ -80,9 +85,10 @@ namespace MonoDevelop.Ide.ExternalTools dependendControls = new Widget[] { titleTextBox, argumentTextBox, - workingDirTextBox, promptArgsCheckBox, useOutputPadCheckBox, - titleLabel, argumentLabel, commandLabel, - workingDirLabel, browseButton, + workingDirTextBox, promptArgsCheckBox, useOutputPadCheckBox, + titleLabel, argumentLabel, commandLabel, defaultKeyLabel, + defaultKeyTextBox, keyBindingInfoEventBox, + workingDirLabel, browseButton, moveUpButton, moveDownButton, saveCurrentFileCheckBox, tagSelectorArgs, tagSelectorPath @@ -107,6 +113,10 @@ namespace MonoDevelop.Ide.ExternalTools tagSelectorPath.TagModel = IdeApp.Workbench.GetStringTagModelDescription (); tagSelectorPath.TargetEntry = workingDirTextBox; + keyBindingInfoTooltip = new EventBoxTooltip (keyBindingInfoEventBox) { + Severity = Tasks.TaskSeverity.Warning + }; + toolListBox.Selection.Changed += SelectionChanged; removeButton.Clicked += RemoveButtonClicked; addButton.Clicked += AddButtonClicked; @@ -120,7 +130,10 @@ namespace MonoDevelop.Ide.ExternalTools promptArgsCheckBox.Toggled += StoreValuesInSelectedTool; useOutputPadCheckBox.Toggled += StoreValuesInSelectedTool; saveCurrentFileCheckBox.Toggled += StoreValuesInSelectedTool; - + + defaultKeyTextBox.KeyPressEvent += OnDefaultKeyEntryKeyPress; + defaultKeyTextBox.KeyReleaseEvent += OnDefaultKeyEntryKeyRelease; + SelectionChanged (this, EventArgs.Empty); } @@ -154,6 +167,101 @@ namespace MonoDevelop.Ide.ExternalTools ((ListStore)ls).Swap (selectedItem, toSwap); } } + + bool accelIncomplete = false; + bool accelComplete = false; + string chord; + + string currentKey; + string CurrentKey { + get { + return currentKey ?? string.Empty; + } + set { + currentKey = value; + defaultKeyTextBox.Text = value == null ? "" : KeyBindingManager.BindingToDisplayLabel (value, false, true); + + var cmdConflicts = new HashSet<string> (); + KeyBinding binding = null; + if (KeyBinding.TryParse (currentKey, out binding)) { + foreach (var cmd in IdeApp.CommandService.GetCommands (binding).Where (c => !((string)c.Id).StartsWith ("MonoDevelop.CustomCommands.Command", StringComparison.Ordinal))) { + cmdConflicts.Add (cmd.Category + " \u2013 " + cmd.DisplayName); + } + } + + TreeIter iter; + if (toolListBoxStore.GetIterFirst (out iter)) { + do { + if (!iter.Equals (SelectedIter)) { + var tool = toolListBoxStore.GetValue (iter, 1) as ExternalTool; + if (tool?.AccelKey == value) + cmdConflicts.Add ("Tools \u2013 " + tool.MenuCommand); + } + } while (toolListBoxStore.IterNext (ref iter)); + } + + if (cmdConflicts.Count > 0) { + keyBindingInfoEventBox.Visible = true; + keyBindingInfoTooltip.Severity = Tasks.TaskSeverity.Warning; + var text = GettextCatalog.GetPluralString ( + "This shortcut is assigned to another command:", + "This shortcut is assigned to other commands:", + cmdConflicts.Count) + "\n"; + foreach (var cmd in cmdConflicts) + text += "\n\u2022 " + cmd; + keyBindingInfoTooltip.ToolTip = text; + } else { + keyBindingInfoEventBox.Visible = false; + } + + if (lockStoreValues) + return; + ExternalTool selectedItem = SelectedTool; + if (selectedItem != null) + selectedItem.AccelKey = CurrentKey; + } + } + + [GLib.ConnectBefore] + void OnDefaultKeyEntryKeyPress (object sender, KeyPressEventArgs e) + { + Gdk.Key key = e.Event.Key; + string accel; + + e.RetVal = true; + + if (accelComplete) { + CurrentKey = String.Empty; + accelIncomplete = false; + accelComplete = false; + chord = null; + + if (key.Equals (Gdk.Key.BackSpace)) + return; + } + + accelComplete = false; + bool combinationComplete; + accel = KeyBindingManager.AccelLabelFromKey (e.Event, out combinationComplete); + if (combinationComplete) { + CurrentKey = KeyBindingManager.Binding (chord, accel); + accelIncomplete = false; + if (chord != null) + accelComplete = true; + else + chord = accel; + } else { + accel = (chord != null ? chord + "|" : string.Empty) + accel; + accelIncomplete = true; + CurrentKey = accel; + } + } + + void OnDefaultKeyEntryKeyRelease (object sender, KeyReleaseEventArgs e) + { + if (accelIncomplete) + CurrentKey = chord != null ? chord : string.Empty; + } void StoreValuesInSelectedTool (object sender, EventArgs e) { @@ -206,13 +314,16 @@ namespace MonoDevelop.Ide.ExternalTools browseButton.Path = externalTool.Command ?? ""; argumentTextBox.Text = externalTool.Arguments ?? ""; workingDirTextBox.Text = externalTool.InitialDirectory ?? ""; + CurrentKey = externalTool.AccelKey; promptArgsCheckBox.Active = externalTool.PromptForArguments ; useOutputPadCheckBox.Active = externalTool.UseOutputPad; saveCurrentFileCheckBox.Active = externalTool.SaveCurrentFile; } else { - titleTextBox.Text = browseButton.Path = argumentTextBox.Text = workingDirTextBox.Text = ""; + titleTextBox.Text = browseButton.Path = argumentTextBox.Text = workingDirTextBox.Text = CurrentKey = ""; promptArgsCheckBox.Active = useOutputPadCheckBox.Active = saveCurrentFileCheckBox.Active = false; } + accelIncomplete = false; + accelComplete = true; } finally { lockStoreValues = false; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolService.cs index aa55bad407..3a1c2bbf25 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.ExternalTools/ExternalToolService.cs @@ -33,6 +33,8 @@ using System.Collections.Generic; using System.Xml; using MonoDevelop.Core; +using MonoDevelop.Components.Commands; +using MonoDevelop.Ide.Commands; namespace MonoDevelop.Ide.ExternalTools { @@ -48,17 +50,45 @@ namespace MonoDevelop.Ide.ExternalTools return tools; } set { + UnregisterCommands (); tools = value; + RegisterCommands (); + } + } + + static void UnregisterCommands () + { + if (tools == null) + return; + for (int i = 0; i < tools.Count; i++) { + var cmd = IdeApp.CommandService.GetActionCommand ("MonoDevelop.CustomCommands.Command" + i); + if (cmd != null) + IdeApp.CommandService.UnregisterCommand (cmd); + } + } + + static void RegisterCommands () + { + if (tools == null) + return; + for (int i = 0; i < tools.Count; i++) { + var tool = tools [i]; + ActionCommand cmd = new ActionCommand ("MonoDevelop.CustomCommands.Command" + i, tool.MenuCommand, null); + cmd.DefaultHandler = new RunCustomToolHandler (tool); + cmd.Category = GettextCatalog.GetString ("Tools (Custom)"); + cmd.Description = GettextCatalog.GetString ("Start tool") + " " + string.Join (string.Empty, tool.MenuCommand.Split ('&')); + cmd.AccelKey = tool.AccelKey; + IdeApp.CommandService.RegisterCommand (cmd); } } static ExternalToolService () { try { - tools = LoadTools (); + Tools = LoadTools (); } catch (Exception e) { LoggingService.LogError ("ExternalToolService: Exception while loading tools.", e); - tools = new List<ExternalTool> (); + Tools = new List<ExternalTool> (); } } |