Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorLluis Sanchez <lluis@xamarin.com>2015-09-16 15:06:01 +0300
committerLluis Sanchez <lluis@xamarin.com>2015-09-16 15:06:01 +0300
commit1f97738a8eb87172f5cc7c715973aa6e2b040ea7 (patch)
treeebe6637b76e8dc38ba1c046ca9a86a99153c45a3 /main
parent1ccc412fd7f4e5ae6ce06e361b2484dd23e8bbe1 (diff)
parent918a1fcbadc8aa6aba8b33da3bf4e27a57e5cdcd (diff)
Merge remote-tracking branch 'origin/master' into roslyn
Diffstat (limited to 'main')
-rw-r--r--main/src/addins/MacPlatform/MainToolbar/StatusBar.cs15
-rw-r--r--main/src/addins/NUnit/Gui/TestResultsPad.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/SystemInformation.cs11
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml7
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/GtkWidgetResult.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest.Results/NSObjectResult.cs52
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs15
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestClientSession.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestService.cs296
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AutoTestSession.cs41
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/ToolsCommands.cs63
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs5
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);
}
}