/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.runtime.swt.internal.operation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Widget;
import abbot.tester.swt.Robot;
import abbot.tester.swt.WidgetLocator;
import com.windowtester.internal.runtime.provisional.WTInternal;
import com.windowtester.runtime.internal.OS;
import com.windowtester.runtime.swt.condition.SWTIdleCondition;
import com.windowtester.runtime.swt.internal.widgets.SWTWidgetReference;
/**
* A (perhaps temporary) home for migrating <code>BasicWidgetSelector</code> click functionality.
*/
public class BasicSWTWidgetClickOperation<T extends SWTWidgetReference<?>> extends SWTWidgetClickOperation<T>{
protected Point pointT = new Point(0, 0);
public BasicSWTWidgetClickOperation(T widget) {
super(widget);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.internal.operation.SWTWidgetClickOperation#getLocation()
*/
@Override
protected SWTLocation getLocation() {
return new SWTWidgetLocation(getWidgetRef(), WTInternal.TOPLEFT).offset(getOffset());
}
@Override
public void execute() {
//this is an attempt to make more operation-like the click->click2 sequence (below)
// TODO[pq]: push this into a subclass (if it's deemed needed)
Widget w = getWidgetRef().getWidget();
if (w == null)
return;
super.execute();
if ((w != null) && (!w.isDisposed())) {
waitForIdle(getDisplay(w));
}
if (w instanceof MenuItem){
pauseCurrentThread(300);
if (OS.isOSX()) // Mac testing
wiggleMouse();
}
}
private void wiggleMouse() {
Point offset = getOffset();
wiggleMouseAt(getWidgetRef().getWidget(), offset.x, offset.y);
}
// public Widget click(final Widget w, final int x, final int y, final int mask, final int count) {
//
// if (w == null)
// return null;
//
//// boolean shift = (mask & SWT.SHIFT) ==SWT.SHIFT;
//// boolean ctrl = (mask & SWT.CTRL) == SWT.CTRL;
//// boolean check = (mask & SWT.CHECK) == SWT.CHECK;
//// boolean alt = (mask & SWT.ALT) == SWT.ALT; // Mac testing
//// boolean command = (mask & SWT.COMMAND) == SWT.COMMAND; // Mac testing
////
//// int type = SWT.MouseUp;
//// // If we're simulating a modifier key then our thread must be made to wait until
//// // click2() generates the key-up event. Note that this is extremely dependent
//// // on the implementation of click2().
//// if (ctrl||shift||check|alt|command) {
//// type = SWT.KeyUp;
//// }
//// Widget listenToWidget = w;
//// if(w instanceof ToolItem)
//// listenToWidget = UIProxy.getParent((ToolItem)w);
//// if(w instanceof CTabItem)
//// listenToWidget = UIProxy.getParent((CTabItem)w);
//// if(w instanceof TabItem)
//// listenToWidget = UIProxy.getParent((TabItem)w);
//// if(w instanceof TreeItem)
//// listenToWidget = UIProxy.getParent((TreeItem)w);
// if(w instanceof MenuItem){
// click2(w, x, y, mask, count);
// pauseCurrentThread(300);
// if (Platform.isOSX()) // Mac testing
// wiggleMouseAt(w, x, y);
// return w;
// }
//
//// new SystemEventMonitor(listenToWidget, type){
//// public void syncExecEvents() {
// click2(w, x, y, mask, count);
//// }
//// }.run();
//
// return w;
// }
//
// /**
// * Click in the given part of the component. All other click methods
// * must eventually invoke this one. Except the cases that call the old
// * click(int,int,int,int) method, which does not handle checks. (Unless
// * those are bugs waiting to be found, which is a possibility.)
// * TODO rewrite this to query everything it needs from the widget *before*
// * it starts posting mouse clicks. The widget can, in theory, be disposed
// * any time after the first click. (Then check the sender tree.)
// */
// protected Widget click2(final Widget w, final int x, final int y, int mask, int count) {
// // TODO[pq]: this mapping should be pushed up (the ref should be passed into this method)
// ISWTWidgetReference<?> ref = SWTWidgetReference.forWidget(w);
// new SWTMouseOperation(mask).at(new SWTWidgetLocation(ref, WTInternal.TOPLEFT).offset(x, y)).count(count).execute();
//
//// printTraceMessage(w, x, y);
////
//// boolean shift = (mask & SWT.SHIFT) == SWT.SHIFT;
//// boolean ctrl = (mask & SWT.CTRL) == SWT.CTRL;
//// boolean check = (mask & SWT.CHECK) == SWT.CHECK;
//// boolean alt = (mask & SWT.ALT) == SWT.ALT; // Mac testing
//// boolean command = (mask & SWT.COMMAND) == SWT.COMMAND; // Mac testing
////
//// if (shift)
//// trace("got shift!");
//// if (ctrl)
//// trace("got ctrl!");
//// if (check)
//// trace("got check!");
//// if (alt)
//// trace("got alt!");
//// if (command)
//// trace("got command!");
////
//// // FIXME handle other modifiers
//// mask &= (SWT.BUTTON1
//// |SWT.BUTTON2
//// |SWT.BUTTON3);
////
//// if (shift)
//// _dispatcher.keyDown(SWT.SHIFT);
//// if (ctrl)
//// _dispatcher.keyDown(SWT.CTRL);
//// if (alt)
//// _dispatcher.keyDown(SWT.ALT);
//// if (command)
//// _dispatcher.keyDown(SWT.COMMAND);
////
////
//// if(!Platform.isLinux() ){
//// mousePress(w, x, y, mask);
//// }else{
//// mouseMove(w, x, y);
//// new abbot.swt.Robot().mousePress(mask);
//// }
//// // [author=Dan] No pause on Linux between mouse down and mouse up
//// // because some controls such as CTabFolder may receive the mouse down
//// // and call OS.lock, thus preventing us from ever posting the mouse up
//// // until the user wiggles the mouse.
//// if (!Platform.isLinux()) { // menu item check doesn't work
//// pauseCurrentThread(getClickDelay());
//// }
//// if (Platform.isOSX() || (Platform.isLinux()&& w instanceof MenuItem)) { // Mac testing
//// wiggleMouseAt(w, x, y);
//// }
////
//// while (count-- > 1) {
//// if(!Platform.isLinux() ){
//// _dispatcher.mouseUp(mask);
//// }else{
//// new abbot.swt.Robot().mousePress(mask);
//// }
//// pauseCurrentThread(DEFAULT_DELAY);
//// if(!Platform.isLinux() ){
//// _dispatcher.mouseDown(mask);
//// }else{
//// new abbot.swt.Robot().mouseRelease(mask);
//// }
//// if (!Platform.isLinux())
//// pauseCurrentThread(getClickDelay());
//// if (Platform.isOSX()) // Mac testing
//// wiggleMouseAt(w, x, y);
//// }
//// if( !Platform.isLinux()){
//// _dispatcher.mouseUp(mask);
//// }else{
//// new abbot.swt.Robot().mouseRelease(mask);
//// }
////
//// /**
//// * Handle checks here
//// */
//// if (check) {
//// pauseCurrentThread(100);
//// setChecked(w);
//// }
////
//// if (shift)
//// _dispatcher.keyUp(SWT.SHIFT);
//// if (ctrl)
//// _dispatcher.keyUp(SWT.CTRL);
//// if (alt)
//// _dispatcher.keyUp(SWT.ALT);
//// if (command)
//// _dispatcher.keyUp(SWT.COMMAND);
//
// if ((w != null) && (!w.isDisposed())) {
// waitForIdle(getDisplay(w));
// }
//
// return w;
// }
//guard to catch widget disposal timing issue
private Display getDisplay(Widget w) {
try {
return w.getDisplay();
} catch (SWTException e) {
return Display.getDefault();
}
}
protected /*synchronized*/ void waitForIdle(final Display display){
/*
* Slow integ of new waitForIdle fixes
* To start, only for GTK (to guard against win32 regressions)
*/
if (SWT.getPlatform().equals("gtk") || OS.isOSX()) {
new SWTIdleCondition(display).waitForIdle();
} else {
/*
* The OLD way to wait (found not safe in Linux)
*/
// display.syncExec(new Runnable() {
// public void run() {
// while(display.readAndDispatch());
// }
// });
//provisional fix for 29881: Dialogs Opened During Window Tester Widget Selector Actions Cause Hangs
new SWTIdleCondition(display).waitForIdle();
}
}
private void wiggleMouseAt(Widget widget, int x, int y) {
try {
mouseMove(widget, x+1, y+1);
pauseCurrentThread(50);
mouseMove(widget, x, y);
} catch (SWTException ex) {
// ignore disposed widget problems
}
}
protected void pauseCurrentThread(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
}
public synchronized void mouseMove(final Widget w, int x, int y) {
pointT = null;
Robot.syncExec(w.getDisplay(), this, new Runnable() {
public void run() {
pointT = WidgetLocator.getLocation(w);
}
});
if (pointT == null) // TODO added for Mac testing
return;
mouseMove(pointT.x + x, pointT.y + y);
}
public void mouseMove(int x, int y) {
Event event = new Event();
event.type = SWT.MouseMove;
event.x = x;
event.y = y;
new SWTPushEventOperation(event).execute();
}
}