diff options
Diffstat (limited to 'main')
14 files changed, 504 insertions, 32 deletions
diff --git a/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs b/main/src/addins/MacPlatform/MainToolbar/StatusBar.cs index 3c31cf0f67..ec24ce10ee 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 ? 6 : 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); @@ -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; } diff --git a/main/src/addins/NUnit/Gui/TestResultsPad.cs b/main/src/addins/NUnit/Gui/TestResultsPad.cs index 13e890eb79..928991d85d 100644 --- a/main/src/addins/NUnit/Gui/TestResultsPad.cs +++ b/main/src/addins/NUnit/Gui/TestResultsPad.cs @@ -214,7 +214,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); 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 () diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml index 1cb977999f..39286f0163 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml @@ -680,6 +680,13 @@ defaultHandler = "MonoDevelop.Ide.Commands.InstrumentationViewerHandler" _label = "Instrumentation Monitor" /> + <Command id = "MonoDevelop.Ide.Commands.ToolCommands.ToggleSessionRecorder" + defaultHandler = "MonoDevelop.Ide.Commands.ToggleSessionRecorderHandler" + _label = "Start Session Recorder" /> + + <Command id = "MonoDevelop.Ide.Commands.ToolCommands.ReplaySession" + defaultHandler = "MonoDevelop.Ide.Commands.ReplaySessionHandler" + _label = "Replay Session..." /> </Category> diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml index e2ee2ba102..dae3537320 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml @@ -228,6 +228,10 @@ <CommandItem id = "MonoDevelop.Ide.Commands.ToolCommands.ToolList" /> <CommandItem id = "MonoDevelop.Ide.Commands.ToolCommands.InstrumentationViewer" /> <CommandItem id = "MonoDevelop.Ide.Commands.EditCommands.InsertGuid" /> + <ItemSet id = "SessionRecorder" _label = "Session Recorder" autohide = "true"> + <CommandItem id = "MonoDevelop.Ide.Commands.ToolCommands.ToggleSessionRecorder" /> + <CommandItem id = "MonoDevelop.Ide.Commands.ToolCommands.ReplaySession" /> + </ItemSet> <SeparatorItem id = "OptionsSection" /> <Condition id="Platform" value="windows"> <CommandItem id = "MonoDevelop.Ide.Commands.EditCommands.MonodevelopPreferences" /> 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.Results/NSObjectResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs index 97496aa70d..8df790e36c 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<IConfigurationModel> model = (IEnumerable<IConfigurationModel>)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<IRuntimeModel> model = (IEnumerable<IRuntimeModel>)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<AppQuery, AppQuery> query, string configuration) + { + AppResult[] results = Query (query); + if (results.Length == 0) { + return false; + } + + return session.SetActiveConfiguration (results [0], configuration); + } + + public bool SetActiveRuntime (Func<AppQuery, AppQuery> 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/AutoTestService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs index 7c58a76780..64b48200c2 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,16 @@ 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; +using System.Text; namespace MonoDevelop.Components.AutoTest { @@ -41,6 +47,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 +76,35 @@ namespace MonoDevelop.Components.AutoTest File.WriteAllText (SessionReferenceFile, sref); } } - + + public static void ReplaySessionFromFile (string filename) + { + currentRecordSession = new SessionRecord (commandManager, filename); + currentRecordSession.ReplayEvents (() => { + currentRecordSession = null; + }); + } + 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,18 +180,104 @@ namespace MonoDevelop.Components.AutoTest { CommandManager commandManager; List<RecordEvent> events = new List<RecordEvent> (); - bool recording; - - public class RecordEvent + enum State { + Idle, + Recording, + Replaying + }; + State state; + + StringBuilder pendingText; + Gdk.ModifierType pendingModifiers = Gdk.ModifierType.None; + + 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 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; } @@ -165,6 +285,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 +315,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<RecordEvent> 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; @@ -219,9 +379,117 @@ 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) + { + 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 (); + } else if (evType == "StringEvent") { + ev = new StringEvent (); + } + + if (ev == null) { + return false; + } + + ev.ParseXML (element); + events.Add (ev); + } + + return true; + } + + public void ReplayEvents (Action completionHandler = null) + { + 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; + + if (completionHandler != null) { + completionHandler (); + } + + 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..6b7677e180 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,6 @@ namespace MonoDevelop.Components.AutoTest } catch (TimeoutException e) { throw new TimeoutException (string.Format ("Timeout while executing ExecuteQuery: {0}", query), e); } - return resultSet; } @@ -530,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); 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 f9c997c48e..7d56a51e3b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -425,7 +425,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 }); } /// <summary> @@ -2601,6 +2601,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; } } 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 fed013ddb5..99f634ff99 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs @@ -25,11 +25,11 @@ // // - +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; @@ -39,7 +39,9 @@ namespace MonoDevelop.Ide.Commands { AddinManager, ToolList, - InstrumentationViewer + InstrumentationViewer, + ToggleSessionRecorder, + ReplaySession, } internal class AddinManagerHandler : CommandHandler @@ -138,4 +140,59 @@ 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 { + 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 (); + } + } + } + + protected override void Update (CommandInfo info) + { + info.Visible = IdeApp.Preferences.EnableAutomatedTesting; + 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); + } + + protected override void Update (CommandInfo info) + { + info.Visible = IdeApp.Preferences.EnableAutomatedTesting; + } + } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs index 3679ab697b..5351157c33 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs @@ -351,7 +351,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); } } |