/*******************************************************************************
* Copyright (c) 2012 BREDEX GmbH.
* 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:
* BREDEX GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.jubula.rc.swt.tester;
import org.apache.commons.lang.Validate;
import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer;
import org.eclipse.jubula.rc.common.driver.IRunnable;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.tester.AbstractMenuTester;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IMenuComponent;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IMenuItemComponent;
import org.eclipse.jubula.rc.common.util.MenuUtilBase;
import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl;
import org.eclipse.jubula.rc.swt.driver.RobotSwtImpl;
import org.eclipse.jubula.rc.swt.tester.adapter.MenuItemAdapter;
import org.eclipse.jubula.tools.internal.i18n.I18n;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
/**
* Toolkit specific commands for the <code>Menu</code>
*
* @author BREDEX GmbH
*/
public class MenuTester extends AbstractMenuTester {
/** Test variable for contextMenus*/
private boolean m_isCM = false;
/**
* {@inheritDoc}
*/
public IComponent getComponent() {
if (m_isCM) {
return super.getComponent();
}
final Shell shell = ((RobotSwtImpl)getRobot()).getActiveWindow();
if (shell == null) {
setComponent(null);
} else {
final IEventThreadQueuer queuer = new EventThreadQueuerSwtImpl();
queuer.invokeAndWait("setMenuBarComponent", new IRunnable<Void>() { //$NON-NLS-1$
public Void run() {
Menu menu = shell.getMenuBar();
setComponent(menu);
return null;
}
});
}
return super.getComponent();
}
/**
* {@inheritDoc}
*/
public String[] getTextArrayFromComponent() {
return null;
}
/**
* Tries to select a menu item in a menu defined by a Text-Path
* @param namePath the menu item to select
* @param operator operator used for matching
*/
public void selectMenuItem(String namePath, final String operator) {
final String[] pathItems = MenuUtilBase.splitPath(namePath);
if (pathItems.length == 0) {
throw new StepExecutionException("empty path to menuitem not allowed", //$NON-NLS-1$
EventFactory.createActionError());
}
try {
final MenuItemAdapter itemAdapter =
(MenuItemAdapter) navigateToMenuItem(
getAndCheckMenu(), pathItems, operator);
if (itemAdapter.getRealComponent() == null) {
throwMenuItemNotFound();
}
Rectangle bounds = itemAdapter.getMenuItemBounds();
Rectangle nullBounds = new Rectangle(0, 0, 0, 0);
if (bounds.equals(nullBounds)) {
itemAdapter.selectProgramatically();
} else {
itemAdapter.selectMenuItem();
}
} catch (StepExecutionException e) {
try {
closeMenu(getAndCheckMenu(), pathItems, operator);
} catch (StepExecutionException e1) {
if (getLog().isInfoEnabled()) {
getLog().info("Tried to close a disabled or already closed menu."); //$NON-NLS-1$
}
}
throw e;
}
}
/**
* Tries to select a menu item in a menu defined by an Index-Path
* @param indexPath the menu item to select
*/
public void selectMenuItemByIndexpath(String indexPath) {
final int[] indexItems = MenuUtilBase.splitIndexPath(indexPath);
if (indexItems.length == 0) {
throw new StepExecutionException("empty path to menuitem not allowed", //$NON-NLS-1$
EventFactory.createActionError());
}
try {
MenuItemAdapter menuItemAdapter = (MenuItemAdapter)
navigateToMenuItem(getAndCheckMenu(), indexItems);
if (menuItemAdapter.getRealComponent() == null) {
throwMenuItemNotFound();
}
Rectangle bounds = menuItemAdapter.getMenuItemBounds();
Rectangle nullBounds = new Rectangle(0, 0, 0, 0);
if (bounds.equals(nullBounds)) {
menuItemAdapter.selectProgramatically();
} else {
menuItemAdapter.selectMenuItem();
}
} catch (StepExecutionException e) {
try {
closeMenu(getAndCheckMenu(), indexItems);
} catch (StepExecutionException e1) {
if (getLog().isInfoEnabled()) {
getLog().info("Tried to close a disabled or already closed menu."); //$NON-NLS-1$
}
}
throwMenuItemNotFound();
}
}
/**
*
* @return the IMenuAdapter.
* @throws StepExecutionException
* if the active window has no menu bar.
*/
protected IMenuComponent getAndCheckMenu() throws StepExecutionException {
// Verify that there is an active window
if (((RobotSwtImpl)getRobot()).getActiveWindow() == null) {
throw new StepExecutionException(
I18n.getString(TestErrorEvent.NO_ACTIVE_WINDOW),
EventFactory.createActionError(
TestErrorEvent.NO_ACTIVE_WINDOW));
}
return super.getAndCheckMenu();
}
/**
*
*/
private void throwMenuItemNotFound() {
throw new StepExecutionException("no such menu item found", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_FOUND));
}
/**
* {@inheritDoc}
*/
protected IMenuItemComponent newMenuItemAdapter(Object component) {
return new MenuItemAdapter(component);
}
/**
* {@inheritDoc}
*/
protected void closeMenu(IMenuComponent menuBar, int[] path) {
Validate.notNull(getMenu(menuBar));
closeMenu(menuBar, path.length);
}
/**
* {@inheritDoc}
*/
protected void closeMenu(IMenuComponent menuBar, String[] textPath,
String operator) {
Validate.notNull(getMenu(menuBar));
closeMenu(menuBar, textPath.length);
}
/**
* Closes the menu cascade with the KEY ESC
* @param menuBar menu
* @param maxCascadeLength an integer so that the closing operation is not infinite
*/
private void closeMenu(final IMenuComponent menuBar, int maxCascadeLength) {
final MenuHiddenListener menuListener =
new MenuHiddenListener();
getMenu(menuBar).getDisplay().syncExec(new Runnable() {
public void run() {
getMenu(menuBar).addMenuListener(menuListener);
}
});
// Press 'ESC' key until the first menu is gone or we reach
// the maxCascadeLength. This prevents infinite loops if this
// is used on a platform that does not use 'ESC' to close menus.
for (int i = 0;
i < maxCascadeLength && !menuListener.isMenuHidden();
i++) {
getRobot().keyType(getMenu(menuBar), SWT.ESC);
}
}
/**
*
* @param menu the menu adapter
* @return the real SWT menu
*/
private Menu getMenu(final IMenuComponent menu) {
return (Menu) menu.getRealComponent();
}
/**
*
* @return -
*/
public boolean isContextMenu() {
return m_isCM;
}
/**
*
* @param isCM
*/
public void setContextMenu(boolean isCM) {
this.m_isCM = isCM;
}
/**
* Listens for a menu to be hidden, the removes itself from the menu's
* listener list.
*
* @author BREDEX GmbH
* @created Nov 01, 2011
*/
private static final class MenuHiddenListener implements MenuListener {
/** whether the expected event has occurred */
private boolean m_eventOccurred = false;
/**
*
* {@inheritDoc}
*/
public void menuHidden(MenuEvent e) {
m_eventOccurred = true;
((Menu)e.widget).removeMenuListener(this);
}
/**
*
* {@inheritDoc}
*/
public void menuShown(MenuEvent e) {
// no-op
}
/**
*
* @return <code>true</code> if the menu has been hidden since this
* listener was registered. Otherwise, <code>false</code>.
*/
public boolean isMenuHidden() {
return m_eventOccurred;
}
}
}