/*******************************************************************************
* 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 com.windowtester.runtime.swt.internal.widgets.MenuItemReference;
import com.windowtester.runtime.swt.internal.widgets.SWTWidgetReference;
/**
* A operation that waits for a menu to appear. This class provides support for making a
* menu visible via mouse operations, where as subclasses such as
* {@link SWTShowViewMenuOperation} provide programmatic menu visibility where it is
* impractical to open a menu using mouse clicks.
*/
public class SWTShowMenuOperation extends SWTMenuOperation
{
private int waitForIdleCount = 0;
/**
* Construct a new instance for showing a cascading menu
*/
public SWTShowMenuOperation(MenuItemReference menuItemReference) {
super(menuItemReference);
}
/**
* Queue a step that waits for a particular menu item to become enabled. Typically,
* this is called *before* calling {@link #click(int, SWTLocation, boolean)}
*
* @return this operation so that calls can be cascaded on a single line such as
*
* <code>new SWTShowMenuOperation().waitForEnabled(...).openMenu(...).execute();</code>
*/
public SWTShowMenuOperation waitForEnabled(SWTWidgetReference<?> widgetRef) {
return (SWTShowMenuOperation) super.waitForEnabled(widgetRef);
}
/**
* Queue a step that waits for the display to finish processing events. Typically,
* this is called *before* calling {@link #click(int, SWTLocation, boolean)}
*
* @return this operation so that calls can be cascaded on a single line such as
* <code>new SWTShowMenuOperation().waitForIdle().openMenu(...).execute();</code>
*/
public SWTShowMenuOperation waitForIdle() {
final String className = getClass().getSimpleName();
queueStep(new Step() {
public void executeInUI() throws Exception {
if (!displayRef.isIdle()) {
if (++waitForIdleCount > 0)
System.out.println(className + " waiting for idle " + waitForIdleCount);
throw new SWTOperationStepException("Waiting for idle");
}
}
});
return this;
}
/**
* Dismiss any menus that are currently open. This is typically called at the end of
* each test to ensure no unintended side-effects carry over into the next test.
*
* @return this operation so that calls can be cascaded on a single line such as
* <code>new SWTShowMenuOperation().closeAllMenus().execute();</code>
*/
public SWTShowMenuOperation closeAllMenus() {
queueStep(new Step() {
public void executeInUI() throws Exception {
int count = menuFilter.cancel();
if (count == 0)
return;
while (count > 0) {
//TODO: this may be OS-specific...
queueCharDown(SWT.ESC);
queueStep(null);
queueCharUp(SWT.ESC);
queueStep(null);
count--;
}
// Wait for the UI thread to finish processing the menu closures before continuing
waitForIdle();
}
});
return this;
}
/**
* Override superclass implementation to check that {@link #execute()} is being called
* from a non-UI thread because menu show requires an intricate dance between UI and
* non-UI threads.
*/
@Override
public void execute() {
if (Thread.currentThread() == displayRef.getDisplay().getThread())
throw new IllegalStateException("Operations must be called from a non-UI thread");
super.execute();
}
/**
* Called after an incorrect selection where the menus are no longer visible.
* Subclasses may override.
*
* @param message the exception message
*/
protected void retryAfterBadSelection(String message) {
// No possibility of recovery here, so exit and retry in MenuDriver
System.out.println(message);
throw new RuntimeException(message);
}
}