blob: bb92dd762616c5b2806dacf4c9c746e9bb528837 [file] [log] [blame]
/*******************************************************************************
* 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.common.tester;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jubula.rc.common.driver.ClickOptions;
import org.eclipse.jubula.rc.common.driver.RobotTiming;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.logger.AutServerLogger;
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.MatchUtil;
import org.eclipse.jubula.rc.common.util.MenuUtilBase;
import org.eclipse.jubula.rc.common.util.Verifier;
import org.eclipse.jubula.tools.i18n.I18n;
import org.eclipse.jubula.tools.objects.event.EventFactory;
import org.eclipse.jubula.tools.objects.event.TestErrorEvent;
import org.eclipse.jubula.tools.utils.TimeUtil;
/**
* General implementation for Menus. Also used for context menus
* if they behave the same.
*
* @author BREDEX GmbH
*
*/
public abstract class AbstractMenuTester extends AbstractUITester {
/** the logger */
private static AutServerLogger log = new AutServerLogger(
AbstractMenuTester.class);
/**
* @return the log
*/
public static AutServerLogger getLog() {
return log;
}
/**
* This method gets the object which should implemented the menu Interface.
* It is saved as Component so it must be casted.
* @return the MenuAdapter
*/
public IMenuComponent getMenuAdapter() {
return (IMenuComponent) getComponent();
}
/**
* Checks if the specified menu item is enabled.
*
* @param menuItem the menu item as a text path to verify against
* @param operator operator used for matching
* @param enabled is the specified menu item enabled?
*/
public void verifyEnabled(String menuItem, String operator, boolean enabled)
{
verifyEnabled(MenuUtilBase.splitPath(menuItem), operator, enabled);
}
/**
* Checks if the specified menu item is enabled.
*
* @param menuItem the menu item to verify against
* @param operator operator used for matching
* @param enabled is the specified menu item enabled?
*/
public void verifyEnabled(String[] menuItem, String operator,
boolean enabled) {
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem, operator);
try {
checkIsNull(item);
Verifier.equals(enabled, item.isEnabled());
} finally {
closeMenu(getAndCheckMenu(), menuItem, operator);
}
}
/**
* Checks if the given MenuItemAdapter is null and throws an Exception
*
* @param item the MenuItemAdapter which should be checked
*/
private void checkIsNull(final IMenuItemComponent item) {
if (item.getRealComponent() == null) {
throwMenuItemNotFound();
}
}
/**
* Checks if the specified menu item is enabled.
*
* @param menuItem the menu item as a text path to verify against
* @param enabled is the specified menu item enabled?
*/
public void verifyEnabledByIndexpath(String menuItem, boolean enabled) {
verifyEnabledByIndexpath(MenuUtilBase.splitIndexPath(menuItem),
enabled);
}
/**
* Checks if the specified menu item is enabled.
*
* @param menuItem the menu item to verify against
* @param enabled is the specified menu item enabled?
*/
public void verifyEnabledByIndexpath(int[] menuItem, boolean enabled) {
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem);
try {
checkIsNull(item);
Verifier.equals(enabled, item.isEnabled());
} finally {
closeMenu(getAndCheckMenu(), menuItem);
}
}
/**
* Verifies if the specified menu item exists
*
* @param menuItem the menu item to verify against
* @param operator operator used for matching
* @param exists should the menu item exist?
*/
public void verifyExists(String menuItem, String operator, boolean exists) {
verifyExists(MenuUtilBase.splitPath(menuItem), operator, exists);
}
/**
* Verifies if the specified menu item exists
*
* @param menuItem the menu item to verify against
* @param operator operator used for matching
* @param exists should the menu item exist?
*/
public void verifyExists(String[] menuItem, String operator, boolean exists)
{
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem, operator);
try {
Verifier.equals(exists, item.isExisting());
} finally {
closeMenu(getAndCheckMenu(), menuItem, operator);
}
}
/**
* Verifies if the specified menu item exists
* @param menuItem the menu item to verify against
* @param exists should the menu item exist?
*/
public void verifyExistsByIndexpath(String menuItem, boolean exists) {
verifyExistsByIndexpath(MenuUtilBase.splitIndexPath(menuItem), exists);
}
/**
* Verifies if the specified menu item exists
*
* @param menuItem the menu item to verify against
* @param exists should the menu item exist?
*/
public void verifyExistsByIndexpath(int[] menuItem, boolean exists) {
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem);
try {
Verifier.equals(exists, item.isExisting());
} finally {
closeMenu(getAndCheckMenu(), menuItem);
}
}
/**
* Checks if the specified menu item is selected.
*
* @param menuItem the menu item to verify against
* @param operator operator used for matching
* @param selected is the specified menu item selected?
*/
public void verifySelected(String menuItem, String operator,
boolean selected) {
verifySelected(MenuUtilBase.splitPath(menuItem), operator, selected);
}
/**
* Checks if the specified menu item is selected.
*
* @param menuItem the menu item to verify against
* @param operator operator used for matching
* @param selected is the specified menu item selected?
*/
public void verifySelected(String[] menuItem, String operator,
boolean selected) {
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem, operator);
try {
checkIsNull(item);
Verifier.equals(selected, item.isSelected());
} finally {
closeMenu(getAndCheckMenu(), menuItem, operator);
}
}
/**
* Checks if the specified menu item is selected.
*
* @param menuItem the menu item to verify against
* @param selected is the specified menu item selected?
*/
public void verifySelectedByIndexpath(String menuItem, boolean selected) {
verifySelectedByIndexpath(MenuUtilBase.splitIndexPath(menuItem),
selected);
}
/**
* Checks if the specified menu item is selected.
*
* @param menuItem the menu item to verify against
* @param selected is the specified menu item selected?
*/
public void verifySelectedByIndexpath(int[] menuItem, boolean selected) {
checkPathLength(menuItem.length);
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), menuItem);
try {
checkIsNull(item);
Verifier.equals(selected, item.isSelected());
} finally {
closeMenu(getAndCheckMenu(), menuItem);
}
}
/**
* 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) {
int[] indexItems = MenuUtilBase.splitIndexPath(indexPath);
checkPathLength(indexItems.length);
try {
final IMenuItemComponent item = navigateToMenuItem(
getAndCheckMenu(), indexItems);
checkIsNull(item);
item.selectMenuItem();
} catch (StepExecutionException e) {
try {
closeMenu(getAndCheckMenu(), indexItems);
} catch (StepExecutionException e1) {
// Menu item is disabled or menu is already closed
// Do nothing
if (getLog().isInfoEnabled()) {
getLog().info("Tried to close a disabled or already closed menu."); //$NON-NLS-1$
}
}
throwMenuItemNotFound();
}
}
/**
* 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) {
String[] menuItems = MenuUtilBase.splitPath(namePath);
if (menuItems.length == 0) {
throw new StepExecutionException("empty path to menuitem not allowed", //$NON-NLS-1$
EventFactory.createActionError());
}
IMenuItemComponent item = navigateToMenuItem(getAndCheckMenu(),
menuItems, operator);
if (item == null || item.getRealComponent() == null) {
try {
closeMenu(getAndCheckMenu(), menuItems, operator);
} catch (StepExecutionException see) {
// Menu item is disabled or menu is already closed
// Do nothing
getLog().info("Tried to close a disabled or already closed menu."); //$NON-NLS-1$
}
throwMenuItemNotFound();
}
item.selectMenuItem();
}
/**
*
* @return the IMenuAdapter.
* @throws StepExecutionException
* if the active window has no menu bar.
*/
protected IMenuComponent getAndCheckMenu() throws StepExecutionException {
Object menu = getMenuAdapter().getRealComponent();
// Verify that the active window has a menu bar
if (menu == null) {
throw new StepExecutionException(
I18n.getString(TestErrorEvent.NO_MENU_BAR),
EventFactory.createActionError(TestErrorEvent.NO_MENU_BAR));
}
return getMenuAdapter();
}
/**
*
*/
private void throwMenuItemNotFound() {
throw new StepExecutionException("no such menu item found", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_FOUND));
}
/**
* this methods closes the hole menu. It is clicking on the parent item in the menu bar.
*
* If you need another implementation override this method.
* @param menuBar the main menu
* @param textPath the text path used for opening the menu
* @param operator the operator which was used for opening the menu
*/
protected void closeMenu(IMenuComponent menuBar, String[] textPath,
String operator) {
IMenuItemComponent menuitem = findMenu(menuBar,
getIndexForName(menuBar, textPath[0], operator));
if (menuitem.getRealComponent() != null) {
getRobot().click(
menuitem.getRealComponent(),
null,
ClickOptions.create().setClickType(
ClickOptions.ClickType.RELEASED));
}
}
/**
* this methods closes the hole menu. It is clicking on the parent item in the menu bar.
*
* If you need another implementation override this method.
* @param menuBar the main menu
* @param path the integer based path used for opening the menu
*/
protected void closeMenu(IMenuComponent menuBar, int[] path) {
IMenuItemComponent menuitem = findMenu(menuBar, path[0]);
if (menuitem.getRealComponent() != null) {
getRobot().click(
menuitem.getRealComponent(),
null,
ClickOptions.create().setClickType(
ClickOptions.ClickType.RELEASED));
}
}
/**
* Gets the index of the specific menu entry with the name
*
* @param menu the menu in which all items are stored
* @param name the name of the item we want the index from
* @param operator the operator for the matching
* @return the index for the specific menu entry
*/
protected int getIndexForName(IMenuComponent menu, String name,
String operator) {
IMenuItemComponent [] subElements = menu.getItems();
int ignoreElementCount = 0;
for (int j = 0; j < subElements.length; j++) {
IMenuItemComponent tempMenu = (IMenuItemComponent)subElements[j];
if (!tempMenu.isShowing()
|| (tempMenu.isSeparator() && tempMenu.isShowing())) {
ignoreElementCount++;
}
if (tempMenu.isShowing()
&& MatchUtil.getInstance().match(
tempMenu.getText(), name, operator)) {
return j - ignoreElementCount;
}
}
return Integer.MAX_VALUE;
}
/**
* implementation for "wait for component"
* @param timeout the maximum amount of time to wait for the component
* @param delay the time to wait after the component is found
*/
public void waitForComponent(int timeout, int delay) {
if (getComponent().getRealComponent() == null) {
long start = System.currentTimeMillis();
do {
RobotTiming.sleepWaitForComponentPollingDelay();
} while (System.currentTimeMillis() - start < timeout
&& getComponent().getRealComponent() == null);
if (getComponent().getRealComponent() == null) {
throw new StepExecutionException("No Menubar found.", //$NON-NLS-1$
EventFactory.createComponentNotFoundErrorEvent());
}
}
TimeUtil.delay(delay);
}
/**
* Tries to navigate through the menu to the specified menu item.
* This method should be overridden if there is a need for a faster implementation.
*
* @param menuBar the menubar
* @param path the path where to navigate in the menu.
* @param operator operator used for matching
* @return the adapter at the end of the specified path or a adapter that contains no component.
*/
protected IMenuItemComponent navigateToMenuItem(
IMenuComponent menuBar, String[] path, String operator) {
checkPathLength(path.length);
IMenuComponent currentmenu = menuBar;
IMenuItemComponent currentMenuItem = null;
final int pathLength = path.length;
final int beforeLast = pathLength - 1;
for (int i = 0; i < path.length; i++) {
int pathIndex = getIndexForName(currentmenu, path[i], operator);
currentMenuItem = getNextMenuItem(currentmenu, pathIndex);
if ((currentMenuItem.getRealComponent() == null)
&& (i < beforeLast)) {
return currentMenuItem;
}
if (i < beforeLast) {
if (!currentMenuItem.hasSubMenu()) {
// the given path is longer than the menu levels
return newMenuItemAdapter(null);
}
currentmenu = currentMenuItem.openSubMenu();
}
}
return currentMenuItem;
}
/**
* Tries to navigate through the menu to the specified menu item.
* This method should be overridden if there is a need for a faster implementation.
*
* @param menubar the menubar
* @param path the path where to navigate in the menu.
* @return -the adapter at the end of the specified path or a adapter that contains no component.
*/
protected IMenuItemComponent navigateToMenuItem(
IMenuComponent menubar, int[] path) {
checkPathLength(path.length);
IMenuComponent currentmenu = menubar;
IMenuItemComponent currentMenuItem = null;
final int pathLength = path.length;
final int beforeLast = pathLength - 1;
for (int i = 0; i < path.length; i++) {
final int pathIndex = path[i];
currentMenuItem = getNextMenuItem(currentmenu, pathIndex);
if ((currentMenuItem.getRealComponent() == null)
&& (i < beforeLast)) {
return currentMenuItem;
}
if (i < beforeLast) {
if (!currentMenuItem.hasSubMenu()) {
// the given path is longer than the menu levels
return newMenuItemAdapter(null);
}
currentmenu = currentMenuItem.openSubMenu();
}
}
return currentMenuItem;
}
/**
* gets the next menu item adapter from its specific index
* @param currentmenu the current menu
* @param pathIndex the index from the next menu item
* @return the wanted menu item in a adapter
*/
private IMenuItemComponent getNextMenuItem(IMenuComponent currentmenu,
final int pathIndex) {
IMenuItemComponent currentMenuItem;
if (pathIndex < 0) {
throwInvalidPathException();
}
currentMenuItem = findMenu(currentmenu, pathIndex);
return currentMenuItem;
}
/**
* @param menu menu
* @param idx index of the current wanted item
* @return the next IMenuItemAdapter from the next cascade
*/
private IMenuItemComponent findMenu(IMenuComponent menu, int idx) {
List visibleSubMenus = new ArrayList();
IMenuItemComponent[] subElements = menu.getItems();
for (int i = 0; i < subElements.length; ++i) {
IMenuItemComponent menuitem = subElements[i];
if (menuitem.getRealComponent() != null && !menuitem.isSeparator()
&& menuitem.isShowing()) {
visibleSubMenus.add(menuitem);
}
}
if (idx >= visibleSubMenus.size() || idx < 0) {
return newMenuItemAdapter(null);
}
return (IMenuItemComponent) visibleSubMenus.get(idx);
}
/**
* Checks the path for it length and throws and StepExecutionExecption if it is 0
* @param length the path length to be checked
*/
private void checkPathLength(int length) {
if (length < 1) {
throw new StepExecutionException("empty path to menuitem is not allowed", EventFactory //$NON-NLS-1$
.createActionError(
TestErrorEvent.INVALID_PARAM_VALUE));
}
}
/**
*
*/
private static void throwInvalidPathException() {
throw new StepExecutionException("invalid path", EventFactory //$NON-NLS-1$
.createActionError(TestErrorEvent.INVALID_PARAM_VALUE));
}
/**
* This adapts or puts the new MenuItem in the context which is needed for
* the algorithms.
* @param component the new MenuItem which is used by the next step
* @return the adapted or casted MenuItem
*/
protected abstract IMenuItemComponent newMenuItemAdapter(Object component);
}