From 858cab854dafadde193b5c32ab497d2ece1f8390 Mon Sep 17 00:00:00 2001 From: iain holmes Date: Thu, 21 May 2015 16:48:53 +0100 Subject: [IDE] Add menu item to start/stop the session recorder --- .../ExtensionModel/Commands.addin.xml | 3 +++ .../ExtensionModel/MainMenu.addin.xml | 1 + .../MonoDevelop.Ide.Commands/ToolsCommands.cs | 23 ++++++++++++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml index 1ae62d65bf..e9358b83e5 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml @@ -683,6 +683,9 @@ defaultHandler = "MonoDevelop.Ide.Commands.InstrumentationViewerHandler" _label = "Instrumentation Monitor" /> + diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml index e3a7cc997a..6c5fc40b5e 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml @@ -222,6 +222,7 @@ + diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs index 797e266a66..ca243e079a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs @@ -25,7 +25,7 @@ // // - +using MonoDevelop.Components.AutoTest; using MonoDevelop.Components.Commands; using MonoDevelop.Core; using MonoDevelop.Core.Execution; @@ -39,7 +39,8 @@ namespace MonoDevelop.Ide.Commands { AddinManager, ToolList, - InstrumentationViewer + InstrumentationViewer, + ToggleSessionRecorder, } internal class AddinManagerHandler : CommandHandler @@ -138,4 +139,22 @@ namespace MonoDevelop.Ide.Commands info.Visible = MonoDevelop.Core.Instrumentation.InstrumentationService.Enabled; } } + + internal class ToggleSessionRecorderHandler : CommandHandler + { + protected override void Run () + { + if (AutoTestService.CurrentRecordSession == null) { + AutoTestService.StartRecordingSession (); + } else { + // FIXME: Throw up a dialog for filename + AutoTestService.StopRecordingSession ("/Users/iain/XS-session.xml"); + } + } + + protected override void Update (CommandInfo info) + { + info.Text = AutoTestService.CurrentRecordSession == null ? "Start Session Recorder" : "Stop Session Recorder"; + } + } } -- cgit v1.2.3 From a2907db9d2a90fa921fc0058ee74af56ca21f3dd Mon Sep 17 00:00:00 2001 From: iain holmes Date: Thu, 21 May 2015 16:34:07 +0100 Subject: [AutoTest] Implement Session Recording Track all the keypresses and commands, then write them as XML to a filek --- .../ExtensionModel/Commands.addin.xml | 4 + .../ExtensionModel/MainMenu.addin.xml | 5 +- .../GtkWidgetResult.cs | 2 +- .../AutoTestService.cs | 202 +++++++++++++++++++-- .../AutoTestSession.cs | 18 +- .../MonoDevelop.Ide.Commands/ToolsCommands.cs | 38 +++- 6 files changed, 251 insertions(+), 18 deletions(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml index e9358b83e5..0feccde288 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml @@ -686,6 +686,10 @@ + + diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml index 6c5fc40b5e..888161e4bc 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml @@ -222,7 +222,10 @@ - + + + + diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/GtkWidgetResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/GtkWidgetResult.cs index 9f08c97267..27eaf3af8c 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/GtkWidgetResult.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/GtkWidgetResult.cs @@ -296,7 +296,7 @@ namespace MonoDevelop.Components.AutoTest.Results } } - void RealTypeKey (Gdk.Key key, Gdk.ModifierType state) + internal void RealTypeKey (Gdk.Key key, Gdk.ModifierType state) { SendKeyEvent (resultWidget, (uint)key, state, Gdk.EventType.KeyPress, null); SendKeyEvent (resultWidget, (uint)key, state, Gdk.EventType.KeyRelease, null); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs index 7c58a76780..d459fb3e47 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs @@ -26,10 +26,15 @@ using System; using MonoDevelop.Components.Commands; +using MonoDevelop.Core; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Remoting; +using System.Diagnostics; using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; namespace MonoDevelop.Components.AutoTest { @@ -41,6 +46,11 @@ namespace MonoDevelop.Components.AutoTest get { return manager.currentSession; } } + static SessionRecord currentRecordSession; + public static SessionRecord CurrentRecordSession { + get { return currentRecordSession; } + } + public static void Start (CommandManager commandManager, bool publishServer) { AutoTestService.commandManager = commandManager; @@ -65,12 +75,33 @@ namespace MonoDevelop.Components.AutoTest File.WriteAllText (SessionReferenceFile, sref); } } - + + public static void ReplaySessionFromFile (string filename) + { + currentRecordSession = new SessionRecord (commandManager, filename); + currentRecordSession.ReplayEvents (); + } + public static SessionRecord StartRecordingSession () { - return new SessionRecord (commandManager); + currentRecordSession = new SessionRecord (commandManager); + return currentRecordSession; } - + + public static void StopRecordingSession (string filename = null) + { + if (currentRecordSession == null) { + return; + } + + currentRecordSession.Pause (); + + if (filename != null) { + currentRecordSession.WriteLogToFile (filename); + } + currentRecordSession = null; + } + internal static string SessionReferenceFile { get { return Path.Combine (Path.GetTempPath (), "monodevelop-autotest-objref"); @@ -146,16 +177,59 @@ namespace MonoDevelop.Components.AutoTest { CommandManager commandManager; List events = new List (); - bool recording; + enum State { + Idle, + Recording, + Replaying + }; + State state; - public class RecordEvent + public abstract class RecordEvent { + public abstract XElement ToXML (); + public abstract void ParseXML (XElement element); + public abstract void Replay (AutoTestSession testSession); } public class KeyPressEvent: RecordEvent { public Gdk.Key Key { get; set; } public Gdk.ModifierType Modifiers { get; set; } + + public override XElement ToXML () + { + return new XElement ("event", new XAttribute ("type", "KeyPressEvent"), + new XElement ("key", Key.ToString ()), + new XElement ("modifier", Modifiers.ToString ())); + } + + public override void ParseXML (XElement element) + { + foreach (var e in element.Elements ()) { + if (e.Name == "key") { + Key = (Gdk.Key)Enum.Parse (typeof (Gdk.Key), e.Value); + } else if (e.Name == "modifier") { + Modifiers = (Gdk.ModifierType)Enum.Parse (typeof (Gdk.ModifierType), e.Value); + } + } + } + + public override void Replay (AutoTestSession testSession) + { + // Select the main window and then we can push key events to it. + AppQuery query = testSession.CreateNewQuery (); + AppResult[] results = query.Window ().Marked ("MonoDevelop.Ide.Gui.DefaultWorkbench").Execute (); + if (results.Length == 0) { + return; + } + + testSession.Select (results[0]); + // We need the GtkWidgetResult for the main window as we only have the keys as a Gdk key + if (results [0] is AutoTest.Results.GtkWidgetResult) { + AutoTest.Results.GtkWidgetResult widgetResult = (AutoTest.Results.GtkWidgetResult) results[0]; + widgetResult.RealTypeKey (Key, Modifiers); + } + } } public class CommandEvent: RecordEvent @@ -165,6 +239,29 @@ namespace MonoDevelop.Components.AutoTest public bool IsCommandArray { get { return DataItemIndex != -1; } } + + public override XElement ToXML () + { + return new XElement ("event", new XAttribute ("type", "CommandEvent"), + new XElement ("commandID", CommandId.ToString ()), + new XElement ("dataItemIndex", DataItemIndex)); + } + + public override void ParseXML (XElement element) + { + foreach (var e in element.Elements ()) { + if (e.Name == "commandID") { + CommandId = e.Value; + } else if (e.Name == "dataItemIndex") { + DataItemIndex = Convert.ToInt32 (e.Value); + } + } + } + + public override void Replay (AutoTestSession testSession) + { + testSession.ExecuteCommand (CommandId); + } } internal SessionRecord (CommandManager commandManager) @@ -172,39 +269,56 @@ namespace MonoDevelop.Components.AutoTest this.commandManager = commandManager; Resume (); } + + internal SessionRecord (CommandManager commandManager, string logFile) + { + state = State.Idle; + this.commandManager = commandManager; + LoadFromLogFile (logFile); + } public IEnumerable Events { get { - if (recording) + if (state == State.Recording) throw new InvalidOperationException ("The record session must be paused before getting the recorded events."); return events; } } public bool IsPaused { - get { return !recording; } + get { return state == State.Idle; } + } + + public bool IsReplaying { + get { return state == State.Replaying; } } public void Pause () { - if (recording) { + if (state == State.Recording) { commandManager.KeyPressed -= HandleCommandManagerKeyPressed; commandManager.CommandActivated -= HandleCommandManagerCommandActivated; - recording = false; + state = State.Idle; } } public void Resume () { - if (!recording) { + if (state == State.Idle) { commandManager.KeyPressed += HandleCommandManagerKeyPressed; commandManager.CommandActivated += HandleCommandManagerCommandActivated; - recording = true; + state = State.Recording; + LoggingService.LogError ("Starting up session recording"); } } void HandleCommandManagerCommandActivated (object sender, CommandActivationEventArgs e) { + if ((string)e.CommandId == "MonoDevelop.Ide.Commands.ToolCommands.ToggleSessionRecorder" || + (string)e.CommandId == "MonoDevelop.Ide.Commands.ToolCommands.ReplaySession") { + return; + } + CommandEvent cme = new CommandEvent () { CommandId = e.CommandId }; cme.DataItemIndex = -1; @@ -223,5 +337,71 @@ namespace MonoDevelop.Components.AutoTest { events.Add (new KeyPressEvent () { Key = e.Key, Modifiers = e.Modifiers }); } + + public void WriteLogToFile (string filepath) + { + var doc = new XDocument (new XElement ("xs-event-replay-log", + from ev in events + select ev.ToXML ())); + + using (XmlWriter xw = XmlWriter.Create (filepath, new XmlWriterSettings { Indent = true })) { + doc.Save (xw); + } + } + + public bool LoadFromLogFile (string filepath) + { + XDocument doc = XDocument.Load (filepath); + foreach (XElement element in doc.Element("xs-event-replay-log").Elements ()) { + if (element == null) { + continue; + } + + string evType = element.Attribute ("type").Value; + RecordEvent ev = null; + if (evType == "KeyPressEvent") { + ev = new KeyPressEvent (); + } else if (evType == "CommandEvent") { + ev = new CommandEvent (); + } + + if (ev == null) { + return false; + } + + ev.ParseXML (element); + events.Add (ev); + } + + return true; + } + + public void ReplayEvents () + { + AutoTestSession testSession = new AutoTestSession (); + Stopwatch sw = new Stopwatch (); + int eventCount = events.Count; + + state = State.Replaying; + + sw.Start (); + // Each spin of the main loop, remove an event from the queue and replay it. + GLib.Idle.Add (() => { + RecordEvent ev = events[0]; + events.RemoveAt (0); + + ev.Replay (testSession); + + if (events.Count > 0) { + return true; + } + + sw.Stop (); + LoggingService.LogInfo ("Time elapsed to replay {0} events: {1}", eventCount, sw.Elapsed); + state = State.Idle; + + return false; + }); + } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs index 2d35b53b90..9c65d934a8 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs @@ -302,14 +302,20 @@ namespace MonoDevelop.Components.AutoTest public void ExecuteOnIdle (Action idleFunc, bool wait = true, int timeout = 20000) { + if (DispatchService.IsGuiThread) { + idleFunc (); + return; + } + if (wait == false) { GLib.Idle.Add (() => { idleFunc (); return false; }); + return; } - + syncEvent.Reset (); GLib.Idle.Add (() => { idleFunc (); @@ -324,7 +330,7 @@ namespace MonoDevelop.Components.AutoTest // Executes the query outside of a syncEvent wait so it is safe to call from // inside an ExecuteOnIdleAndWait - AppResult[] ExecuteQueryNoWait (AppQuery query) + internal AppResult[] ExecuteQueryNoWait (AppQuery query) { AppResult[] resultSet = query.Execute (); Sync (() => { @@ -346,7 +352,15 @@ namespace MonoDevelop.Components.AutoTest } catch (TimeoutException e) { throw new TimeoutException (string.Format ("Timeout while executing ExecuteQuery: {0}", query), e); } +/* + if (DispatchService.IsGuiThread) { + return ExecuteQueryNoWait (query); + } + ExecuteOnIdleAndWait (() => { + resultSet = ExecuteQueryNoWait (query); + }); +*/ return resultSet; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs index ca243e079a..3c26e912a1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs @@ -29,7 +29,7 @@ using MonoDevelop.Components.AutoTest; using MonoDevelop.Components.Commands; using MonoDevelop.Core; using MonoDevelop.Core.Execution; -using MonoDevelop.Ide.Gui; +using MonoDevelop.Ide.Gui.Dialogs; using System; using MonoDevelop.Ide.Updater; @@ -41,6 +41,7 @@ namespace MonoDevelop.Ide.Commands ToolList, InstrumentationViewer, ToggleSessionRecorder, + ReplaySession, } internal class AddinManagerHandler : CommandHandler @@ -147,8 +148,18 @@ namespace MonoDevelop.Ide.Commands if (AutoTestService.CurrentRecordSession == null) { AutoTestService.StartRecordingSession (); } else { - // FIXME: Throw up a dialog for filename - AutoTestService.StopRecordingSession ("/Users/iain/XS-session.xml"); + var selector = new FileSelectorDialog ("Save session as...", Gtk.FileChooserAction.Save); + try { + var result = MessageService.RunCustomDialog (selector, MessageService.RootWindow); + + if (result == (int)Gtk.ResponseType.Cancel) { + return; + } + + AutoTestService.StopRecordingSession (selector.Filename); + } finally { + selector.Destroy (); + } } } @@ -157,4 +168,25 @@ namespace MonoDevelop.Ide.Commands info.Text = AutoTestService.CurrentRecordSession == null ? "Start Session Recorder" : "Stop Session Recorder"; } } + + internal class ReplaySessionHandler : CommandHandler + { + protected override void Run () + { + var selector = new FileSelectorDialog ("Open session"); + string filename = null; + try { + var result = MessageService.RunCustomDialog (selector, MessageService.RootWindow); + + if (result == (int)Gtk.ResponseType.Cancel) { + return; + } + + filename = selector.Filename; + } finally { + selector.Destroy (); + } + AutoTestService.ReplaySessionFromFile (filename); + } + } } -- cgit v1.2.3 From dac707aec3fcc06e1c5e72abff01a3ece5db9479 Mon Sep 17 00:00:00 2001 From: iain holmes Date: Wed, 10 Jun 2015 15:42:00 +0100 Subject: [Session Recording] Hide the session recorder when the automated testing is turned off --- main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml | 2 +- .../core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml index 888161e4bc..478f8dddc0 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml @@ -222,7 +222,7 @@ - + diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs index 3c26e912a1..109d363505 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs @@ -165,6 +165,7 @@ namespace MonoDevelop.Ide.Commands protected override void Update (CommandInfo info) { + info.Visible = IdeApp.Preferences.EnableAutomatedTesting; info.Text = AutoTestService.CurrentRecordSession == null ? "Start Session Recorder" : "Stop Session Recorder"; } } @@ -188,5 +189,10 @@ namespace MonoDevelop.Ide.Commands } AutoTestService.ReplaySessionFromFile (filename); } + + protected override void Update (CommandInfo info) + { + info.Visible = IdeApp.Preferences.EnableAutomatedTesting; + } } } -- cgit v1.2.3 From cdceb25670e85b35a54757967fcc9d5a1fd2a116 Mon Sep 17 00:00:00 2001 From: iain holmes Date: Thu, 18 Jun 2015 17:19:38 +0100 Subject: [Session Recording] Reset the session once it is completed --- .../MonoDevelop.Components.AutoTest/AutoTestService.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs index d459fb3e47..94c38d7adb 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs @@ -79,7 +79,9 @@ namespace MonoDevelop.Components.AutoTest public static void ReplaySessionFromFile (string filename) { currentRecordSession = new SessionRecord (commandManager, filename); - currentRecordSession.ReplayEvents (); + currentRecordSession.ReplayEvents (() => { + currentRecordSession = null; + }); } public static SessionRecord StartRecordingSession () @@ -376,7 +378,7 @@ namespace MonoDevelop.Components.AutoTest return true; } - public void ReplayEvents () + public void ReplayEvents (Action completionHandler = null) { AutoTestSession testSession = new AutoTestSession (); Stopwatch sw = new Stopwatch (); @@ -400,6 +402,10 @@ namespace MonoDevelop.Components.AutoTest LoggingService.LogInfo ("Time elapsed to replay {0} events: {1}", eventCount, sw.Elapsed); state = State.Idle; + if (completionHandler != null) { + completionHandler (); + } + return false; }); } -- cgit v1.2.3 From f3d3af8d833369490cd26d2fbaa377f0c98ba3c1 Mon Sep 17 00:00:00 2001 From: iain holmes Date: Tue, 23 Jun 2015 10:57:36 +0100 Subject: [Session Recording] Compress keystrokes into single String events If the keypress is a printable character, then add it to a pending string event and only commit the string event when the modifier changes or the key press isn't printable --- .../AutoTestService.cs | 88 +++++++++++++++++++++- .../AutoTestSession.cs | 9 --- .../CommandManager.cs | 3 +- 3 files changed, 87 insertions(+), 13 deletions(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs index 94c38d7adb..64b48200c2 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs @@ -35,6 +35,7 @@ using System.Collections.Generic; using System.Linq; using System.Xml; using System.Xml.Linq; +using System.Text; namespace MonoDevelop.Components.AutoTest { @@ -185,7 +186,10 @@ namespace MonoDevelop.Components.AutoTest Replaying }; State state; - + + StringBuilder pendingText; + Gdk.ModifierType pendingModifiers = Gdk.ModifierType.None; + public abstract class RecordEvent { public abstract XElement ToXML (); @@ -233,7 +237,47 @@ namespace MonoDevelop.Components.AutoTest } } } - + + public class StringEvent: RecordEvent + { + internal string Text; + internal Gdk.ModifierType Modifiers { get; set; } + + public override XElement ToXML () + { + return new XElement ("event", new XAttribute ("type", "StringEvent"), + new XElement ("text", Text), + new XElement ("modifier", Modifiers.ToString ())); + } + + public override void ParseXML (XElement element) + { + foreach (var e in element.Elements ()) { + if (e.Name == "text") { + Text = e.Value; + } else if (e.Name == "modifier") { + Modifiers = (Gdk.ModifierType)Enum.Parse (typeof(Gdk.ModifierType), e.Value); + } + } + } + + public override void Replay (AutoTestSession testSession) + { + AppQuery query = testSession.CreateNewQuery (); + AppResult[] results = query.Window ().Marked ("MonoDevelop.Ide.Gui.DefaultWorkbench").Execute (); + if (results.Length == 0) { + return; + } + + testSession.Select (results [0]); + + if (results [0] is AutoTest.Results.GtkWidgetResult) { + AutoTest.Results.GtkWidgetResult widgetResult = (AutoTest.Results.GtkWidgetResult)results [0]; + widgetResult.EnterText (Text); + } + } + } + public class CommandEvent: RecordEvent { public object CommandId { get; set; } @@ -335,9 +379,45 @@ namespace MonoDevelop.Components.AutoTest events.Add (cme); } + void CompleteStringEvent (string s, Gdk.ModifierType modifiers) + { + events.Add (new StringEvent { Text = pendingText.ToString (), Modifiers = pendingModifiers }); + pendingText = null; + pendingModifiers = Gdk.ModifierType.None; + } + void HandleCommandManagerKeyPressed (object sender, KeyPressArgs e) { - events.Add (new KeyPressEvent () { Key = e.Key, Modifiers = e.Modifiers }); + uint unicode = Gdk.Keyval.ToUnicode (e.KeyValue); + if (pendingText != null) { + if (pendingModifiers != e.Modifiers || unicode == 0) { + CompleteStringEvent (pendingText.ToString (), pendingModifiers); + } else { + pendingText.Append ((char)unicode); + return; + } + + // If text event has been completed, then we need to reset the pending events + if (unicode != 0) { + pendingText = new StringBuilder (); + pendingText.Append ((char)unicode); + pendingModifiers = e.Modifiers; + } else { + // Don't have a unicode key, so just issue a standard key event + events.Add (new KeyPressEvent { Key = e.Key, Modifiers = e.Modifiers }); + pendingText = null; + pendingModifiers = Gdk.ModifierType.None; + } + } else { + if (unicode == 0) { + events.Add (new KeyPressEvent () { Key = e.Key, Modifiers = e.Modifiers }); + return; + } + + pendingText = new StringBuilder (); + pendingText.Append ((char)unicode); + pendingModifiers = e.Modifiers; + } } public void WriteLogToFile (string filepath) @@ -365,6 +445,8 @@ namespace MonoDevelop.Components.AutoTest ev = new KeyPressEvent (); } else if (evType == "CommandEvent") { ev = new CommandEvent (); + } else if (evType == "StringEvent") { + ev = new StringEvent (); } if (ev == null) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs index 9c65d934a8..d94f39e2ba 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs @@ -352,15 +352,6 @@ namespace MonoDevelop.Components.AutoTest } catch (TimeoutException e) { throw new TimeoutException (string.Format ("Timeout while executing ExecuteQuery: {0}", query), e); } -/* - if (DispatchService.IsGuiThread) { - return ExecuteQueryNoWait (query); - } - - ExecuteOnIdleAndWait (() => { - resultSet = ExecuteQueryNoWait (query); - }); -*/ return resultSet; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 205ac7ecfc..24ac85fc96 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -426,7 +426,7 @@ namespace MonoDevelop.Components.Commands void NotifyKeyPressed (Gdk.EventKey ev) { if (KeyPressed != null) - KeyPressed (this, new KeyPressArgs () { Key = ev.Key, Modifiers = ev.State }); + KeyPressed (this, new KeyPressArgs () { Key = ev.Key, KeyValue = ev.KeyValue, Modifiers = ev.State }); } /// @@ -2602,6 +2602,7 @@ namespace MonoDevelop.Components.Commands public class KeyPressArgs: EventArgs { public Gdk.Key Key { get; internal set; } + public uint KeyValue { get; internal set; } public Gdk.ModifierType Modifiers { get; internal set; } } -- cgit v1.2.3 From 7d9d6ab6cc2577634669ee1df6aa6a25536edb06 Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Tue, 15 Sep 2015 18:47:05 +0300 Subject: [Mac] Moved mac progress bar 2px up on El Capitan Bug 33966 - XS: Toolbar progress bar is misaligned on El Capitan --- main/src/addins/MacPlatform/MainToolbar/StatusBar.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs index 560acb802c..f2e5d046f1 100644 --- a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs +++ b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs @@ -561,6 +561,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar } static CGColor xamBlue = new CGColor (52f / 255, 152f / 255, 219f / 255); + static nfloat verticalOffset = MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 2 : 0; CALayer CreateProgressBarLayer (double width) { CALayer progress = ProgressLayer; @@ -570,7 +571,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar progress.BackgroundColor = xamBlue; progress.BorderColor = xamBlue; progress.FillMode = CAFillMode.Forwards; - progress.Frame = new CGRect (0, Frame.Height - barHeight, (nfloat)width, barHeight); + progress.Frame = new CGRect (0, Frame.Height - barHeight - verticalOffset, (nfloat)width, barHeight); } return progress; } -- cgit v1.2.3 From 67a546342ef60ff547f87ef72ad7337a761b82cb Mon Sep 17 00:00:00 2001 From: iain holmes Date: Wed, 9 Sep 2015 17:50:09 +0100 Subject: [AutoTest] Add code to set the active runtime and configuration in SelectorView --- .../NSObjectResult.cs | 52 ++++++++++++++++++++++ .../MonoDevelop.Components.AutoTest/AppResult.cs | 15 ++++++- .../AutoTestClientSession.cs | 20 +++++++++ .../AutoTestSession.cs | 30 +++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs index b9fa5d5b05..e12c8ab3ed 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs @@ -26,12 +26,15 @@ #if MAC using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Xml; using AppKit; using Foundation; +using MonoDevelop.Components.MainToolbar; + namespace MonoDevelop.Components.AutoTest.Results { public class NSObjectResult : AppResult @@ -240,6 +243,55 @@ namespace MonoDevelop.Components.AutoTest.Results { } + +#region MacPlatform.MacIntegration.MainToolbar.SelectorView + public override bool SetActiveConfiguration (string configurationName) + { + Type type = ResultObject.GetType (); + PropertyInfo pinfo = type.GetProperty ("ConfigurationModel"); + if (pinfo == null) { + return false; + } + + IEnumerable model = (IEnumerable)pinfo.GetValue (ResultObject, null); + var configuration = model.FirstOrDefault (c => c.DisplayString == configurationName); + if (configuration == null) { + return false; + } + + pinfo = type.GetProperty ("ActiveConfiguration"); + if (pinfo == null) { + return false; + } + + pinfo.SetValue (ResultObject, configuration); + return true; + } + + public override bool SetActiveRuntime (string runtimeName) + { + Type type = ResultObject.GetType (); + PropertyInfo pinfo = type.GetProperty ("RuntimeModel"); + if (pinfo == null) { + return false; + } + + IEnumerable model = (IEnumerable)pinfo.GetValue (ResultObject, null); + + var runtime = model.FirstOrDefault (r => r.GetMutableModel ().FullDisplayString == runtimeName); + if (runtime == null) { + return false; + } + + pinfo = type.GetProperty ("ActiveRuntime"); + if (pinfo == null) { + return false; + } + + pinfo.SetValue (ResultObject, runtime); + return true; + } +#endregion } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs index 925b3eead2..20a71e2df5 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs @@ -63,9 +63,22 @@ namespace MonoDevelop.Components.AutoTest public abstract bool TypeKey (string keyString, string state = ""); public abstract bool EnterText (string text); public abstract bool Toggle (bool active); - public abstract void Flash (); + // More specific actions for complicated widgets + + #region For MacPlatform.MacIntegration.MainToolbar.SelectorView + public virtual bool SetActiveConfiguration (string configurationName) + { + return false; + } + + public virtual bool SetActiveRuntime (string runtimeName) + { + return false; + } + #endregion + // Inspection Operations public abstract ObjectProperties Properties (); public abstract string GetResultType (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestClientSession.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestClientSession.cs index 589565869e..085c1cba86 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestClientSession.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestClientSession.cs @@ -354,6 +354,26 @@ namespace MonoDevelop.Components.AutoTest } } + public bool SetActiveConfiguration (Func query, string configuration) + { + AppResult[] results = Query (query); + if (results.Length == 0) { + return false; + } + + return session.SetActiveConfiguration (results [0], configuration); + } + + public bool SetActiveRuntime (Func query, string runtime) + { + AppResult[] results = Query (query); + if (results.Length == 0) { + return false; + } + + return session.SetActiveRuntime (results [0], runtime); + } + public void RunAndWaitForTimer (Action action, string counterName, int timeout = 20000) { AutoTestSession.TimerCounterContext context = session.CreateNewTimerContext (counterName); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs index d94f39e2ba..6b7677e180 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs @@ -535,6 +535,36 @@ namespace MonoDevelop.Components.AutoTest } } + public bool SetActiveConfiguration (AppResult result, string configuration) + { + bool success = false; + + try { + ExecuteOnIdle (() => { + success = result.SetActiveConfiguration (configuration); + }); + } catch (TimeoutException e) { + ThrowOperationTimeoutException ("SetActiveConfiguration", result.SourceQuery, result, e); + } + + return success; + } + + public bool SetActiveRuntime (AppResult result, string runtime) + { + bool success = false; + + try { + ExecuteOnIdle (() => { + success = result.SetActiveRuntime (runtime); + }); + } catch (TimeoutException e) { + ThrowOperationTimeoutException ("SetActiveRuntime", result.SourceQuery, result, e); + } + + return success; + } + void ThrowOperationTimeoutException (string operation, string query, AppResult result, Exception innerException) { throw new TimeoutException (string.Format ("Timeout while executing {0}: {1}\n\ton Element: {2}", operation, query, result), innerException); -- cgit v1.2.3 From 19eba3efa4dc39ff8a11bb967a4302fe69e975ae Mon Sep 17 00:00:00 2001 From: Vaclav Vancura Date: Tue, 15 Sep 2015 21:07:06 +0200 Subject: [Mac] Toolbar: status are alignment fixes for El Capitan --- main/src/addins/MacPlatform/MainToolbar/StatusBar.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'main') diff --git a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs index f2e5d046f1..b51e837d96 100644 --- a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs +++ b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs @@ -154,7 +154,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar BezelStyle = NSTextFieldBezelStyle.Rounded; WantsLayer = true; - Layer.CornerRadius = 4; + Layer.CornerRadius = MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 8 : 4; ctxHandler = new StatusBarContextHandler (this); updateHandler = delegate { @@ -298,12 +298,12 @@ namespace MonoDevelop.MacIntegration.MainToolbar right -= 9; if (layer != null) { - layer.Frame = new CGRect (right, 3, 1, 16); + layer.Frame = new CGRect (right, MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 4 : 3, 1, 16); layer.SetNeedsDisplay (); } else { layer = CALayer.Create (); layer.Name = SeparatorLayerId; - layer.Frame = new CGRect (right, 3, 1, 16); + layer.Frame = new CGRect (right, MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 4 : 3, 1, 16); layer.BackgroundColor = NSColor.LightGray.CGColor; Layer.AddSublayer (layer); } @@ -341,12 +341,12 @@ namespace MonoDevelop.MacIntegration.MainToolbar nfloat right = DrawSeparatorIfNeeded (LeftMostStatusItemX ()); CGSize size = buildResultText.AttributedString.Size; right = right - 6 - size.Width; - buildResultText.Frame = new CGRect (right, 5f, size.Width, size.Height); + buildResultText.Frame = new CGRect (right, MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 6 : 5, size.Width, size.Height); if (buildResultText.SuperLayer == null) Layer.AddSublayer (buildResultText); buildResultText.SetNeedsDisplay (); right -= buildResultIcon.Bounds.Width; - buildResultIcon.Frame = new CGRect (right, 3, buildResultIcon.Bounds.Width, buildResultIcon.Bounds.Height); + buildResultIcon.Frame = new CGRect (right, MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 4 : 3, buildResultIcon.Bounds.Width, buildResultIcon.Bounds.Height); if (buildResultIcon.SuperLayer == null) Layer.AddSublayer (buildResultIcon); @@ -364,7 +364,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar RemoveTrackingArea (icon.TrackingArea); right -= item.Bounds.Width + 6; - item.Frame = new CGRect (right, 3, item.Bounds.Width, item.Bounds.Height); + item.Frame = new CGRect (right, MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 4 : 3, item.Bounds.Width, item.Bounds.Height); var area = new NSTrackingArea (item.Frame, NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInKeyWindow, this, null); AddTrackingArea (area); -- cgit v1.2.3 From 364e0f74943ba821e64955d43271966f49aa589f Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Tue, 15 Sep 2015 19:16:03 +0300 Subject: [Ide] Add user installed addins into the about dialog --- .../MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs index 69e83d4d0b..bbf4868d2e 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs @@ -120,6 +120,17 @@ namespace MonoDevelop.Core Title = "Operating System", Description = sb.ToString () }; + + string userAddins = string.Join (Environment.NewLine, + AddinManager.Registry.GetModules (AddinSearchFlags.IncludeAddins | AddinSearchFlags.LatestVersionsOnly) + .Where (addin => addin.IsUserAddin && addin.Enabled) + .Select (addin => string.Format ("{0} {1}", addin.Name, addin.Version)) + ); + if (!string.IsNullOrEmpty (userAddins)) + yield return new SystemInformationSection () { + Title = "Enabled user installed addins", + Description = userAddins, + }; } internal static string GetReleaseId () -- cgit v1.2.3 From 194dd7b6453b49ce9cda4909947b4986aabbc9f1 Mon Sep 17 00:00:00 2001 From: Vaclav Vancura Date: Tue, 15 Sep 2015 21:12:40 +0200 Subject: [Mac] Toolbar: Small progress bar fix for non-retina Macs --- main/src/addins/MacPlatform/MainToolbar/StatusBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs index b51e837d96..077be842ea 100644 --- a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs +++ b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs @@ -154,7 +154,7 @@ namespace MonoDevelop.MacIntegration.MainToolbar BezelStyle = NSTextFieldBezelStyle.Rounded; WantsLayer = true; - Layer.CornerRadius = MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 8 : 4; + Layer.CornerRadius = MacSystemInformation.OsVersion >= MacSystemInformation.ElCapitan ? 6 : 4; ctxHandler = new StatusBarContextHandler (this); updateHandler = delegate { -- cgit v1.2.3 From 9e88a98d9ec56d6827ca9e759f410c4a15c6de1a Mon Sep 17 00:00:00 2001 From: Vaclav Vancura Date: Mon, 14 Sep 2015 15:46:23 +0200 Subject: [Ide] Startup: logging .gtkrc used --- main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs index e4bbdeb869..2c90d8394f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs @@ -356,7 +356,10 @@ namespace MonoDevelop.Ide gtkrc += "-yosemite"; } } - Environment.SetEnvironmentVariable ("GTK2_RC_FILES", PropertyService.EntryAssemblyPath.Combine (gtkrc)); + + var gtkrcf = PropertyService.EntryAssemblyPath.Combine (gtkrc); + LoggingService.LogInfo ("GTK: Using gtkrc from {0}", gtkrcf); + Environment.SetEnvironmentVariable ("GTK2_RC_FILES", gtkrcf); } } -- cgit v1.2.3 From 918a1fcbadc8aa6aba8b33da3bf4e27a57e5cdcd Mon Sep 17 00:00:00 2001 From: Lluis Sanchez Date: Wed, 16 Sep 2015 14:03:45 +0200 Subject: Fix image loading error --- main/src/addins/NUnit/Gui/TestResultsPad.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main') diff --git a/main/src/addins/NUnit/Gui/TestResultsPad.cs b/main/src/addins/NUnit/Gui/TestResultsPad.cs index 84a529f426..dbd2f6fffd 100644 --- a/main/src/addins/NUnit/Gui/TestResultsPad.cs +++ b/main/src/addins/NUnit/Gui/TestResultsPad.cs @@ -213,7 +213,7 @@ namespace MonoDevelop.NUnit buttonRun = new Button (); buttonRun.Label = GettextCatalog.GetString ("Rerun Tests"); - buttonRun.Image = new Gtk.Image (Gtk.Stock.Execute, IconSize.Menu); + buttonRun.Image = new ImageView (ImageService.GetIcon ("nunit-run", IconSize.Menu)); buttonRun.Image.Show (); buttonRun.Sensitive = false; toolbar.Add (buttonRun); -- cgit v1.2.3