diff --git a/src/TestStack.White/Configuration/CoreAppXmlConfiguration.cs b/src/TestStack.White/Configuration/CoreAppXmlConfiguration.cs index d69d45d5..738b3d50 100644 --- a/src/TestStack.White/Configuration/CoreAppXmlConfiguration.cs +++ b/src/TestStack.White/Configuration/CoreAppXmlConfiguration.cs @@ -26,6 +26,7 @@ static CoreAppXmlConfiguration() DefaultValues.Add("PopupTimeout", 5000); DefaultValues.Add("TooltipWaitTime", 3000); DefaultValues.Add("SuggestionListTimeout", 3000); + DefaultValues.Add("HighlightTimeout", 1000); DefaultValues.Add("DefaultDateFormat", DateFormat.CultureDefault.ToString()); DefaultValues.Add("DragStepCount", 1); DefaultValues.Add("InProc", false); @@ -108,6 +109,12 @@ public virtual int SuggestionListTimeout set { SetUsedValue("SuggestionListTimeout", value); } } + public virtual int HighlightTimeout + { + get { return Convert.ToInt32(UsedValues["HighlightTimeout"]); } + set { SetUsedValue("HighlightTimeout", value); } + } + public virtual DateFormat DefaultDateFormat { get { return DateFormat.Parse(UsedValues["DefaultDateFormat"]); } diff --git a/src/TestStack.White/Configuration/CoreConfiguration.cs b/src/TestStack.White/Configuration/CoreConfiguration.cs index 17d99e11..0b29c2d1 100644 --- a/src/TestStack.White/Configuration/CoreConfiguration.cs +++ b/src/TestStack.White/Configuration/CoreConfiguration.cs @@ -23,6 +23,7 @@ public interface ICoreConfiguration int PopupTimeout { get; set; } int TooltipWaitTime { get; set; } int SuggestionListTimeout { get; set; } + int HighlightTimeout { get; set; } DateFormat DefaultDateFormat { get; set; } int DragStepCount { get; set; } bool InProc { get; set; } diff --git a/src/TestStack.White/Drawing/ScreenRectangle.cs b/src/TestStack.White/Drawing/ScreenRectangle.cs new file mode 100644 index 00000000..2e6d4e37 --- /dev/null +++ b/src/TestStack.White/Drawing/ScreenRectangle.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows; +using System.Windows.Forms; +using TestStack.White.Configuration; + +namespace TestStack.White.Drawing +{ + internal class ScreenRectangle + { + private Form form = new Form(); + //TODO: Think about making color configurable + private Color Color = Color.Red; + + internal ScreenRectangle(Rect rectangle) + { + form.FormBorderStyle = FormBorderStyle.None; + form.ShowInTaskbar = false; + form.TopMost = true; + form.Left = 0; + form.Top = 0; + form.Width = 1; + form.Height = 1; + form.BackColor = this.Color; + form.Opacity = 0.8; + form.Visible = false; + + //Set popup style + int num1 = TestStack.White.WindowsAPI.NativeWindow.GetWindowLong(form.Handle, -20); + TestStack.White.WindowsAPI.NativeWindow.SetWindowLong(form.Handle, -20, num1 | 0x80); + + //Set position + TestStack.White.WindowsAPI.NativeWindow.SetWindowPos(form.Handle, new IntPtr(-1), Convert.ToInt32(rectangle.X), Convert.ToInt32(rectangle.Y), + Convert.ToInt32(rectangle.Width), Convert.ToInt32(rectangle.Height), 0x10); + } + + internal virtual void Show() + { + TestStack.White.WindowsAPI.NativeWindow.ShowWindow(form.Handle, 8); + } + + internal virtual void Hide() + { + form.Hide(); + } + } + + internal class FrameRectangle + { + //Using 4 rectangles to display each border + private ScreenRectangle leftBorder; + private ScreenRectangle topBorder; + private ScreenRectangle rightBorder; + private ScreenRectangle bottomBorder; + + private ScreenRectangle[] rectangles; + private int width = 3; + + internal FrameRectangle(Rect boundingRectangle) + { + leftBorder = new ScreenRectangle(new Rect(boundingRectangle.X - width, boundingRectangle.Y - width, width, boundingRectangle.Height + 2*width)); + topBorder = new ScreenRectangle(new Rect(boundingRectangle.X, boundingRectangle.Y - width, boundingRectangle.Width, width)); + rightBorder = new ScreenRectangle(new Rect(boundingRectangle.X + boundingRectangle.Width, boundingRectangle.Y - width, width, boundingRectangle.Height + 2*width)); + bottomBorder = new ScreenRectangle(new Rect(boundingRectangle.X, boundingRectangle.Y + boundingRectangle.Height, boundingRectangle.Width, width)); + rectangles = new ScreenRectangle[] { leftBorder, topBorder, rightBorder, bottomBorder }; + } + + internal virtual void Highlight() + { + rectangles.ToList().ForEach(x => x.Show()); + Thread.Sleep(CoreAppXmlConfiguration.Instance.HighlightTimeout); + rectangles.ToList().ForEach(x => x.Hide()); + } + } +} diff --git a/src/TestStack.White/TestStack.White.csproj b/src/TestStack.White/TestStack.White.csproj index 1e47ec8f..8180c03b 100644 --- a/src/TestStack.White/TestStack.White.csproj +++ b/src/TestStack.White/TestStack.White.csproj @@ -94,6 +94,7 @@ + diff --git a/src/TestStack.White/UIItems/IUIItem.cs b/src/TestStack.White/UIItems/IUIItem.cs index 73b3edee..d1632e21 100644 --- a/src/TestStack.White/UIItems/IUIItem.cs +++ b/src/TestStack.White/UIItems/IUIItem.cs @@ -94,5 +94,7 @@ public interface IUIItem : ActionListener AutomationElement GetElement(SearchCriteria searchCriteria); void Enter(string value); + + void DrawHighlight(); } } \ No newline at end of file diff --git a/src/TestStack.White/UIItems/UIItem.cs b/src/TestStack.White/UIItems/UIItem.cs index 36efd431..5f589131 100644 --- a/src/TestStack.White/UIItems/UIItem.cs +++ b/src/TestStack.White/UIItems/UIItem.cs @@ -20,6 +20,7 @@ using TestStack.White.WindowsAPI; using Action = TestStack.White.UIItems.Actions.Action; using Point = System.Windows.Point; +using System.Windows.Forms; namespace TestStack.White.UIItems { @@ -424,5 +425,18 @@ public virtual void RaiseClickEvent() var invokePattern = (InvokePattern)Pattern(InvokePattern.Pattern); if (invokePattern != null) invokePattern.Invoke(); } + + /// + /// Highlight UIItem with red frame + /// + public virtual void DrawHighlight() + { + Rect rectangle = AutomationElement.Current.BoundingRectangle; + + if (rectangle != Rect.Empty) + { + new Drawing.FrameRectangle(rectangle).Highlight(); + } + } } } \ No newline at end of file diff --git a/src/TestStack.White/UIItems/WindowItems/Win32Window.cs b/src/TestStack.White/UIItems/WindowItems/Win32Window.cs index 406b2807..feb8d73a 100644 --- a/src/TestStack.White/UIItems/WindowItems/Win32Window.cs +++ b/src/TestStack.White/UIItems/WindowItems/Win32Window.cs @@ -1,5 +1,8 @@ +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Windows.Automation; +using TestStack.White.AutomationElementSearch; using TestStack.White.Factory; using TestStack.White.Sessions; using TestStack.White.UIItems.Finders; @@ -36,6 +39,16 @@ public override Window ModalWindow(string title, InitializeOption option) WindowSession.ModalWindowSession(option)); } + public override List ModalWindows() + { + var descendants = new AutomationElementFinder(automationElement) + .Children(new AutomationSearchConditionFactory().GetWindowSearchConditions(automationElement.Current.ProcessId).ToArray()); + + return descendants + .Select(descendant => ChildWindowFactory.Create(descendant, InitializeOption.NoCache, WindowSession.ModalWindowSession(InitializeOption.NoCache))) + .ToList(); + } + public override Window ModalWindow(SearchCriteria searchCriteria, InitializeOption option) { return windowFactory.ModalWindow(searchCriteria, option, WindowSession.ModalWindowSession(option)); diff --git a/src/TestStack.White/WindowsAPI/NativeWindow.cs b/src/TestStack.White/WindowsAPI/NativeWindow.cs index acf44b78..99900014 100644 --- a/src/TestStack.White/WindowsAPI/NativeWindow.cs +++ b/src/TestStack.White/WindowsAPI/NativeWindow.cs @@ -83,10 +83,24 @@ public virtual COLORREF TextColor return GetTextColor(GetDC(handle)); } } - + public virtual void PostCloseMessage() { PostMessage(handle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } + + //Native methods needed for highlighting UIItems + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hwndAfter, int x, int y, int width, int height, int flags); + [return: MarshalAs(UnmanagedType.Bool)] + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + internal static extern int GetWindowLong(IntPtr hWnd, int nIndex); } } \ No newline at end of file